Class: Rubino::CLI::Chat::SessionResolver
- Inherits:
-
Object
- Object
- Rubino::CLI::Chat::SessionResolver
- Defined in:
- lib/rubino/cli/chat/session_resolver.rb
Overview
Resolves which session a chat invocation runs against (–session / –resume / –continue / bare-chat auto-resume) and replays a resumed session’s history through the UI, extracted from ChatCommand (#17). Also owns the resume-facing one-liners (the auto-resume notice and the exit-time resume hint).
Instance Attribute Summary collapse
-
#auto_resumed_session ⇒ Object
readonly
The session a bare-‘chat` auto-resume / –continue picked, when one was found.
Instance Method Summary collapse
-
#initialize(options) ⇒ SessionResolver
constructor
A new instance of SessionResolver.
-
#print_auto_resume_line(ui, session) ⇒ Object
Prominent one-line banner shown when a bare ‘chat` auto-resumed the last session (#99, F2): make it OBVIOUS which session was picked up so a dev never accidentally continues/pollutes an old one.
-
#print_resume_hint(ui, session) ⇒ Object
On exit, hand the user back the exact command to return to this chat.
-
#print_session_history(ui, session_id) ⇒ Object
— Session history replay (resume / continue) —.
-
#resolve_session_id(auto_resume: false) ⇒ Object
Resolves which session this invocation should run against.
-
#resuming_session? ⇒ Boolean
True when the chat was started against an existing session (–resume / –continue / explicit –session / bare-chat auto-resume): show its history rather than the first-run welcome panel.
Constructor Details
#initialize(options) ⇒ SessionResolver
Returns a new instance of SessionResolver.
15 16 17 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 15 def initialize() @options = end |
Instance Attribute Details
#auto_resumed_session ⇒ Object (readonly)
The session a bare-‘chat` auto-resume / –continue picked, when one was found. run_interactive gates the auto-resume notice on this.
21 22 23 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 21 def auto_resumed_session @auto_resumed_session end |
Instance Method Details
#print_auto_resume_line(ui, session) ⇒ Object
Prominent one-line banner shown when a bare ‘chat` auto-resumed the last session (#99, F2): make it OBVIOUS which session was picked up so a dev never accidentally continues/pollutes an old one. Carries the SHORT id, the message count, and the cwd it belongs to — the three facts a “wait, what session am I in?” moment needs — plus how to start fresh. Rendered as a warning (not dim status) so it actually stands out against the resumed history that follows.
83 84 85 86 87 88 89 90 91 92 93 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 83 def print_auto_resume_line(ui, session) return unless session id = session[:id].to_s[0..7] msgs = session[:message_count].to_i msgcnt = "#{msgs} msg#{"s" if msgs != 1}" cwd = pretty_cwd(session[:cwd]) where = cwd ? ", #{cwd}" : "" = "▸ resumed session #{id} (#{msgcnt}#{where}) — /new for fresh" ui.respond_to?(:warning) ? ui.warning() : ui.status() end |
#print_resume_hint(ui, session) ⇒ Object
On exit, hand the user back the exact command to return to this chat. Claude Code prints no equivalent hint; without this, the session id is buried in ~/.claude state and the user has to guess at –resume or scroll back through history. Prefer the human-friendly title when one is set; fall back to the id otherwise.
100 101 102 103 104 105 106 107 108 109 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 100 def print_resume_hint(ui, session) return unless session id = session[:id] title = session[:title] handle = title && !title.to_s.strip.empty? ? %("#{title}") : id return unless handle ui.info("Resume with: rubino chat --resume #{handle}") end |
#print_session_history(ui, session_id) ⇒ Object
— Session history replay (resume / continue) —
PromptAssembler feeds the past turns to the model on every request, but the inline REPL never printed them. On –resume the terminal looked empty even though the model had full context. Replay user, assistant and tool messages through the existing UI methods so the scrolled-back transcript matches what the user originally saw.
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 118 def print_session_history(ui, session_id) return unless session_id = ::Rubino::Session::Store.new.for_session(session_id) return if .empty? ui.status("Loaded #{.size} prior message#{"s" if .size != 1}") ui.separator .each do |msg| at = (msg.created_at) case msg.role.to_s when "user" # A `!` bang command persisted its <bash-input>/<bash-stdout> # context messages as user rows; replay them as the `! <cmd>` # echo + dim output block, never the raw tags. next if BangShell.replay(ui, msg.content, at: at) ui.replay_user_input(msg.content, at: at) when "assistant" next if msg.content.nil? || msg.content.to_s.empty? # Render the prior assistant turn as markdown, same as a live reply — # not the old box (which the M2 redesign repurposed into a "● running" # tool-style row, so resume showed assistant turns as fake tool runs # with raw markdown). ui.assistant_text(msg.content) when "tool" name = msg.tool_name || "tool" arguments = msg..is_a?(Hash) ? msg.[:arguments] : nil ui.tool_started(name, arguments: arguments, at: at) ui.tool_finished(name, result: replay_tool_result(msg, name)) end end ui.separator end |
#resolve_session_id(auto_resume: false) ⇒ Object
Resolves which session this invocation should run against. auto_resume enables the bare-‘chat` auto-resume (#99) — only the interactive REPL opts in; one-shot (`-q`/scripted) keeps the old “fresh unless asked” behaviour so automation isn’t silently hijacked onto a past session.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 27 def resolve_session_id(auto_resume: false) # Reap sessions orphaned by a hard kill (SIGKILL) or a closed terminal # whose SIGHUP never landed (#11): end any "active" row whose owning # process is gone before we resolve a resume target, so --continue / # auto-resume never treats a dead session as live. Session::Repository.new.reap_orphaned_active! id = opt(:session) return id if id resume = opt(:resume) || opt(:r) return resume if resume if opt(:continue) || opt(:c) # Explicit --continue/-c resumes the same session a bare `chat` # auto-resume would (#43): the latest RESUMABLE session (any status, # message_count > 0), not just an "active" one — otherwise a cleanly # ended prior session is invisible and -c silently forks a fresh one, # losing context. SCOPED to the launch dir (r5 MF-4 / C-1) so -c in # folder B never resumes folder A's conversation, and a session a # different live tab is still writing is skipped (no two-tab stomp). # When there genuinely is none for this dir, tell the user instead of # silently starting over. @auto_resumed_session = Session::Repository.new.latest_resumable_for_cwd return @auto_resumed_session[:id] if @auto_resumed_session warn pastel.yellow("No previous session to continue in this directory — starting a new one.") return nil end # --new forces a brand-new session; otherwise a BARE interactive `chat` # auto-resumes the most recent resumable session FOR THIS dir so a user # who closed the terminal continues where they left off — without ever # grabbing another folder's session (r5 MF-4 / C-1). nil ⇒ no prior # session for this dir (true first run here) ⇒ fresh session + welcome. return nil if opt(:new) || !auto_resume @auto_resumed_session = Session::Repository.new.latest_resumable_for_cwd @auto_resumed_session&.dig(:id) end |
#resuming_session? ⇒ Boolean
True when the chat was started against an existing session (–resume / –continue / explicit –session / bare-chat auto-resume): show its history rather than the first-run welcome panel.
71 72 73 74 |
# File 'lib/rubino/cli/chat/session_resolver.rb', line 71 def resuming_session? !!(opt(:session) || opt(:resume) || opt(:r) || opt(:continue) || opt(:c) || @auto_resumed_session) end |