legion-tty 0.4.25 → 0.4.26
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 +11 -0
- data/README.md +120 -56
- data/lib/legion/tty/screens/chat/message_commands.rb +42 -0
- data/lib/legion/tty/screens/chat/ui_commands.rb +92 -0
- data/lib/legion/tty/screens/chat.rb +9 -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: 8afc2aa24b5ae5e56f84d7f7ff538e9d0ccc0b9274fd983cec26116fb234b774
|
|
4
|
+
data.tar.gz: 2d442f8ca2ec7a2624f4f3de63defb569c3b324babfff9e8f98c9540bef984d3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f1cd31e1a7fff97bd1de1088247fa1c195c27beaaef7f7d94df5e0ebaf6e46bca7c31a55c2321956c9fbbb46a88e862b6db6139f5df54b104785e1061766b37e
|
|
7
|
+
data.tar.gz: f38bec5c06b804f6b74fc103804a7b46cb9a9b762ec73c4eac3409d0ea72db235b69638b93cd8342a9052d4a5eb20399498b05e0cda59a303c911c4b08e734f2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.4.26] - 2026-03-19
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- `/goto <N>` command: jump to specific message by index
|
|
7
|
+
- `/inject <role> <text>` command: inject a message with specific role (user/assistant/system)
|
|
8
|
+
- `/stopwatch [start|stop|lap|reset]` command: built-in stopwatch with MM:SS.ms format
|
|
9
|
+
- `/ago <N>` command: show what was said N messages ago
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- Updated README.md and CLAUDE.md to reflect 107 slash commands, 1732 specs, 146 files
|
|
13
|
+
|
|
3
14
|
## [0.4.25] - 2026-03-19
|
|
4
15
|
|
|
5
16
|
### Added
|
data/README.md
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
Rich terminal UI for the LegionIO async cognition engine.
|
|
4
4
|
|
|
5
|
-
**Version**: 0.4.
|
|
5
|
+
**Version**: 0.4.25
|
|
6
6
|
|
|
7
|
-
Think Claude Code meets Codex CLI, but for LegionIO: onboarding wizard with identity detection, streaming AI chat shell with
|
|
7
|
+
Think Claude Code meets Codex CLI, but for LegionIO: onboarding wizard with identity detection, streaming AI chat shell with 103 slash commands, operational dashboard, extensions browser, config editor, and session persistence - all rendered with the [tty-ruby](https://ttytoolkit.org/) gem ecosystem.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
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
|
|
13
|
+
- **AI chat shell** - Streaming LLM chat with 103 slash commands, tab completion, markdown rendering, and tool panels
|
|
14
14
|
- **Operational dashboard** - Service/LLM status, extension inventory, system info, panel navigation (Ctrl+D or `/dashboard`)
|
|
15
15
|
- **Extensions browser** - Browse installed LEX gems by category with detail view and homepage opener ('o' key)
|
|
16
16
|
- **Config viewer/editor** - View and edit `~/.legionio/settings/*.json` with vault:// masking and JSON validation
|
|
@@ -35,6 +35,26 @@ Think Claude Code meets Codex CLI, but for LegionIO: onboarding wizard with iden
|
|
|
35
35
|
- **Animated spinner** - Status bar spinner during LLM thinking
|
|
36
36
|
- **Daemon routing** - Routes through LegionIO daemon when available, falls back to direct
|
|
37
37
|
- **Second-run flow** - Skips onboarding, re-scans environment, drops into chat
|
|
38
|
+
- **Session chaining** - `/chain` sends pipe-separated prompts sequentially; `/info` shows full session state
|
|
39
|
+
- **Scroll navigation** - `/scroll`, `/top`, `/bottom`, `/head`, `/tail` for precise history navigation
|
|
40
|
+
- **Conversation editing** - `/replace`, `/reset`, `/prompt`, `/highlight` for post-hoc message editing
|
|
41
|
+
- **Multi-line input** - `/multiline` toggles submit-on-empty-line mode with `[ML]` status indicator
|
|
42
|
+
- **Message annotations** - `/annotate` and `/annotations` for inline notes on specific messages
|
|
43
|
+
- **Message filtering** - `/filter` by role, tag, or pinned status
|
|
44
|
+
- **Export YAML** - `/export yaml` alongside existing md/json/html formats
|
|
45
|
+
- **Session archiving** - `/archive` moves session to `~/.legionio/archives/` and starts fresh
|
|
46
|
+
- **Shell integration** - `/tee` mirrors messages to a file in real-time; `/pipe` pipes output through a shell command
|
|
47
|
+
- **Math utilities** - `/calc` for safe expression evaluation; `/rand` for random number generation
|
|
48
|
+
- **Shell-like commands** - `/ls`, `/pwd`, `/echo`, `/env` for quick filesystem and environment inspection
|
|
49
|
+
- **Display controls** - `/wrap`, `/number`, `/color`, `/timestamps`, `/truncate`, `/silent`, `/speak`
|
|
50
|
+
- **Draft buffer** - `/draft` and `/revise` for composing and editing messages before sending
|
|
51
|
+
- **Word frequency** - `/freq` shows top-20 words in conversation (excludes stop words)
|
|
52
|
+
- **Named markers** - `/mark` inserts named bookmarks; list all markers with `/mark`
|
|
53
|
+
- **Persistent preferences** - `/prefs` reads/writes `~/.legionio/prefs.json` across sessions
|
|
54
|
+
- **Quick Q&A** - `/ask` and `/define` for concise one-paragraph LLM answers
|
|
55
|
+
- **Status overview** - `/status` shows all 18 toggleable modes and settings at a glance
|
|
56
|
+
- **Command discovery** - `/commands [pattern]` lists all slash commands with optional pattern filter
|
|
57
|
+
- **About info** - `/about` shows gem name, version, author, license, and GitHub URL
|
|
38
58
|
|
|
39
59
|
## Installation
|
|
40
60
|
|
|
@@ -76,64 +96,108 @@ legion chat prompt "explain async cognition"
|
|
|
76
96
|
|
|
77
97
|
| Command | Description |
|
|
78
98
|
|---------|-------------|
|
|
79
|
-
| `/
|
|
80
|
-
| `/
|
|
99
|
+
| `/about` | Show gem name, version, author, license, and GitHub URL |
|
|
100
|
+
| `/alias [name] [cmd]` | Create or list command aliases |
|
|
101
|
+
| `/annotate [N] <text>` | Add a note to a specific message |
|
|
102
|
+
| `/annotations` | List all annotated messages with their notes |
|
|
103
|
+
| `/archive [name]` | Archive session to `~/.legionio/archives/` and start fresh |
|
|
104
|
+
| `/archives` | List all archived sessions with file sizes |
|
|
105
|
+
| `/ask <question>` | Quick concise Q&A mode (LLM answers in one paragraph) |
|
|
106
|
+
| `/autosave [N\|off]` | Toggle periodic auto-save with configurable interval |
|
|
107
|
+
| `/bookmark` | Export pinned messages to a markdown file |
|
|
108
|
+
| `/bottom` | Scroll to bottom of message history |
|
|
109
|
+
| `/calc <expression>` | Evaluate a math expression (supports Math functions) |
|
|
110
|
+
| `/chain <p1\|p2\|...>` | Send pipe-separated prompts to LLM sequentially |
|
|
81
111
|
| `/clear` | Clear message history |
|
|
82
|
-
| `/
|
|
83
|
-
| `/
|
|
112
|
+
| `/color [on\|off]` | Toggle colorized output (strips ANSI codes when off) |
|
|
113
|
+
| `/commands [pattern]` | List all slash commands with optional pattern filter |
|
|
114
|
+
| `/compact [N]` | Keep last N message pairs, remove older |
|
|
115
|
+
| `/config` | View and edit `~/.legionio/settings/*.json` files |
|
|
116
|
+
| `/context` | Show active session state summary |
|
|
117
|
+
| `/copy` | Copy last assistant response to clipboard |
|
|
84
118
|
| `/cost` | Show token usage and estimated cost |
|
|
85
|
-
| `/
|
|
86
|
-
| `/tools` | List discovered LEX extensions |
|
|
119
|
+
| `/count <pattern>` | Count messages matching a pattern with per-role breakdown |
|
|
87
120
|
| `/dashboard` | Toggle operational dashboard |
|
|
88
|
-
| `/
|
|
89
|
-
| `/
|
|
90
|
-
| `/load <name>` | Load a saved session |
|
|
91
|
-
| `/sessions` | List all saved sessions |
|
|
92
|
-
| `/system <prompt>` | Set or override system prompt |
|
|
121
|
+
| `/debug` | Toggle debug mode |
|
|
122
|
+
| `/define <term>` | Ask LLM for a concise definition |
|
|
93
123
|
| `/delete <session>` | Delete a saved session |
|
|
94
|
-
| `/
|
|
95
|
-
| `/
|
|
124
|
+
| `/diff` | Show new messages since last session load |
|
|
125
|
+
| `/draft [text\|send\|clear]` | Save text to draft buffer, show, send, or clear it |
|
|
126
|
+
| `/echo <text>` | Add a user-defined system message note |
|
|
127
|
+
| `/env` | Show environment info (Ruby version, platform, terminal, PID) |
|
|
128
|
+
| `/export [md\|json\|html\|yaml]` | Export chat history to file |
|
|
96
129
|
| `/extensions` | Browse installed LEX extensions |
|
|
97
|
-
| `/
|
|
98
|
-
| `/
|
|
99
|
-
| `/
|
|
130
|
+
| `/fav [N]` | Favorite a message (persists to `~/.legionio/favorites.json`) |
|
|
131
|
+
| `/favs` | Show all favorited messages |
|
|
132
|
+
| `/filter [role\|tag\|pinned\|clear]` | Filter displayed messages |
|
|
133
|
+
| `/focus` | Toggle minimal UI (hide status bar) |
|
|
134
|
+
| `/freq` | Word frequency analysis with top 20 words (excludes stop words) |
|
|
100
135
|
| `/grep <pattern>` | Regex search across messages |
|
|
101
|
-
| `/
|
|
102
|
-
| `/
|
|
103
|
-
| `/
|
|
104
|
-
| `/stats` | Show conversation statistics |
|
|
105
|
-
| `/personality [style]` | Switch personality (default/concise/detailed/friendly/technical) |
|
|
106
|
-
| `/undo` | Remove last user+assistant message pair |
|
|
136
|
+
| `/head [N]` | Peek at first N messages (default 5) |
|
|
137
|
+
| `/help` | Show all commands and hotkeys |
|
|
138
|
+
| `/highlight <pattern>` | Highlight text patterns in message rendering |
|
|
107
139
|
| `/history` | Show input history |
|
|
140
|
+
| `/hotkeys` | Show registered hotkey bindings |
|
|
141
|
+
| `/import <path>` | Import session from a JSON file |
|
|
142
|
+
| `/info` | Comprehensive session info (modes, counts, aliases, macros, provider) |
|
|
143
|
+
| `/load <name>` | Load a saved session |
|
|
144
|
+
| `/log [N]` | View last N lines of boot log (default 20) |
|
|
145
|
+
| `/ls [path]` | List directory contents |
|
|
146
|
+
| `/macro <action>` | Record/stop/play/list/delete command macros |
|
|
147
|
+
| `/mark <label>` | Insert a named marker/bookmark in conversation |
|
|
148
|
+
| `/merge <session>` | Merge another session into current |
|
|
149
|
+
| `/model <name>` | Switch LLM model at runtime |
|
|
150
|
+
| `/multiline` | Toggle multi-line input mode (submit with empty line) |
|
|
151
|
+
| `/mute` | Toggle system message display |
|
|
152
|
+
| `/number [on\|off]` | Toggle message numbering with `[N]` prefix |
|
|
153
|
+
| `/palette` | Open command palette (fuzzy search) |
|
|
154
|
+
| `/personality [style]` | Switch personality (default/concise/detailed/friendly/technical) |
|
|
108
155
|
| `/pin [N]` | Pin a message (last assistant or by index) |
|
|
109
156
|
| `/pins` | Show all pinned messages |
|
|
157
|
+
| `/pipe <command>` | Pipe last assistant response through a shell command |
|
|
158
|
+
| `/plan` | Toggle read-only bookmark mode |
|
|
159
|
+
| `/prefs [key] [value]` | Read or write persistent user preferences |
|
|
160
|
+
| `/prompt save\|load\|list\|delete` | Persist and reuse custom system prompts |
|
|
161
|
+
| `/pwd` | Show current working directory |
|
|
162
|
+
| `/quit` | Exit (auto-saves session) |
|
|
163
|
+
| `/rand [N\|min..max]` | Generate random numbers (float, integer, or range) |
|
|
164
|
+
| `/react <emoji>` | Add emoji reaction to a message |
|
|
110
165
|
| `/rename <name>` | Rename current session (moves saved file) |
|
|
111
|
-
| `/
|
|
112
|
-
| `/
|
|
166
|
+
| `/repeat` | Re-execute the last slash command |
|
|
167
|
+
| `/replace old >>> new` | Find and replace text across all messages |
|
|
168
|
+
| `/reset` | Reset session to clean state |
|
|
169
|
+
| `/retry` | Resend last user message to LLM |
|
|
170
|
+
| `/revise <text>` | Replace the content of the last user message |
|
|
171
|
+
| `/save [name]` | Save current session |
|
|
172
|
+
| `/scroll [top\|bottom\|N]` | Navigate to a specific scroll position |
|
|
173
|
+
| `/search <text>` | Search message history |
|
|
174
|
+
| `/session <name>` | Set session name |
|
|
175
|
+
| `/sessions` | List all saved sessions |
|
|
176
|
+
| `/silent` | Toggle silent mode (responses tracked but not displayed) |
|
|
113
177
|
| `/snippet <action>` | Save/load/list/delete code snippets |
|
|
114
|
-
| `/
|
|
115
|
-
| `/
|
|
116
|
-
| `/
|
|
117
|
-
| `/
|
|
118
|
-
| `/
|
|
119
|
-
| `/
|
|
120
|
-
| `/macro <action>` | Record/stop/play/list/delete command macros |
|
|
178
|
+
| `/sort [length\|role]` | Show messages sorted by length or grouped by role |
|
|
179
|
+
| `/speak [on\|off]` | Toggle text-to-speech for assistant messages (macOS only) |
|
|
180
|
+
| `/stats` | Show conversation statistics |
|
|
181
|
+
| `/status` | Show all 18 toggleable modes and settings |
|
|
182
|
+
| `/summary` | Generate a local conversation summary |
|
|
183
|
+
| `/system <prompt>` | Set or override system prompt |
|
|
121
184
|
| `/tag <label>` | Tag a message with a label |
|
|
122
185
|
| `/tags [label]` | Show tag statistics or filter by tag |
|
|
123
|
-
| `/
|
|
124
|
-
| `/
|
|
125
|
-
| `/template [name]` | List or use prompt templates |
|
|
126
|
-
| `/
|
|
127
|
-
| `/
|
|
128
|
-
| `/
|
|
186
|
+
| `/tail [N]` | Peek at last N messages (default 5) |
|
|
187
|
+
| `/tee <path>` | Copy new messages to a file in real-time |
|
|
188
|
+
| `/template [name]` | List or use prompt templates (8 built-in) |
|
|
189
|
+
| `/theme [name]` | Switch color theme (purple/green/blue/amber) |
|
|
190
|
+
| `/time` | Show current date and time |
|
|
191
|
+
| `/timestamps [on\|off]` | Toggle timestamp display on messages |
|
|
192
|
+
| `/tools` | List discovered LEX extensions |
|
|
193
|
+
| `/top` | Scroll to top of message history |
|
|
194
|
+
| `/truncate [N\|off]` | Display-only truncation of long messages |
|
|
195
|
+
| `/undo` | Remove last user+assistant message pair |
|
|
196
|
+
| `/uptime` | Show session elapsed time |
|
|
129
197
|
| `/version` | Show version and platform info |
|
|
130
|
-
| `/
|
|
131
|
-
| `/
|
|
132
|
-
| `/
|
|
133
|
-
| `/sort [length\|role]` | Show messages sorted by length or role |
|
|
134
|
-
| `/import <path>` | Import session from a JSON file |
|
|
135
|
-
| `/mute` | Toggle system message display |
|
|
136
|
-
| `/wc` | Show word count statistics |
|
|
198
|
+
| `/wc` | Show word count statistics per role |
|
|
199
|
+
| `/welcome` | Redisplay the welcome message |
|
|
200
|
+
| `/wrap [N\|off]` | Set custom word wrap width |
|
|
137
201
|
|
|
138
202
|
## Hotkeys
|
|
139
203
|
|
|
@@ -158,13 +222,13 @@ legion-tty
|
|
|
158
222
|
|
|
159
223
|
Screens/
|
|
160
224
|
Onboarding # First-run wizard (rain -> intro -> wizard -> reveal)
|
|
161
|
-
Chat # AI chat REPL with streaming +
|
|
162
|
-
SessionCommands # save/load/sessions/delete/rename
|
|
163
|
-
ExportCommands # export/bookmark/html/json/markdown
|
|
164
|
-
MessageCommands # compact/copy/diff/search/grep/undo/pin/pins
|
|
165
|
-
UiCommands # help/clear/dashboard/hotkeys/palette/context/stats/debug/history/uptime/time
|
|
166
|
-
ModelCommands # model/system/personality switching
|
|
167
|
-
CustomCommands # alias/snippet
|
|
225
|
+
Chat # AI chat REPL with streaming + 103 slash commands
|
|
226
|
+
SessionCommands # save/load/sessions/delete/rename/import/merge/autosave
|
|
227
|
+
ExportCommands # export/bookmark/html/json/markdown/yaml
|
|
228
|
+
MessageCommands # compact/copy/diff/search/grep/undo/pin/pins/react/tag/fav/sort/count
|
|
229
|
+
UiCommands # help/clear/dashboard/hotkeys/palette/context/stats/debug/history/uptime/time/tips/welcome/focus/wc/log/version/mute + calc/rand/mark/freq/color/timestamps/top/bottom/head/tail/echo/env/speak/silent/wrap/number/truncate/about/commands/ask/define/status/prefs
|
|
230
|
+
ModelCommands # model/system/personality switching/retry/chain/info/scroll/summary/prompt/reset/replace/highlight/multiline/filter/annotate/annotations
|
|
231
|
+
CustomCommands # alias/snippet/template/macro/draft/revise/tee/pipe/archive/archives/ls/pwd/rand/calc
|
|
168
232
|
Dashboard # Service/LLM status, panel navigation (j/k/1-5)
|
|
169
233
|
Extensions # LEX gem browser by category with homepage opener
|
|
170
234
|
Config # Settings file viewer/editor with JSON validation
|
|
@@ -213,8 +277,8 @@ Boot logs go to `~/.legionio/logs/tty-boot.log`.
|
|
|
213
277
|
|
|
214
278
|
```bash
|
|
215
279
|
bundle install
|
|
216
|
-
bundle exec rspec #
|
|
217
|
-
bundle exec rubocop #
|
|
280
|
+
bundle exec rspec # 1687 examples, 0 failures
|
|
281
|
+
bundle exec rubocop # 143 files, 0 offenses
|
|
218
282
|
```
|
|
219
283
|
|
|
220
284
|
## License
|
|
@@ -5,6 +5,8 @@ module Legion
|
|
|
5
5
|
module Screens
|
|
6
6
|
class Chat < Base
|
|
7
7
|
module MessageCommands
|
|
8
|
+
INJECT_VALID_ROLES = %w[user assistant system].freeze
|
|
9
|
+
|
|
8
10
|
private
|
|
9
11
|
|
|
10
12
|
# rubocop:disable Metrics/AbcSize
|
|
@@ -655,6 +657,46 @@ module Legion
|
|
|
655
657
|
@message_stream.add_message(role: :system, content: "Revised: #{new_content}")
|
|
656
658
|
:handled
|
|
657
659
|
end
|
|
660
|
+
|
|
661
|
+
def handle_inject(input)
|
|
662
|
+
parts = input.split(nil, 3)
|
|
663
|
+
role_str = parts[1]
|
|
664
|
+
text = parts[2]
|
|
665
|
+
|
|
666
|
+
unless role_str && INJECT_VALID_ROLES.include?(role_str) && text && !text.strip.empty?
|
|
667
|
+
@message_stream.add_message(
|
|
668
|
+
role: :system,
|
|
669
|
+
content: 'Usage: /inject <user|assistant|system> <text>'
|
|
670
|
+
)
|
|
671
|
+
return :handled
|
|
672
|
+
end
|
|
673
|
+
|
|
674
|
+
@message_stream.add_message(role: role_str.to_sym, content: text.strip)
|
|
675
|
+
@status_bar.update(message_count: @message_stream.messages.size)
|
|
676
|
+
@message_stream.add_message(role: :system, content: "Injected [#{role_str}] message.")
|
|
677
|
+
:handled
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
def handle_ago(input)
|
|
681
|
+
n = (input.split(nil, 2)[1] || '1').to_i
|
|
682
|
+
msgs = @message_stream.messages
|
|
683
|
+
if n < 1 || n > msgs.size
|
|
684
|
+
@message_stream.add_message(
|
|
685
|
+
role: :system,
|
|
686
|
+
content: "No message #{n} ago (conversation has #{msgs.size} message(s))."
|
|
687
|
+
)
|
|
688
|
+
return :handled
|
|
689
|
+
end
|
|
690
|
+
|
|
691
|
+
idx = msgs.size - n
|
|
692
|
+
msg = msgs[idx]
|
|
693
|
+
preview = truncate_text(msg[:content].to_s, 200)
|
|
694
|
+
@message_stream.add_message(
|
|
695
|
+
role: :system,
|
|
696
|
+
content: "[#{n} ago | ##{idx} | #{msg[:role]}] #{preview}"
|
|
697
|
+
)
|
|
698
|
+
:handled
|
|
699
|
+
end
|
|
658
700
|
end
|
|
659
701
|
end
|
|
660
702
|
end
|
|
@@ -393,6 +393,37 @@ module Legion
|
|
|
393
393
|
end
|
|
394
394
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
395
395
|
|
|
396
|
+
def handle_goto(input)
|
|
397
|
+
n_str = input.split(nil, 2)[1]
|
|
398
|
+
unless n_str&.match?(/\A\d+\z/)
|
|
399
|
+
@message_stream.add_message(role: :system, content: 'Usage: /goto <N>')
|
|
400
|
+
return :handled
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
idx = n_str.to_i
|
|
404
|
+
return goto_out_of_range(idx) unless goto_in_range?(idx)
|
|
405
|
+
|
|
406
|
+
scroll_to_message(idx)
|
|
407
|
+
@message_stream.add_message(role: :system, content: "Jumped to message #{idx}.")
|
|
408
|
+
:handled
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def goto_in_range?(idx)
|
|
412
|
+
idx >= 0 && idx < @message_stream.messages.size
|
|
413
|
+
end
|
|
414
|
+
|
|
415
|
+
def goto_out_of_range(idx)
|
|
416
|
+
total = @message_stream.messages.size
|
|
417
|
+
@message_stream.add_message(role: :system, content: "Message #{idx} out of range (0..#{total - 1}).")
|
|
418
|
+
:handled
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
def scroll_to_message(idx)
|
|
422
|
+
total = @message_stream.messages.size
|
|
423
|
+
@message_stream.scroll_down(@message_stream.scroll_offset)
|
|
424
|
+
@message_stream.scroll_up([total - idx - 1, 0].max)
|
|
425
|
+
end
|
|
426
|
+
|
|
396
427
|
def handle_highlight(input)
|
|
397
428
|
arg = input.split(nil, 2)[1]
|
|
398
429
|
@highlights ||= []
|
|
@@ -852,6 +883,67 @@ module Legion
|
|
|
852
883
|
when 'timestamps' then handle_timestamps("/timestamps #{value}")
|
|
853
884
|
end
|
|
854
885
|
end
|
|
886
|
+
|
|
887
|
+
def handle_stopwatch(input)
|
|
888
|
+
sub = input.split(nil, 2)[1]&.strip
|
|
889
|
+
case sub
|
|
890
|
+
when 'start' then stopwatch_start
|
|
891
|
+
when 'stop' then stopwatch_stop
|
|
892
|
+
when 'lap' then stopwatch_lap
|
|
893
|
+
when 'reset' then stopwatch_reset
|
|
894
|
+
else stopwatch_status
|
|
895
|
+
end
|
|
896
|
+
:handled
|
|
897
|
+
end
|
|
898
|
+
|
|
899
|
+
def stopwatch_start
|
|
900
|
+
@stopwatch_start = Time.now
|
|
901
|
+
@message_stream.add_message(role: :system, content: 'Stopwatch started.')
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
def stopwatch_stop
|
|
905
|
+
unless @stopwatch_start
|
|
906
|
+
@message_stream.add_message(role: :system, content: 'Stopwatch is not running.')
|
|
907
|
+
return
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
@stopwatch_elapsed += Time.now - @stopwatch_start
|
|
911
|
+
@stopwatch_start = nil
|
|
912
|
+
@message_stream.add_message(role: :system,
|
|
913
|
+
content: "Stopwatch stopped. Elapsed: #{format_stopwatch(@stopwatch_elapsed)}")
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def stopwatch_lap
|
|
917
|
+
total = @stopwatch_elapsed
|
|
918
|
+
total += Time.now - @stopwatch_start if @stopwatch_start
|
|
919
|
+
@message_stream.add_message(role: :system, content: "Lap: #{format_stopwatch(total)}")
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
def stopwatch_reset
|
|
923
|
+
@stopwatch_start = nil
|
|
924
|
+
@stopwatch_elapsed = 0
|
|
925
|
+
@message_stream.add_message(role: :system, content: 'Stopwatch reset.')
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
def stopwatch_status
|
|
929
|
+
if @stopwatch_start
|
|
930
|
+
total = @stopwatch_elapsed + (Time.now - @stopwatch_start)
|
|
931
|
+
@message_stream.add_message(role: :system, content: "Stopwatch running: #{format_stopwatch(total)}")
|
|
932
|
+
elsif @stopwatch_elapsed.positive?
|
|
933
|
+
@message_stream.add_message(role: :system,
|
|
934
|
+
content: "Stopwatch stopped at: #{format_stopwatch(@stopwatch_elapsed)}")
|
|
935
|
+
else
|
|
936
|
+
@message_stream.add_message(role: :system, content: 'Stopwatch: 00:00.000 (not started)')
|
|
937
|
+
end
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
def format_stopwatch(seconds)
|
|
941
|
+
total_ms = (seconds * 1000).to_i
|
|
942
|
+
ms = total_ms % 1000
|
|
943
|
+
secs = (total_ms / 1000) % 60
|
|
944
|
+
mins = total_ms / 60_000
|
|
945
|
+
format('%<mins>02d:%<secs>02d.%<ms>03d', mins: mins, secs: secs, ms: ms)
|
|
946
|
+
end
|
|
855
947
|
end
|
|
856
948
|
end
|
|
857
949
|
end
|
|
@@ -48,7 +48,9 @@ module Legion
|
|
|
48
48
|
/mark /freq
|
|
49
49
|
/about /commands
|
|
50
50
|
/ask /define
|
|
51
|
-
/status /prefs
|
|
51
|
+
/status /prefs
|
|
52
|
+
/stopwatch /ago
|
|
53
|
+
/goto /inject].freeze
|
|
52
54
|
|
|
53
55
|
PERSONALITIES = {
|
|
54
56
|
'default' => 'You are Legion, an async cognition engine and AI assistant. Be helpful and concise.',
|
|
@@ -93,6 +95,8 @@ module Legion
|
|
|
93
95
|
@speak_mode = false
|
|
94
96
|
@silent_mode = false
|
|
95
97
|
@draft = nil
|
|
98
|
+
@stopwatch_start = nil
|
|
99
|
+
@stopwatch_elapsed = 0
|
|
96
100
|
end
|
|
97
101
|
|
|
98
102
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
|
@@ -501,6 +505,10 @@ module Legion
|
|
|
501
505
|
when '/define' then handle_define(input)
|
|
502
506
|
when '/status' then handle_status
|
|
503
507
|
when '/prefs' then handle_prefs(input)
|
|
508
|
+
when '/stopwatch' then handle_stopwatch(input)
|
|
509
|
+
when '/ago' then handle_ago(input)
|
|
510
|
+
when '/goto' then handle_goto(input)
|
|
511
|
+
when '/inject' then handle_inject(input)
|
|
504
512
|
else :handled
|
|
505
513
|
end
|
|
506
514
|
end
|
data/lib/legion/tty/version.rb
CHANGED