feat: index runtime sessions by pane
CI / rust (push) Successful in 4m19s

This commit is contained in:
2026-08-31 18:29:28 -07:00
parent abcf664ab8
commit 4ed7613b22
9 changed files with 679 additions and 205 deletions
+45 -5
View File
@@ -404,13 +404,27 @@ impl ShellModel {
///
/// Returns [`InvalidExternalOutputPane`] when `pane` is not a terminal.
pub fn with_external_output(pane: PaneId) -> Result<Self, InvalidExternalOutputPane> {
Self::with_external_outputs([pane])
}
/// Creates the comparison model with actor-driven output for each named
/// terminal while non-terminal surfaces retain deterministic updates.
///
/// # Errors
///
/// Returns [`InvalidExternalOutputPane`] if any pane is not a terminal.
pub fn with_external_outputs(
panes: impl IntoIterator<Item = PaneId>,
) -> Result<Self, InvalidExternalOutputPane> {
let mut model = Self::default();
let pane_state = &mut model.panes[pane.index()];
if pane_state.kind() != SurfaceKind::Terminal {
return Err(InvalidExternalOutputPane);
for pane in panes {
let pane_state = &mut model.panes[pane.index()];
if pane_state.kind() != SurfaceKind::Terminal {
return Err(InvalidExternalOutputPane);
}
pane_state.output_source = OutputSource::External;
pane_state.lines.clear();
}
pane_state.output_source = OutputSource::External;
pane_state.lines.clear();
Ok(model)
}
@@ -990,6 +1004,32 @@ mod tests {
assert_eq!(model.counters().external_snapshot_updates, 1);
}
#[test]
fn three_external_terminals_keep_independent_output_and_three_fixtures() {
let mut model = ShellModel::with_external_outputs([
PaneId::CodexRuntime,
PaneId::ClaudeUi,
PaneId::PiDocs,
])
.unwrap();
let tick = model.dispatch(ShellAction::SyntheticStreamTick);
assert_eq!(tick.terminal_lines_appended, 0);
assert_eq!(model.counters().surface_updates, 3);
model.dispatch(ShellAction::ReplaceExternalOutput {
pane: PaneId::ClaudeUi,
lines: vec!["claude shell".into()],
});
model.dispatch(ShellAction::ReplaceExternalOutput {
pane: PaneId::PiDocs,
lines: vec!["pi shell".into()],
});
assert_eq!(model.pane(PaneId::ClaudeUi).lines(), ["claude shell"]);
assert_eq!(model.pane(PaneId::PiDocs).lines(), ["pi shell"]);
assert!(model.pane(PaneId::CodexRuntime).lines().is_empty());
assert_eq!(model.counters().external_snapshot_updates, 2);
}
#[test]
fn external_output_rejects_nonterminals_and_deterministic_panes() {
assert!(ShellModel::with_external_output(PaneId::Architecture).is_err());