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 +4 -4
- data/CHANGELOG.md +7 -0
- data/lib/legion/tty/components/input_bar.rb +7 -1
- data/lib/legion/tty/screens/chat.rb +21 -2
- data/lib/legion/tty/theme.rb +102 -35
- data/lib/legion/tty/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 93f9cd78860072bfa0df27f33574552a7d5ac749fbb9440f61017ed76f7f9f4d
|
|
4
|
+
data.tar.gz: c590bb6fb1cbe8639b5df4e46e0aa255f5d23f01499c8d2b1137ad86700412b7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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
|
data/lib/legion/tty/theme.rb
CHANGED
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
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
|
data/lib/legion/tty/version.rb
CHANGED