legion-tty 0.4.16 → 0.4.17
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 +8 -0
- data/lib/legion/tty/screens/chat/custom_commands.rb +41 -0
- data/lib/legion/tty/screens/chat/message_commands.rb +66 -0
- data/lib/legion/tty/screens/chat/ui_commands.rb +26 -0
- data/lib/legion/tty/screens/chat.rb +7 -1
- 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: 764baccaffa8d9863f8cb85248c15775fce561f729b74d70ff0b597f343eb0f5
|
|
4
|
+
data.tar.gz: 39cacbd736ae3aacbeb54c429428c55cbde2a9325654f6d32e3e272c60586f7e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f91d4641d6ca7566d9229c1ae644b820f7963793a5a93d92be56547d178f5c205ddcf28ed2b0303fd545c86c85bfeda99f1ebe226392940e748f504a6045868c
|
|
7
|
+
data.tar.gz: 03c2a6d201175628179ad926a6453c9446bb1bcdfd999dafafa38dc59aa0a0a422ebe654a89b8751f5f745e45a2c51ca28bf84ee9ba60c368120b9f13e6b6e97
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.17] - 2026-03-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `/template` command: 8 predefined prompt templates (explain, review, summarize, refactor, test, debug, translate, compare)
|
|
7
|
+
- `/fav` and `/favs` commands: persistent favorites saved to `~/.legionio/favorites.json`
|
|
8
|
+
- `/log [N]` command: view last N lines of boot log (default 20)
|
|
9
|
+
- `/version` command: show legion-tty version, Ruby version, and platform
|
|
10
|
+
|
|
3
11
|
## [0.4.16] - 2026-03-19
|
|
4
12
|
|
|
5
13
|
### Added
|
|
@@ -6,8 +6,49 @@ module Legion
|
|
|
6
6
|
class Chat < Base
|
|
7
7
|
# rubocop:disable Metrics/ModuleLength
|
|
8
8
|
module CustomCommands
|
|
9
|
+
TEMPLATES = {
|
|
10
|
+
'explain' => 'Explain the following concept in simple terms: ',
|
|
11
|
+
'review' => "Review this code for bugs, security issues, and improvements:\n```\n",
|
|
12
|
+
'summarize' => "Summarize the following text in 3 bullet points:\n",
|
|
13
|
+
'refactor' => "Refactor this code for readability and performance:\n```\n",
|
|
14
|
+
'test' => "Write unit tests for this code:\n```\n",
|
|
15
|
+
'debug' => "Help me debug this error:\n",
|
|
16
|
+
'translate' => 'Translate the following to ',
|
|
17
|
+
'compare' => "Compare and contrast the following:\n"
|
|
18
|
+
}.freeze
|
|
19
|
+
|
|
9
20
|
private
|
|
10
21
|
|
|
22
|
+
# rubocop:disable Metrics/MethodLength
|
|
23
|
+
def handle_template(input)
|
|
24
|
+
name = input.split(nil, 2)[1]
|
|
25
|
+
unless name
|
|
26
|
+
lines = TEMPLATES.map { |k, v| " #{k}: #{v[0, 60]}" }
|
|
27
|
+
@message_stream.add_message(
|
|
28
|
+
role: :system,
|
|
29
|
+
content: "Available templates (#{TEMPLATES.size}):\n#{lines.join("\n")}\n\nUsage: /template <name>"
|
|
30
|
+
)
|
|
31
|
+
return :handled
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
template = TEMPLATES[name]
|
|
35
|
+
unless template
|
|
36
|
+
available = TEMPLATES.keys.join(', ')
|
|
37
|
+
@message_stream.add_message(
|
|
38
|
+
role: :system,
|
|
39
|
+
content: "Template '#{name}' not found. Available: #{available}"
|
|
40
|
+
)
|
|
41
|
+
return :handled
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@message_stream.add_message(
|
|
45
|
+
role: :system,
|
|
46
|
+
content: "Template '#{name}':\n#{template}"
|
|
47
|
+
)
|
|
48
|
+
:handled
|
|
49
|
+
end
|
|
50
|
+
# rubocop:enable Metrics/MethodLength
|
|
51
|
+
|
|
11
52
|
def handle_alias(input)
|
|
12
53
|
parts = input.split(nil, 3)
|
|
13
54
|
if parts.size < 2
|
|
@@ -298,6 +298,72 @@ module Legion
|
|
|
298
298
|
)
|
|
299
299
|
end
|
|
300
300
|
end
|
|
301
|
+
|
|
302
|
+
def favorites_file
|
|
303
|
+
File.expand_path('~/.legionio/favorites.json')
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def load_favorites
|
|
307
|
+
return [] unless File.exist?(favorites_file)
|
|
308
|
+
|
|
309
|
+
raw = File.read(favorites_file)
|
|
310
|
+
parsed = ::JSON.parse(raw, symbolize_names: true)
|
|
311
|
+
parsed.is_a?(Array) ? parsed : []
|
|
312
|
+
rescue StandardError
|
|
313
|
+
[]
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def save_favorites(favs)
|
|
317
|
+
require 'fileutils'
|
|
318
|
+
FileUtils.mkdir_p(File.dirname(favorites_file))
|
|
319
|
+
File.write(favorites_file, ::JSON.generate(favs))
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
|
323
|
+
def handle_fav(input)
|
|
324
|
+
idx_str = input.split(nil, 2)[1]
|
|
325
|
+
msg = if idx_str
|
|
326
|
+
@message_stream.messages[idx_str.to_i]
|
|
327
|
+
else
|
|
328
|
+
@message_stream.messages.reverse.find { |m| m[:role] == :assistant }
|
|
329
|
+
end
|
|
330
|
+
unless msg
|
|
331
|
+
@message_stream.add_message(role: :system, content: 'No message to favorite.')
|
|
332
|
+
return :handled
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
@favorites ||= []
|
|
336
|
+
entry = {
|
|
337
|
+
role: msg[:role],
|
|
338
|
+
content: msg[:content].to_s,
|
|
339
|
+
saved_at: Time.now.iso8601,
|
|
340
|
+
session: @session_name
|
|
341
|
+
}
|
|
342
|
+
@favorites << entry
|
|
343
|
+
save_favorites(load_favorites + [entry])
|
|
344
|
+
preview = truncate_text(msg[:content].to_s, 60)
|
|
345
|
+
@message_stream.add_message(role: :system, content: "Favorited: #{preview}")
|
|
346
|
+
:handled
|
|
347
|
+
end
|
|
348
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
349
|
+
|
|
350
|
+
def handle_favs
|
|
351
|
+
all_favs = load_favorites
|
|
352
|
+
if all_favs.empty?
|
|
353
|
+
@message_stream.add_message(role: :system, content: 'No favorites saved.')
|
|
354
|
+
return :handled
|
|
355
|
+
end
|
|
356
|
+
|
|
357
|
+
lines = all_favs.each_with_index.map do |fav, i|
|
|
358
|
+
saved = fav[:saved_at] || ''
|
|
359
|
+
" #{i + 1}. [#{fav[:role]}] #{truncate_text(fav[:content].to_s, 60)} (#{saved})"
|
|
360
|
+
end
|
|
361
|
+
@message_stream.add_message(
|
|
362
|
+
role: :system,
|
|
363
|
+
content: "Favorites (#{all_favs.size}):\n#{lines.join("\n")}"
|
|
364
|
+
)
|
|
365
|
+
:handled
|
|
366
|
+
end
|
|
301
367
|
end
|
|
302
368
|
# rubocop:enable Metrics/ModuleLength
|
|
303
369
|
end
|
|
@@ -277,6 +277,32 @@ module Legion
|
|
|
277
277
|
def format_stat_number(num)
|
|
278
278
|
num.to_s.chars.reverse.each_slice(3).map(&:join).join(',').reverse
|
|
279
279
|
end
|
|
280
|
+
|
|
281
|
+
def handle_log(input)
|
|
282
|
+
n = (input.split(nil, 2)[1] || '20').to_i.clamp(1, 500)
|
|
283
|
+
log_path = File.expand_path('~/.legionio/logs/tty-boot.log')
|
|
284
|
+
unless File.exist?(log_path)
|
|
285
|
+
@message_stream.add_message(role: :system, content: 'No boot log found.')
|
|
286
|
+
return :handled
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
lines = File.readlines(log_path, chomp: true).last(n)
|
|
290
|
+
@message_stream.add_message(
|
|
291
|
+
role: :system,
|
|
292
|
+
content: "Boot log (last #{lines.size} lines):\n#{lines.join("\n")}"
|
|
293
|
+
)
|
|
294
|
+
:handled
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def handle_version
|
|
298
|
+
ruby_ver = RUBY_VERSION
|
|
299
|
+
platform = RUBY_PLATFORM
|
|
300
|
+
@message_stream.add_message(
|
|
301
|
+
role: :system,
|
|
302
|
+
content: "legion-tty v#{Legion::TTY::VERSION}\nRuby: #{ruby_ver}\nPlatform: #{platform}"
|
|
303
|
+
)
|
|
304
|
+
:handled
|
|
305
|
+
end
|
|
280
306
|
end
|
|
281
307
|
# rubocop:enable Metrics/ModuleLength
|
|
282
308
|
end
|
|
@@ -29,7 +29,8 @@ module Legion
|
|
|
29
29
|
/hotkeys /save /load /sessions /system /delete /plan /palette /extensions /config
|
|
30
30
|
/theme /search /grep /stats /personality /undo /history /pin /pins /rename
|
|
31
31
|
/context /alias /snippet /debug /uptime /time /bookmark /welcome /tips
|
|
32
|
-
/wc /import /mute /autosave /react /macro /tag /tags /repeat /count
|
|
32
|
+
/wc /import /mute /autosave /react /macro /tag /tags /repeat /count
|
|
33
|
+
/template /fav /favs /log /version].freeze
|
|
33
34
|
|
|
34
35
|
PERSONALITIES = {
|
|
35
36
|
'default' => 'You are Legion, an async cognition engine and AI assistant. Be helpful and concise.',
|
|
@@ -379,6 +380,11 @@ module Legion
|
|
|
379
380
|
when '/tags' then handle_tags(input)
|
|
380
381
|
when '/repeat' then handle_repeat
|
|
381
382
|
when '/count' then handle_count(input)
|
|
383
|
+
when '/template' then handle_template(input)
|
|
384
|
+
when '/fav' then handle_fav(input)
|
|
385
|
+
when '/favs' then handle_favs
|
|
386
|
+
when '/log' then handle_log(input)
|
|
387
|
+
when '/version' then handle_version
|
|
382
388
|
else :handled
|
|
383
389
|
end
|
|
384
390
|
end
|
data/lib/legion/tty/version.rb
CHANGED