feat(proto): SurfaceSpec, Group, Workspace, status view types
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,9 @@ pub mod codec;
|
||||
pub mod ids;
|
||||
pub mod layout;
|
||||
pub mod message;
|
||||
pub mod workspace;
|
||||
|
||||
pub use ids::{GroupId, SurfaceId, WorkspaceId};
|
||||
pub use layout::{LayoutNode, Orient};
|
||||
pub use message::{Cmd, Envelope, ErrorBody, Evt};
|
||||
pub use workspace::{Group, SurfaceSpec, SurfaceView, Workspace, WorkspaceView};
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
use std::collections::HashMap;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use crate::ids::{GroupId, SurfaceId, WorkspaceId};
|
||||
use crate::layout::LayoutNode;
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
/// 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user