legion-tty 0.4.2 → 0.4.3

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: 3985cb489efcaf4eaf208514bee79ff9650b1f841a00cd76a32468a0734e4198
4
- data.tar.gz: fa7c612dac3248efe49762a4bd6b869b8348c4388ee569fdbd60c030501db918
3
+ metadata.gz: 93f9cd78860072bfa0df27f33574552a7d5ac749fbb9440f61017ed76f7f9f4d
4
+ data.tar.gz: c590bb6fb1cbe8639b5df4e46e0aa255f5d23f01499c8d2b1137ad86700412b7
5
5
  SHA512:
6
- metadata.gz: 9909b4d373d5b22892611dd3c302d02cb4960bfec8524da602c117b62de5d8fbacb9f39a777b97e5eabe9c379e4918fb79aab313d2f67e5c4129ff1214153d32
7
- data.tar.gz: 3b8e072e3ad9cb3bd73b9e7e7bb5b6fb6baa86527e4da6e0045564c40851ec77e5e67a89cf7409d1280b59dc1a34831780859d56632e6e4c9a7b6095991a555f
6
+ metadata.gz: 8880c1013b5c36a3d9a7d378280b6a1212ba82f527a37dd7f5f81b5b0fc591435ea10fec4a565b5e95a714be1b6340b587214ce9ccde08ee1dfbc63572e0d2f9
7
+ data.tar.gz: d99de6e491d811a3e891833760c4f25fe45c4034494bd200322b41145fc39a16929b8ea3b5295c2044cc1e123e45f30022f310ca97aaf1643f842696a424db77
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.3] - 2026-03-19
4
+
5
+ ### Added
6
+ - Daemon-first chat routing: chat screen routes through LegionIO daemon when available
7
+ - `send_via_daemon` and `send_via_direct` methods with automatic fallback
8
+ - `daemon_available?` guard for `Legion::LLM::DaemonClient` presence
9
+
3
10
  ## [0.4.2] - 2026-03-19
4
11
 
5
12
  ### Added
@@ -41,11 +41,17 @@ module Legion
41
41
  @completions.select { |c| c.start_with?(partial) }.sort
42
42
  end
43
43
 
44
+ def history
45
+ return [] unless @reader.respond_to?(:history)
46
+
47
+ @reader.history.to_a
48
+ end
49
+
44
50
  private
45
51
 
46
52
  def build_default_reader
47
53
  require 'tty-reader'
48
- reader = ::TTY::Reader.new
54
+ reader = ::TTY::Reader.new(history_cycle: true)
49
55
  register_tab_completion(reader)
50
56
  reader
51
57
  rescue LoadError
@@ -13,7 +13,7 @@ module Legion
13
13
  # rubocop:disable Metrics/ClassLength
14
14
  class Chat < Base
15
15
  SLASH_COMMANDS = %w[/help /quit /clear /model /session /cost /export /tools /dashboard /hotkeys /save /load
16
- /sessions /system /delete /plan /palette /extensions /config].freeze
16
+ /sessions /system /delete /plan /palette /extensions /config /theme].freeze
17
17
 
18
18
  attr_reader :message_stream, :status_bar
19
19
 
@@ -275,6 +275,7 @@ module Legion
275
275
  when '/palette' then handle_palette
276
276
  when '/extensions' then handle_extensions_screen
277
277
  when '/config' then handle_config_screen
278
+ when '/theme' then handle_theme(input)
278
279
  else :handled
279
280
  end
280
281
  end
@@ -285,7 +286,8 @@ module Legion
285
286
  role: :system,
286
287
  content: "Commands:\n /help /quit /clear /model <name> /session <name> /cost\n " \
287
288
  "/export [md|json] /tools /dashboard /hotkeys /save /load /sessions\n " \
288
- "/system <prompt> /delete <session> /plan /palette /extensions /config\n\n" \
289
+ "/system <prompt> /delete <session> /plan /palette /extensions /config\n " \
290
+ "/theme [name] -- switch color theme (purple, green, blue, amber)\n\n" \
289
291
  'Hotkeys: Ctrl+D=dashboard Ctrl+K=palette Ctrl+S=sessions Esc=back'
290
292
  )
291
293
  :handled
@@ -570,6 +572,23 @@ module Legion
570
572
  :handled
571
573
  end
572
574
 
575
+ def handle_theme(input)
576
+ name = input.split(nil, 2)[1]
577
+ if name
578
+ if Theme.switch(name)
579
+ @message_stream.add_message(role: :system, content: "Theme switched to: #{name}")
580
+ else
581
+ available = Theme.available_themes.join(', ')
582
+ @message_stream.add_message(role: :system, content: "Unknown theme '#{name}'. Available: #{available}")
583
+ end
584
+ else
585
+ current = Theme.current_theme
586
+ available = Theme.available_themes.join(', ')
587
+ @message_stream.add_message(role: :system, content: "Current theme: #{current}\nAvailable: #{available}")
588
+ end
589
+ :handled
590
+ end
591
+
573
592
  def detect_provider
574
593
  cfg = safe_config
575
594
  provider = cfg[:provider].to_s.downcase
@@ -2,44 +2,100 @@
2
2
 
3
3
  module Legion
4
4
  module TTY
5
+ # rubocop:disable Metrics/ModuleLength
5
6
  module Theme
6
7
  # rubocop:disable Naming/VariableNumber
7
- PALETTE = {
8
- purple_1: [30, 27, 46],
9
- purple_2: [41, 37, 63],
10
- purple_3: [52, 47, 80],
11
- purple_4: [63, 57, 97],
12
- purple_5: [74, 67, 114],
13
- purple_6: [85, 77, 131],
14
- purple_7: [96, 87, 148],
15
- purple_8: [107, 97, 165],
16
- purple_9: [118, 107, 182],
17
- purple_10: [129, 119, 199],
18
- purple_11: [140, 131, 210],
19
- purple_12: [157, 148, 221],
20
- purple_13: [174, 167, 230],
21
- purple_14: [191, 186, 239],
22
- purple_15: [208, 205, 245],
23
- purple_16: [225, 224, 250],
24
- purple_17: [242, 243, 255]
8
+ THEMES = {
9
+ purple: {
10
+ palette: {
11
+ shade_1: [30, 27, 46], shade_2: [41, 37, 63], shade_3: [52, 47, 80],
12
+ shade_4: [63, 57, 97], shade_5: [74, 67, 114], shade_6: [85, 77, 131],
13
+ shade_7: [96, 87, 148], shade_8: [107, 97, 165], shade_9: [118, 107, 182],
14
+ shade_10: [129, 119, 199], shade_11: [140, 131, 210], shade_12: [157, 148, 221],
15
+ shade_13: [174, 167, 230], shade_14: [191, 186, 239], shade_15: [208, 205, 245],
16
+ shade_16: [225, 224, 250], shade_17: [242, 243, 255]
17
+ },
18
+ semantic: {
19
+ primary: :shade_9, secondary: :shade_6, accent: :shade_12,
20
+ success: [0, 200, 83], warning: [255, 191, 0], error: [255, 69, 58],
21
+ info: :shade_7, surface: :shade_1, muted: :shade_4,
22
+ rain: :shade_11, rain_fade: :shade_3
23
+ }
24
+ },
25
+ green: {
26
+ palette: {
27
+ shade_1: [15, 30, 15], shade_2: [20, 45, 20], shade_3: [25, 60, 25],
28
+ shade_4: [30, 75, 30], shade_5: [35, 90, 35], shade_6: [40, 110, 40],
29
+ shade_7: [50, 130, 50], shade_8: [60, 150, 60], shade_9: [75, 170, 75],
30
+ shade_10: [90, 190, 90], shade_11: [110, 210, 110], shade_12: [140, 225, 140],
31
+ shade_13: [170, 235, 170], shade_14: [195, 242, 195], shade_15: [215, 248, 215],
32
+ shade_16: [230, 252, 230], shade_17: [245, 255, 245]
33
+ },
34
+ semantic: {
35
+ primary: :shade_9, secondary: :shade_6, accent: :shade_12,
36
+ success: [0, 200, 83], warning: [255, 191, 0], error: [255, 69, 58],
37
+ info: :shade_7, surface: :shade_1, muted: :shade_4,
38
+ rain: :shade_11, rain_fade: :shade_3
39
+ }
40
+ },
41
+ blue: {
42
+ palette: {
43
+ shade_1: [15, 20, 40], shade_2: [20, 30, 60], shade_3: [25, 40, 80],
44
+ shade_4: [30, 50, 100], shade_5: [40, 65, 120], shade_6: [50, 80, 140],
45
+ shade_7: [65, 100, 160], shade_8: [80, 120, 180], shade_9: [100, 140, 200],
46
+ shade_10: [120, 160, 215], shade_11: [145, 185, 225], shade_12: [170, 205, 235],
47
+ shade_13: [195, 220, 242], shade_14: [210, 230, 248], shade_15: [225, 240, 252],
48
+ shade_16: [238, 248, 255], shade_17: [248, 252, 255]
49
+ },
50
+ semantic: {
51
+ primary: :shade_9, secondary: :shade_6, accent: :shade_12,
52
+ success: [0, 200, 83], warning: [255, 191, 0], error: [255, 69, 58],
53
+ info: :shade_7, surface: :shade_1, muted: :shade_4,
54
+ rain: :shade_11, rain_fade: :shade_3
55
+ }
56
+ },
57
+ amber: {
58
+ palette: {
59
+ shade_1: [35, 25, 10], shade_2: [50, 35, 15], shade_3: [65, 45, 20],
60
+ shade_4: [80, 55, 25], shade_5: [100, 70, 30], shade_6: [120, 85, 35],
61
+ shade_7: [140, 100, 40], shade_8: [165, 120, 50], shade_9: [190, 140, 60],
62
+ shade_10: [210, 160, 70], shade_11: [225, 180, 85], shade_12: [235, 200, 110],
63
+ shade_13: [242, 215, 140], shade_14: [248, 230, 170], shade_15: [252, 240, 200],
64
+ shade_16: [255, 248, 225], shade_17: [255, 252, 245]
65
+ },
66
+ semantic: {
67
+ primary: :shade_9, secondary: :shade_6, accent: :shade_12,
68
+ success: [0, 200, 83], warning: [255, 191, 0], error: [255, 69, 58],
69
+ info: :shade_7, surface: :shade_1, muted: :shade_4,
70
+ rain: :shade_11, rain_fade: :shade_3
71
+ }
72
+ }
25
73
  }.freeze
26
74
 
27
- SEMANTIC = {
28
- primary: :purple_9,
29
- secondary: :purple_6,
30
- accent: :purple_12,
31
- success: [0, 200, 83],
32
- warning: [255, 191, 0],
33
- error: [255, 69, 58],
34
- info: :purple_7,
35
- surface: :purple_1,
36
- muted: :purple_4,
37
- rain: :purple_11,
38
- rain_fade: :purple_3
39
- }.freeze
75
+ # Legacy aliases for backward compatibility
76
+ PALETTE = THEMES[:purple][:palette].transform_keys { |k| k.to_s.sub('shade_', 'purple_').to_sym }.freeze
77
+ SEMANTIC = THEMES[:purple][:semantic].freeze
40
78
  # rubocop:enable Naming/VariableNumber
41
79
 
42
80
  class << self
81
+ def current_theme
82
+ @current_theme || :purple
83
+ end
84
+
85
+ # rubocop:disable Naming/PredicateMethod
86
+ def switch(name)
87
+ name = name.to_sym
88
+ return false unless THEMES.key?(name)
89
+
90
+ @current_theme = name
91
+ true
92
+ end
93
+ # rubocop:enable Naming/PredicateMethod
94
+
95
+ def available_themes
96
+ THEMES.keys
97
+ end
98
+
43
99
  def c(name, text)
44
100
  rgb = resolve_rgb(name)
45
101
  return text unless rgb
@@ -47,17 +103,28 @@ module Legion
47
103
  "\e[38;2;#{rgb[0]};#{rgb[1]};#{rgb[2]}m#{text}\e[0m"
48
104
  end
49
105
 
106
+ def reset_theme
107
+ @current_theme = :purple
108
+ end
109
+
50
110
  private
51
111
 
52
112
  def resolve_rgb(name)
53
- if PALETTE.key?(name)
113
+ theme = THEMES[current_theme]
114
+ palette = theme[:palette]
115
+ semantic = theme[:semantic]
116
+
117
+ if palette.key?(name)
118
+ palette[name]
119
+ elsif semantic.key?(name)
120
+ ref = semantic[name]
121
+ ref.is_a?(Symbol) ? palette[ref] : ref
122
+ elsif PALETTE.key?(name)
54
123
  PALETTE[name]
55
- elsif SEMANTIC.key?(name)
56
- ref = SEMANTIC[name]
57
- ref.is_a?(Symbol) ? PALETTE[ref] : ref
58
124
  end
59
125
  end
60
126
  end
61
127
  end
128
+ # rubocop:enable Metrics/ModuleLength
62
129
  end
63
130
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module TTY
5
- VERSION = '0.4.2'
5
+ VERSION = '0.4.3'
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.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity