4bd4aa4a36
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
109 lines
3.0 KiB
Rust
109 lines
3.0 KiB
Rust
use std::collections::HashMap;
|
|
use serde::{Deserialize, Serialize};
|
|
use crate::ids::{GroupId, SurfaceId, WorkspaceId};
|
|
use crate::layout::LayoutNode;
|
|
use crate::status::SurfaceState;
|
|
|
|
/// Everything needed to (re)create a panel's process.
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct SurfaceSpec {
|
|
pub command: String,
|
|
#[serde(default)]
|
|
pub args: Vec<String>,
|
|
pub cwd: String,
|
|
#[serde(default)]
|
|
pub agent_label: Option<String>,
|
|
pub cols: u16,
|
|
pub rows: u16,
|
|
#[serde(default)]
|
|
pub autostart: bool,
|
|
}
|
|
|
|
/// A colored, ordered collection of workspaces.
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct Group {
|
|
pub id: GroupId,
|
|
pub name: String,
|
|
pub color: String,
|
|
pub order: u32,
|
|
}
|
|
|
|
/// Persisted workspace: structure only (no live process state).
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct Workspace {
|
|
pub id: WorkspaceId,
|
|
pub path: String,
|
|
pub name: String,
|
|
#[serde(default)]
|
|
pub group_id: Option<GroupId>,
|
|
pub order: u32,
|
|
#[serde(default)]
|
|
pub unread: bool,
|
|
/// None = empty workspace (no panels yet).
|
|
#[serde(default)]
|
|
pub layout: Option<LayoutNode>,
|
|
pub surfaces: HashMap<SurfaceId, SurfaceSpec>,
|
|
}
|
|
|
|
/// Per-surface view in `status` — spec plus live lifecycle flag.
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct SurfaceView {
|
|
pub spec: SurfaceSpec,
|
|
/// true = has a live actor/PTY; false = stopped (in tree, no process).
|
|
pub running: bool,
|
|
/// Ephemeral agent-activity status (meaningful while running).
|
|
#[serde(default)]
|
|
pub state: SurfaceState,
|
|
}
|
|
|
|
/// Workspace view in `status` / `workspace_changed`: structure + per-surface state.
|
|
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
|
pub struct WorkspaceView {
|
|
pub id: WorkspaceId,
|
|
pub path: String,
|
|
pub name: String,
|
|
pub group_id: Option<GroupId>,
|
|
pub order: u32,
|
|
pub unread: bool,
|
|
pub layout: Option<LayoutNode>,
|
|
pub surfaces: HashMap<SurfaceId, SurfaceView>,
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn surface_spec_round_trips() {
|
|
let s = SurfaceSpec {
|
|
command: "claude".into(),
|
|
args: vec![],
|
|
cwd: "/tmp".into(),
|
|
agent_label: Some("claude".into()),
|
|
cols: 80,
|
|
rows: 24,
|
|
autostart: false,
|
|
};
|
|
let j = serde_json::to_string(&s).unwrap();
|
|
let back: SurfaceSpec = serde_json::from_str(&j).unwrap();
|
|
assert_eq!(back, s);
|
|
}
|
|
|
|
#[test]
|
|
fn workspace_round_trips_with_empty_layout() {
|
|
let w = Workspace {
|
|
id: WorkspaceId("w_1".into()),
|
|
path: "/tmp/p".into(),
|
|
name: "p".into(),
|
|
group_id: None,
|
|
order: 0,
|
|
unread: false,
|
|
layout: None,
|
|
surfaces: HashMap::new(),
|
|
};
|
|
let j = serde_json::to_string(&w).unwrap();
|
|
let back: Workspace = serde_json::from_str(&j).unwrap();
|
|
assert_eq!(back, w);
|
|
}
|
|
}
|