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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 70299176c70666c5c4a4e7a1e6ac8ae1a03050525e299b7fcc4cf6a4cb8146c4
4
- data.tar.gz: c3cf40f5acfa8e14da112380c93931340985d937aafd6667c638bdb4b3ed0913
3
+ metadata.gz: 764baccaffa8d9863f8cb85248c15775fce561f729b74d70ff0b597f343eb0f5
4
+ data.tar.gz: 39cacbd736ae3aacbeb54c429428c55cbde2a9325654f6d32e3e272c60586f7e
5
5
  SHA512:
6
- metadata.gz: 8df88d8c600985633a63d34c18c3d1366dd9868d4109c2240c7522fa905511d04d865a8a259af71009840571ec627dae22f0def660043ecbc63701a4a0564dcb
7
- data.tar.gz: 7b607c3304efb10d94866d23eabd122b1aee84e0cc6cb8ecd7329129ad6b18277867b4e74825788d0bbc171563ea6a60c73d75fd2bdeeb7be1e9227ec26515a0
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].freeze
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module TTY
5
- VERSION = '0.4.16'
5
+ VERSION = '0.4.17'
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.16
4
+ version: 0.4.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity