legion-tty 0.4.6 → 0.4.7

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: 750c41521ce23860a6e8613b4e84471e4c2813657ec68f23b24fcf0aa7015ecd
4
- data.tar.gz: b203df2393abcc0afa085b7ec30c73fbbe3815d2f9886d1b3744fdbbf1fddc62
3
+ metadata.gz: 5b54f067b654097c2ea13e9a36aed12ac6e79f01a7e737494fa57da489d9ada9
4
+ data.tar.gz: 767c21b9ed0f1ac37f92db12bbef79432d42de65695d07736c9e1478b48ef96d
5
5
  SHA512:
6
- metadata.gz: 06d4eab7afdfbdb8933c3166c3b5dc3cd028c7462f29d4601364ba759ae9b648bbdd1a7e4f304587dcc1148af166840815bba87d5c81044cd622355964cb9cc1
7
- data.tar.gz: e331268056bf882144790fe0c88f95454050a6b16a017b033f00e29785f71a027107784fc8a4e25906a3d3cd733c0d20454577423d2e5a038b21b6d9fb490c29
6
+ metadata.gz: 6cec6ebd2ee78648a6f8d00e5db9c3004d1b9e1787b914a31135b1ed75137d467c9982363c83dc40f8697b9ef930869e9ab719b066297e5dc61011361a8f5f22
7
+ data.tar.gz: 3b1f39208ef1198f3db8620aee08f56d65146f3d761d5356b04992aadd79514aae957e044384878181b390cf738e2258ea08fadf6c4299c3c1aaf1bba0e4b7f4
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.7] - 2026-03-19
4
+
5
+ ### Added
6
+ - Smart session auto-naming: generates slug from first user message instead of "default"
7
+ - Message timestamps: each message records creation time, displayed in user message headers
8
+ - Scroll position indicator in status bar (shows current/total when content is scrollable)
9
+
3
10
  ## [0.4.6] - 2026-03-19
4
11
 
5
12
  ### Added
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Rich terminal UI for the LegionIO async cognition engine.
4
4
 
5
- **Version**: 0.4.1
5
+ **Version**: 0.4.6
6
6
 
7
7
  Think Claude Code meets Codex CLI, but for LegionIO: onboarding wizard with identity detection, streaming AI chat shell, operational dashboard, extensions browser, config editor, and session persistence - all rendered with the [tty-ruby](https://ttytoolkit.org/) gem ecosystem.
8
8
 
@@ -10,7 +10,7 @@ Think Claude Code meets Codex CLI, but for LegionIO: onboarding wizard with iden
10
10
 
11
11
  - **Onboarding wizard** - First-run setup with Kerberos identity detection, GitHub profile probing, environment scanning, and LLM provider selection
12
12
  - **Digital rain intro** - Matrix-style rain using discovered LEX extension names
13
- - **AI chat shell** - Streaming LLM chat with 19 slash commands, tab completion, markdown rendering, and tool panels
13
+ - **AI chat shell** - Streaming LLM chat with 27 slash commands, tab completion, markdown rendering, and tool panels
14
14
  - **Operational dashboard** - Service status, extension inventory, system info, recent activity (Ctrl+D or `/dashboard`)
15
15
  - **Extensions browser** - Browse installed LEX gems by category (core, agentic, service, AI, other) with detail view
16
16
  - **Config viewer/editor** - View and edit `~/.legionio/settings/*.json` with vault:// masking
@@ -19,9 +19,15 @@ Think Claude Code meets Codex CLI, but for LegionIO: onboarding wizard with iden
19
19
  - **Session management** - Auto-save on quit, `/save`, `/load`, `/sessions`, session picker (Ctrl+S)
20
20
  - **Token tracking** - Per-model pricing for 9 models across 8 providers via `/cost`
21
21
  - **Plan mode** - Bookmark messages without sending to LLM (`/plan`)
22
+ - **Personality styles** - Switch between default, concise, detailed, friendly, technical (`/personality`)
23
+ - **Theme selection** - Four built-in themes: purple (default), green, blue, amber (`/theme`)
24
+ - **Conversation tools** - `/compact`, `/copy`, `/diff`, `/search`, `/stats`
22
25
  - **Hotkey navigation** - Ctrl+D (dashboard), Ctrl+K (palette), Ctrl+S (sessions), Escape (back)
23
26
  - **Tab completion** - Type `/` and Tab to auto-complete slash commands
27
+ - **Input history** - Up/down arrow to navigate previous inputs
24
28
  - **Progress panel** - Visual progress bars for long operations (extension scanning, gem ops)
29
+ - **Animated spinner** - Status bar spinner during LLM thinking
30
+ - **Daemon routing** - Routes through LegionIO daemon when available, falls back to direct
25
31
  - **Second-run flow** - Skips onboarding, re-scans environment, drops into chat
26
32
 
27
33
  ## Installation
@@ -83,6 +89,13 @@ legion chat prompt "explain async cognition"
83
89
  | `/palette` | Open command palette (fuzzy search) |
84
90
  | `/extensions` | Browse installed LEX extensions |
85
91
  | `/config` | View and edit settings files |
92
+ | `/theme [name]` | Switch color theme (purple/green/blue/amber) |
93
+ | `/search <text>` | Search message history |
94
+ | `/compact [N]` | Keep last N message pairs, remove older |
95
+ | `/copy` | Copy last assistant response to clipboard |
96
+ | `/diff` | Show new messages since last session load |
97
+ | `/stats` | Show conversation statistics |
98
+ | `/personality [style]` | Switch personality (default/concise/detailed/friendly/technical) |
86
99
 
87
100
  ## Hotkeys
88
101
 
@@ -126,6 +139,7 @@ legion-tty
126
139
  SessionPicker # Session list and selection
127
140
  TableView # TTY::Table wrapper
128
141
  ProgressPanel # TTY::ProgressBar wrapper
142
+ Notification # Transient notifications with TTL and levels
129
143
 
130
144
  Background/
131
145
  Scanner # Service port probing, git repo discovery, shell history
@@ -154,8 +168,8 @@ Boot logs go to `~/.legionio/logs/tty-boot.log`.
154
168
 
155
169
  ```bash
156
170
  bundle install
157
- bundle exec rspec # 598 examples, 0 failures
158
- bundle exec rubocop # 68 files, 0 offenses
171
+ bundle exec rspec # 653 examples, 0 failures
172
+ bundle exec rubocop # 77 files, 0 offenses
159
173
  ```
160
174
 
161
175
  ## License
@@ -14,7 +14,7 @@ module Legion
14
14
  end
15
15
 
16
16
  def add_message(role:, content:)
17
- @messages << { role: role, content: content, tool_panels: [] }
17
+ @messages << { role: role, content: content, tool_panels: [], timestamp: Time.now }
18
18
  end
19
19
 
20
20
  def append_streaming(text)
@@ -57,7 +57,13 @@ module Legion
57
57
  total = all_lines.size
58
58
  start_idx = [total - height - @scroll_offset, 0].max
59
59
  start_idx = [start_idx, total].min
60
- all_lines[start_idx, height] || []
60
+ result = all_lines[start_idx, height] || []
61
+ @last_visible_count = result.size
62
+ result
63
+ end
64
+
65
+ def scroll_position
66
+ { current: @scroll_offset, total: @messages.size, visible: @last_visible_count || 0 }
61
67
  end
62
68
 
63
69
  private
@@ -72,7 +78,7 @@ module Legion
72
78
 
73
79
  def role_lines(msg, width)
74
80
  case msg[:role]
75
- when :user then user_lines(msg)
81
+ when :user then user_lines(msg, width)
76
82
  when :assistant then assistant_lines(msg, width)
77
83
  when :system then system_lines(msg)
78
84
  when :tool then tool_call_lines(msg, width)
@@ -80,9 +86,16 @@ module Legion
80
86
  end
81
87
  end
82
88
 
83
- def user_lines(msg)
84
- prefix = Theme.c(:accent, 'You')
85
- ['', "#{prefix}: #{msg[:content]}"]
89
+ def user_lines(msg, _width)
90
+ ts = format_timestamp(msg[:timestamp])
91
+ header = "#{Theme.c(:accent, 'You')} #{Theme.c(:muted, ts)}"
92
+ ['', "#{header}: #{msg[:content]}"]
93
+ end
94
+
95
+ def format_timestamp(time)
96
+ return '' unless time
97
+
98
+ time.strftime('%H:%M')
86
99
  end
87
100
 
88
101
  def assistant_lines(msg, width)
@@ -37,7 +37,8 @@ module Legion
37
37
  thinking_segment,
38
38
  tokens_segment,
39
39
  cost_segment,
40
- session_segment
40
+ session_segment,
41
+ scroll_segment
41
42
  ].compact
42
43
  end
43
44
 
@@ -71,6 +72,13 @@ module Legion
71
72
  Theme.c(:muted, @state[:session]) if @state[:session]
72
73
  end
73
74
 
75
+ def scroll_segment
76
+ scroll = @state[:scroll]
77
+ return nil unless scroll.is_a?(Hash) && scroll[:total].to_i > scroll[:visible].to_i
78
+
79
+ Theme.c(:muted, "#{scroll[:current]}/#{scroll[:total]}")
80
+ end
81
+
74
82
  def format_number(num)
75
83
  num.to_s.chars.reverse.each_slice(3).map(&:join).join(',').reverse
76
84
  end
@@ -121,6 +121,7 @@ module Legion
121
121
  divider = Theme.c(:muted, '-' * width)
122
122
  stream_height = [height - 2, 1].max
123
123
  stream_lines = @message_stream.render(width: width, height: stream_height)
124
+ @status_bar.update(scroll: @message_stream.scroll_position)
124
125
  stream_lines + [divider, bar_line]
125
126
  end
126
127
 
@@ -440,6 +441,9 @@ module Legion
440
441
  def auto_save_session
441
442
  return if @message_stream.messages.empty?
442
443
 
444
+ if @session_name == 'default'
445
+ @session_name = @session_store.auto_session_name(messages: @message_stream.messages)
446
+ end
443
447
  @session_store.save(@session_name, messages: @message_stream.messages)
444
448
  rescue StandardError
445
449
  nil
@@ -51,8 +51,14 @@ module Legion
51
51
  FileUtils.rm_f(path)
52
52
  end
53
53
 
54
- def auto_session_name
55
- "auto-#{Time.now.strftime('%Y%m%d-%H%M%S')}"
54
+ def auto_session_name(messages: [])
55
+ first_user = messages.find { |m| m[:role] == :user }
56
+ return "session-#{Time.now.strftime('%H%M%S')}" unless first_user
57
+
58
+ words = first_user[:content].to_s.downcase.gsub(/[^a-z0-9\s]/, '').split
59
+ slug = words.first(4).join('-')
60
+ slug = "session-#{Time.now.strftime('%H%M%S')}" if slug.empty?
61
+ slug
56
62
  end
57
63
 
58
64
  private
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module TTY
5
- VERSION = '0.4.6'
5
+ VERSION = '0.4.7'
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.6
4
+ version: 0.4.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity