diff options
| author | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-09 04:40:50 +0300 |
|---|---|---|
| committer | Ogulcan Celik <ogulcancelik@gmail.com> | 2026-04-09 04:42:35 +0300 |
| commit | bb2c579df206e51d43833544d114f321423c997c (patch) | |
| tree | a26c6702e048f31429ebaa260ee40c3c2b111d3e | |
| parent | 5460a9601ea8dd3d05e64e97040c71c6be29172b (diff) | |
feat(cli): support labels when creating tabs and workspaces
| -rw-r--r-- | SKILL.md | 18 | ||||
| -rw-r--r-- | SOCKET_API.md | 10 | ||||
| -rw-r--r-- | src/api/schema.rs | 5 | ||||
| -rw-r--r-- | src/app/mod.rs | 28 | ||||
| -rw-r--r-- | src/cli.rs | 27 |
5 files changed, 78 insertions, 10 deletions
@@ -71,6 +71,14 @@ create a new tab: herdr tab create --workspace 1 ``` +without `--label`, the new tab keeps the default numbered tab name. + +create and name it in one step: + +```bash +herdr tab create --workspace 1 --label "logs" +``` + rename it: ```bash @@ -178,6 +186,14 @@ create a new workspace: herdr workspace create --cwd /path/to/project ``` +without `--label`, the new workspace keeps the default cwd-based name. + +create and name one in one step: + +```bash +herdr workspace create --cwd /path/to/project --label "api server" +``` + create one without focusing it: ```bash @@ -276,4 +292,6 @@ herdr pane read 1-1 --source recent --lines 100 - parse ids from `workspace create`, `tab create`, and `pane split` responses when you need new ids. for `pane split`, the new pane id is at `result.pane.pane_id`. - use `pane read` for current output that already exists. use `wait output` for future output you expect next. - `--no-focus` on split, tab create, and workspace create keeps your current terminal context focused. +- without `--label`, workspace create keeps cwd-based naming and tab create keeps numbered naming. +- `--label` on tab create and workspace create applies the custom name immediately. - if you are running inside herdr, the `HERDR_ENV` environment variable is set to `1`. diff --git a/SOCKET_API.md b/SOCKET_API.md index c73e0a7d..2739b96d 100644 --- a/SOCKET_API.md +++ b/SOCKET_API.md @@ -801,7 +801,7 @@ workspace commands: ```text herdr workspace list -herdr workspace create [--cwd PATH] [--no-focus] +herdr workspace create [--cwd PATH] [--label TEXT] [--no-focus] herdr workspace get <workspace_id> herdr workspace focus <workspace_id> herdr workspace rename <workspace_id> <label> @@ -812,7 +812,7 @@ tab commands: ```text herdr tab list [--workspace <workspace_id>] -herdr tab create [--workspace <workspace_id>] [--cwd PATH] [--no-focus] +herdr tab create [--workspace <workspace_id>] [--cwd PATH] [--label TEXT] [--no-focus] herdr tab get <tab_id> herdr tab focus <tab_id> herdr tab rename <tab_id> <label> @@ -842,7 +842,11 @@ herdr wait agent-status <pane_id> --status <idle|working|blocked|done|unknown> [ ### cli behavior notes - `workspace create` focuses by default; pass `--no-focus` to keep focus where it is +- `workspace create` without `--label` keeps the default cwd-based workspace naming +- `workspace create --label` applies the custom workspace name immediately - `tab create` focuses by default; pass `--no-focus` to keep focus where it is +- `tab create` without `--label` keeps the default numbered tab naming +- `tab create --label` applies the custom tab name immediately - `pane split` focuses the new pane by default; pass `--no-focus` to keep focus on the original pane - `pane read` prints **text**, not json - `pane read --source recent-unwrapped` returns recent terminal text with soft wraps joined back together @@ -859,7 +863,7 @@ herdr wait agent-status <pane_id> --status <idle|working|blocked|done|unknown> [ create a workspace, split a pane, run a server, and wait for readiness: ```bash -herdr workspace create --cwd /path/to/project +herdr workspace create --cwd /path/to/project --label "api server" herdr pane split 1-1 --direction right --no-focus herdr pane run 1-2 "npm run dev" herdr wait output 1-2 --match "ready" --timeout 30000 diff --git a/src/api/schema.rs b/src/api/schema.rs index 568a276b..42a9c259 100644 --- a/src/api/schema.rs +++ b/src/api/schema.rs @@ -93,6 +93,8 @@ pub struct WorkspaceCreateParams { pub cwd: Option<String>, #[serde(default)] pub focus: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub label: Option<String>, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] @@ -109,6 +111,8 @@ pub struct TabCreateParams { pub cwd: Option<String>, #[serde(default)] pub focus: bool, + #[serde(default, skip_serializing_if = "Option::is_none")] + pub label: Option<String>, } #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Default)] @@ -688,6 +692,7 @@ mod tests { method: Method::WorkspaceCreate(WorkspaceCreateParams { cwd: Some("/tmp".into()), focus: true, + label: Some("api".into()), }), }; diff --git a/src/app/mod.rs b/src/app/mod.rs index a39ed436..8d089a9d 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1069,6 +1069,11 @@ impl App { .unwrap_or_else(|| std::path::PathBuf::from("/")); match self.create_workspace_with_options(cwd, params.focus) { Ok(index) => { + if let Some(label) = params.label { + if let Some(workspace) = self.state.workspaces.get_mut(index) { + workspace.set_custom_name(label); + } + } let workspace = self.workspace_info(index); self.emit_event(crate::api::schema::EventEnvelope { event: crate::api::schema::EventKind::WorkspaceCreated, @@ -1280,7 +1285,13 @@ impl App { } } Method::TabCreate(params) => { - let ws_idx = if let Some(workspace_id) = params.workspace_id { + let crate::api::schema::TabCreateParams { + workspace_id, + cwd, + focus, + label, + } = params; + let ws_idx = if let Some(workspace_id) = workspace_id { let Some(ws_idx) = self.parse_workspace_id(&workspace_id) else { return serde_json::to_string(&ErrorResponse { id: request.id, @@ -1304,8 +1315,7 @@ impl App { }) .unwrap(); }; - let cwd = params - .cwd + let cwd = cwd .map(std::path::PathBuf::from) .or_else(|| { self.state.workspaces.get(ws_idx).and_then(|ws| { @@ -1333,7 +1343,17 @@ impl App { }); match result { Ok(tab_idx) => { - if params.focus { + if let Some(label) = label { + if let Some(tab) = self + .state + .workspaces + .get_mut(ws_idx) + .and_then(|ws| ws.tabs.get_mut(tab_idx)) + { + tab.set_custom_name(label); + } + } + if focus { self.state.switch_workspace(ws_idx); self.state.switch_tab(tab_idx); self.state.mode = Mode::Terminal; @@ -144,6 +144,7 @@ fn workspace_list(args: &[String]) -> std::io::Result<i32> { fn workspace_create(args: &[String]) -> std::io::Result<i32> { let mut cwd = None; let mut focus = true; + let mut label = None; let mut index = 0; while index < args.len() { @@ -156,6 +157,14 @@ fn workspace_create(args: &[String]) -> std::io::Result<i32> { cwd = Some(value.clone()); index += 2; } + "--label" => { + let Some(value) = args.get(index + 1) else { + eprintln!("missing value for --label"); + return Ok(2); + }; + label = Some(value.clone()); + index += 2; + } "--no-focus" => { focus = false; index += 1; @@ -169,7 +178,7 @@ fn workspace_create(args: &[String]) -> std::io::Result<i32> { print_response(&send_request(&Request { id: "cli:workspace:create".into(), - method: Method::WorkspaceCreate(WorkspaceCreateParams { cwd, focus }), + method: Method::WorkspaceCreate(WorkspaceCreateParams { cwd, focus, label }), })?) } @@ -273,6 +282,7 @@ fn tab_create(args: &[String]) -> std::io::Result<i32> { let mut workspace_id = None; let mut cwd = None; let mut focus = true; + let mut label = None; let mut index = 0; while index < args.len() { @@ -293,6 +303,14 @@ fn tab_create(args: &[String]) -> std::io::Result<i32> { cwd = Some(value.clone()); index += 2; } + "--label" => { + let Some(value) = args.get(index + 1) else { + eprintln!("missing value for --label"); + return Ok(2); + }; + label = Some(value.clone()); + index += 2; + } "--no-focus" => { focus = false; index += 1; @@ -310,6 +328,7 @@ fn tab_create(args: &[String]) -> std::io::Result<i32> { workspace_id, cwd, focus, + label, }), })?) } @@ -1055,7 +1074,7 @@ fn parse_u64_flag(flag: &str, value: &str) -> std::io::Result<u64> { fn print_workspace_help() { eprintln!("herdr workspace commands:"); eprintln!(" herdr workspace list"); - eprintln!(" herdr workspace create [--cwd PATH] [--no-focus]"); + eprintln!(" herdr workspace create [--cwd PATH] [--label TEXT] [--no-focus]"); eprintln!(" herdr workspace get <workspace_id>"); eprintln!(" herdr workspace focus <workspace_id>"); eprintln!(" herdr workspace rename <workspace_id> <label>"); @@ -1065,7 +1084,9 @@ fn print_workspace_help() { fn print_tab_help() { eprintln!("herdr tab commands:"); eprintln!(" herdr tab list [--workspace <workspace_id>]"); - eprintln!(" herdr tab create [--workspace <workspace_id>] [--cwd PATH] [--no-focus]"); + eprintln!( + " herdr tab create [--workspace <workspace_id>] [--cwd PATH] [--label TEXT] [--no-focus]" + ); eprintln!(" herdr tab get <tab_id>"); eprintln!(" herdr tab focus <tab_id>"); eprintln!(" herdr tab rename <tab_id> <label>"); |
