update: SessionId / SessionStart / SessionOrigin 等を Segment 系名称へ
- Type/Function/Variantを Segment* 系へ統一 - SessionId/SessionStart/SessionOrigin/SessionStartState/SessionState/SessionLogSink/SessionLockInfo - new_session_id / session_id / create_session* / list_sessions / lookup_session / update_session / find_by_session - protocol Event::SessionRotated → SegmentRotated、CompactDone.new_session_id → new_segment_id - Module: session_log → segment_log / session → segment (file mv 含む) pod 側の session_log_sink → segment_log_sink も同様 - crate 名 (session-store)、CLI flag (--session)、ResumeWithSession (CLI tied) は据え置き - session-tests/session_metrics_test 等の Store impl も追従
This commit is contained in:
+10
-10
@@ -483,7 +483,7 @@ impl App {
|
||||
self.blocks.push(Block::UserMessage { segments });
|
||||
self.assistant_streaming = false;
|
||||
}
|
||||
Event::SessionRotated { entry } => {
|
||||
Event::SegmentRotated { entry } => {
|
||||
self.reset_for_rotation();
|
||||
self.apply_log_entry_raw(&entry);
|
||||
self.assistant_streaming = false;
|
||||
@@ -685,7 +685,7 @@ impl App {
|
||||
started_at: Instant::now(),
|
||||
}));
|
||||
}
|
||||
Event::CompactDone { new_session_id } => {
|
||||
Event::CompactDone { new_segment_id } => {
|
||||
if let Some(evt) = self.last_streaming_compact_mut() {
|
||||
let elapsed_secs = match evt {
|
||||
CompactEvent::Streaming { started_at } => {
|
||||
@@ -694,12 +694,12 @@ impl App {
|
||||
_ => None,
|
||||
};
|
||||
*evt = CompactEvent::Done {
|
||||
new_session_id,
|
||||
new_segment_id,
|
||||
elapsed_secs,
|
||||
};
|
||||
} else {
|
||||
self.blocks.push(Block::Compact(CompactEvent::Done {
|
||||
new_session_id,
|
||||
new_segment_id,
|
||||
elapsed_secs: None,
|
||||
}));
|
||||
}
|
||||
@@ -932,7 +932,7 @@ impl App {
|
||||
}
|
||||
|
||||
/// Drop the derived view in preparation for replaying a new
|
||||
/// `SessionStart` (compaction / fork). Greeting is preserved
|
||||
/// `SegmentStart` (compaction / fork). Greeting is preserved
|
||||
/// because the Pod identity hasn't changed.
|
||||
fn reset_for_rotation(&mut self) {
|
||||
let greeting = self.blocks.iter().find_map(|b| match b {
|
||||
@@ -958,7 +958,7 @@ impl App {
|
||||
return;
|
||||
};
|
||||
match entry {
|
||||
session_store::LogEntry::SessionStart { history, .. } => {
|
||||
session_store::LogEntry::SegmentStart { history, .. } => {
|
||||
for logged in history {
|
||||
let item: llm_worker::Item = logged.into();
|
||||
let item_value = serde_json::to_value(&item).expect("Item is Serialize");
|
||||
@@ -1445,7 +1445,7 @@ mod completion_flow_tests {
|
||||
#[test]
|
||||
fn snapshot_renders_system_message_block_from_session_start() {
|
||||
let mut app = App::new("test".into());
|
||||
let session_start = session_store::LogEntry::SessionStart {
|
||||
let session_start = session_store::LogEntry::SegmentStart {
|
||||
ts: 1,
|
||||
system_prompt: None,
|
||||
config: Default::default(),
|
||||
@@ -1525,15 +1525,15 @@ mod completion_flow_tests {
|
||||
let id = uuid::Uuid::parse_str("12345678-1234-5678-1234-567812345678").unwrap();
|
||||
|
||||
app.handle_pod_event(Event::CompactStart);
|
||||
app.handle_pod_event(Event::CompactDone { new_session_id: id });
|
||||
app.handle_pod_event(Event::CompactDone { new_segment_id: id });
|
||||
|
||||
assert_eq!(compact_block_count(&app), 1);
|
||||
assert!(matches!(
|
||||
app.blocks.as_slice(),
|
||||
[Block::Compact(CompactEvent::Done {
|
||||
new_session_id,
|
||||
new_segment_id,
|
||||
elapsed_secs: Some(_),
|
||||
})] if *new_session_id == id
|
||||
})] if *new_segment_id == id
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ pub enum CompactEvent {
|
||||
Streaming { started_at: Instant },
|
||||
/// Compaction ended cleanly with `CompactDone`.
|
||||
Done {
|
||||
new_session_id: uuid::Uuid,
|
||||
new_segment_id: uuid::Uuid,
|
||||
elapsed_secs: Option<u64>,
|
||||
},
|
||||
/// Compaction ended with `CompactFailed`.
|
||||
|
||||
@@ -25,7 +25,7 @@ use crossterm::terminal::{
|
||||
use protocol::{Method, PodStatus};
|
||||
use ratatui::Terminal;
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use session_store::SessionId;
|
||||
use session_store::SegmentId;
|
||||
|
||||
use client::PodClient;
|
||||
|
||||
@@ -56,7 +56,7 @@ enum Mode {
|
||||
Resume,
|
||||
/// `tui --session <UUID>`: skip the picker, go straight to the
|
||||
/// resume name dialog with `id` baked in.
|
||||
ResumeWithSession(SessionId),
|
||||
ResumeWithSession(SegmentId),
|
||||
}
|
||||
|
||||
enum ParseError {
|
||||
@@ -78,7 +78,7 @@ impl std::fmt::Display for ParseError {
|
||||
fn parse_args() -> Result<Mode, ParseError> {
|
||||
let args: Vec<String> = std::env::args().skip(1).collect();
|
||||
let mut resume = false;
|
||||
let mut session: Option<SessionId> = None;
|
||||
let mut session: Option<SegmentId> = None;
|
||||
let mut socket_override: Option<PathBuf> = None;
|
||||
let mut positional: Option<String> = None;
|
||||
|
||||
@@ -94,7 +94,7 @@ fn parse_args() -> Result<Mode, ParseError> {
|
||||
.get(i + 1)
|
||||
.ok_or(ParseError::MissingValue("--session"))?;
|
||||
session = Some(
|
||||
raw.parse::<SessionId>()
|
||||
raw.parse::<SegmentId>()
|
||||
.map_err(|_| ParseError::InvalidSession(raw.clone()))?,
|
||||
);
|
||||
i += 2;
|
||||
@@ -216,7 +216,7 @@ async fn run_resume() -> Result<(), Box<dyn std::error::Error>> {
|
||||
run_spawn(Some(id)).await
|
||||
}
|
||||
|
||||
async fn run_spawn(resume_from: Option<SessionId>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
async fn run_spawn(resume_from: Option<SegmentId>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let ready = match spawn::run(resume_from).await? {
|
||||
SpawnOutcome::Ready(r) => r,
|
||||
SpawnOutcome::Cancelled => return Ok(()),
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//!
|
||||
//! Reads the most recent sessions from the configured store, lets the
|
||||
//! user pick one with the arrow keys, and returns the chosen
|
||||
//! `SessionId`. Closes its inline viewport before returning so the
|
||||
//! `SegmentId`. Closes its inline viewport before returning so the
|
||||
//! caller can open a fresh viewport for the name dialog.
|
||||
//!
|
||||
//! The picker only handles selection. Forking, pod-registry checks, and
|
||||
@@ -12,7 +12,7 @@ use std::io;
|
||||
use std::time::Duration;
|
||||
|
||||
use crossterm::event::{self, Event as TermEvent, KeyCode, KeyEventKind, KeyModifiers};
|
||||
use pod_registry::lookup_session;
|
||||
use pod_registry::lookup_segment;
|
||||
use ratatui::Terminal;
|
||||
use ratatui::backend::CrosstermBackend;
|
||||
use ratatui::layout::{Constraint, Layout};
|
||||
@@ -20,7 +20,7 @@ use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::{Frame, TerminalOptions, Viewport};
|
||||
use session_store::{FsStore, LogEntry, LoggedContentPart, LoggedItem, SessionId, Store};
|
||||
use session_store::{FsStore, LogEntry, LoggedContentPart, LoggedItem, SegmentId, Store};
|
||||
|
||||
const MAX_ROWS: usize = 10;
|
||||
const VIEWPORT_LINES: u16 = MAX_ROWS as u16 + 4;
|
||||
@@ -60,14 +60,14 @@ impl From<session_store::StoreError> for PickerError {
|
||||
}
|
||||
|
||||
pub enum PickerOutcome {
|
||||
Picked(SessionId),
|
||||
Picked(SegmentId),
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
/// One row in the picker view. Rendered from the session log so the
|
||||
/// user can recognise their session at a glance without parsing UUIDs.
|
||||
struct Row {
|
||||
id: SessionId,
|
||||
id: SegmentId,
|
||||
/// Last user / assistant snippet, or a `[corrupt]` placeholder.
|
||||
preview: String,
|
||||
/// `Some(pod_name)` when a live Pod currently holds an allocation
|
||||
@@ -79,7 +79,7 @@ struct Row {
|
||||
|
||||
pub async fn run() -> Result<PickerOutcome, PickerError> {
|
||||
let store = open_default_store()?;
|
||||
let ids = store.list_sessions()?;
|
||||
let ids = store.list_segments()?;
|
||||
if ids.is_empty() {
|
||||
return Err(PickerError::NoSessions);
|
||||
}
|
||||
@@ -89,7 +89,7 @@ pub async fn run() -> Result<PickerOutcome, PickerError> {
|
||||
// Best-effort live check. A pods.json I/O hiccup downgrades
|
||||
// the row to "no badge" rather than killing the picker — the
|
||||
// user still gets to see the listing.
|
||||
let live_pod = lookup_session(id).ok().flatten().map(|info| info.pod_name);
|
||||
let live_pod = lookup_segment(id).ok().flatten().map(|info| info.pod_name);
|
||||
rows.push(Row {
|
||||
id,
|
||||
preview,
|
||||
@@ -158,7 +158,7 @@ fn open_default_store() -> Result<FsStore, PickerError> {
|
||||
Ok(FsStore::new(&dir)?)
|
||||
}
|
||||
|
||||
fn build_preview(store: &FsStore, id: SessionId) -> String {
|
||||
fn build_preview(store: &FsStore, id: SegmentId) -> String {
|
||||
match store.read_all(id) {
|
||||
Ok(entries) => last_message_preview(&entries).unwrap_or_else(|| "[empty]".to_string()),
|
||||
Err(_) => "[corrupt]".to_string(),
|
||||
@@ -313,7 +313,7 @@ fn row_line(row: &Row, selected: bool) -> Line<'_> {
|
||||
Line::from(spans)
|
||||
}
|
||||
|
||||
fn short_session(id: SessionId) -> String {
|
||||
fn short_session(id: SegmentId) -> String {
|
||||
let s = id.to_string();
|
||||
s.chars().take(8).collect()
|
||||
}
|
||||
|
||||
+11
-11
@@ -28,7 +28,7 @@ use ratatui::style::{Color, Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::{Frame, TerminalOptions, Viewport};
|
||||
use session_store::SessionId;
|
||||
use session_store::SegmentId;
|
||||
|
||||
const VIEWPORT_LINES: u16 = 6;
|
||||
|
||||
@@ -46,7 +46,7 @@ pub enum SpawnOutcome {
|
||||
pub enum SpawnError {
|
||||
Io(io::Error),
|
||||
Store(session_store::StoreError),
|
||||
MissingResumeScope { session_id: SessionId },
|
||||
MissingResumeScope { segment_id: SegmentId },
|
||||
Spawn(client::SpawnError),
|
||||
}
|
||||
|
||||
@@ -55,9 +55,9 @@ impl std::fmt::Display for SpawnError {
|
||||
match self {
|
||||
Self::Io(e) => write!(f, "io error: {e}"),
|
||||
Self::Store(e) => write!(f, "failed to read session log: {e}"),
|
||||
Self::MissingResumeScope { session_id } => write!(
|
||||
Self::MissingResumeScope { segment_id } => write!(
|
||||
f,
|
||||
"session {session_id} has no persisted scope snapshot; refusing resume without explicit scope"
|
||||
"session {segment_id} has no persisted scope snapshot; refusing resume without explicit scope"
|
||||
),
|
||||
Self::Spawn(e) => write!(f, "{e}"),
|
||||
}
|
||||
@@ -89,7 +89,7 @@ type InlineTerminal = Terminal<CrosstermBackend<io::Stdout>>;
|
||||
/// Source session for a resume run. `None` = fresh spawn (current
|
||||
/// behaviour); `Some(id)` swaps the dialog into "Resume Pod" mode and
|
||||
/// passes `--session <id>` to the spawned `pod` child.
|
||||
pub async fn run(resume_from: Option<SessionId>) -> Result<SpawnOutcome, SpawnError> {
|
||||
pub async fn run(resume_from: Option<SegmentId>) -> Result<SpawnOutcome, SpawnError> {
|
||||
let cwd = std::env::current_dir().map_err(SpawnError::Io)?;
|
||||
|
||||
// Run the same merge pod itself uses, then read what's missing
|
||||
@@ -321,7 +321,7 @@ fn build_overlay_toml(form: &Form) -> String {
|
||||
toml::to_string(&toml::Value::Table(root)).expect("overlay serialisation cannot fail")
|
||||
}
|
||||
|
||||
async fn load_resume_scope(session_id: SessionId) -> Result<ScopeConfig, SpawnError> {
|
||||
async fn load_resume_scope(segment_id: SegmentId) -> Result<ScopeConfig, SpawnError> {
|
||||
let store_dir = manifest::paths::sessions_dir().ok_or_else(|| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::NotFound,
|
||||
@@ -329,10 +329,10 @@ async fn load_resume_scope(session_id: SessionId) -> Result<ScopeConfig, SpawnEr
|
||||
)
|
||||
})?;
|
||||
let store = session_store::FsStore::new(&store_dir)?;
|
||||
let state = session_store::restore(&store, session_id)?;
|
||||
let state = session_store::restore(&store, segment_id)?;
|
||||
let snapshot = state
|
||||
.pod_scope
|
||||
.ok_or(SpawnError::MissingResumeScope { session_id })?;
|
||||
.ok_or(SpawnError::MissingResumeScope { segment_id })?;
|
||||
Ok(ScopeConfig {
|
||||
allow: snapshot.allow,
|
||||
deny: snapshot.deny,
|
||||
@@ -376,7 +376,7 @@ struct Form {
|
||||
/// switches, the source session is shown to the user, and the
|
||||
/// child pod is launched with `--session <id>` so it restores
|
||||
/// from `id` and appends to the same session log.
|
||||
resume_from: Option<SessionId>,
|
||||
resume_from: Option<SegmentId>,
|
||||
/// Scope snapshot recovered from the source session log. Set only for
|
||||
/// resume runs, and serialized into the overlay instead of cwd-default
|
||||
/// scope so resume does not silently broaden access.
|
||||
@@ -473,7 +473,7 @@ fn draw_form(f: &mut Frame<'_>, form: &Form) {
|
||||
|
||||
/// First 8 hex digits of a UUID — short enough to skim, long enough
|
||||
/// to disambiguate inside a 10-row picker.
|
||||
pub(crate) fn short_session(id: SessionId) -> String {
|
||||
pub(crate) fn short_session(id: SegmentId) -> String {
|
||||
let s = id.to_string();
|
||||
s.chars().take(8).collect()
|
||||
}
|
||||
@@ -584,7 +584,7 @@ mod tests {
|
||||
#[test]
|
||||
fn overlay_uses_resume_scope_snapshot() {
|
||||
let mut f = form("agent-r", false);
|
||||
f.resume_from = Some(session_store::new_session_id());
|
||||
f.resume_from = Some(session_store::new_segment_id());
|
||||
f.resume_scope = Some(ScopeConfig {
|
||||
allow: vec![manifest::ScopeRule {
|
||||
target: PathBuf::from("/work/example"),
|
||||
|
||||
@@ -1019,10 +1019,10 @@ fn render_compact(lines: &mut Vec<Line<'static>>, evt: &CompactEvent, width: u16
|
||||
)
|
||||
}
|
||||
CompactEvent::Done {
|
||||
new_session_id,
|
||||
new_segment_id,
|
||||
elapsed_secs,
|
||||
} => {
|
||||
let short = new_session_id
|
||||
let short = new_segment_id
|
||||
.to_string()
|
||||
.chars()
|
||||
.take(8)
|
||||
|
||||
Reference in New Issue
Block a user