diff --git a/.github/workflows/release_configurations.json b/.github/workflows/release_configurations.json
index 3467fdf75b7..d892ef70926 100644
--- a/.github/workflows/release_configurations.json
+++ b/.github/workflows/release_configurations.json
@@ -7,7 +7,7 @@
"is_prerelease": false,
"is_autopush": false,
"release_base_name": "Zaplex",
- "release_body_text": "Zaplex 1.1.1 — signed and notarized macOS distribution",
+ "release_body_text": "Zaplex 1.2.0 — signed and notarized macOS distribution",
"changelog_slack_channel": "",
"gcs_cache_control_value": "",
"web_gcs_bucket_prefix": ""
diff --git a/.github/workflows/test-dmg.yml b/.github/workflows/test-dmg.yml
index 2ab138f6a19..4b36e30bba4 100644
--- a/.github/workflows/test-dmg.yml
+++ b/.github/workflows/test-dmg.yml
@@ -28,7 +28,7 @@ on:
dmg_tag:
description: "GIT_RELEASE_TAG (bestimmt den remote-server-Pfad auf dem Ziel-Host)"
type: string
- default: v1.1.1
+ default: v1.2.0
fast:
description: "Debug-Profil für Mac-App und Linux-Daemon. Nur für schnelle Entwicklerprüfung; für Abnahme-DMGs ausgeschaltet lassen."
type: boolean
diff --git a/.github/workflows/zap_release.yml b/.github/workflows/zap_release.yml
index d057801ca62..75356284b85 100644
--- a/.github/workflows/zap_release.yml
+++ b/.github/workflows/zap_release.yml
@@ -31,7 +31,7 @@ on:
release_tag:
description: "Release tag; must match VERSION"
type: string
- default: v1.1.1
+ default: v1.2.0
required: true
# Build and metadata jobs only need repository read access. The publisher job
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 16f9ff9ebd4..495beabe293 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,7 +2,9 @@
This document records key changes: the Zap/Warp release history inherited before the zaplex fork (translated from the original Chinese), followed by zaplex's own work on top of it. Only functional commits are listed; internal dev/stable rolling tags are omitted.
-## [1.1.1] — 2026-09-23
+## [1.2.0] — 2026-10-06
+
+- Tabs und Panes haben ein gemeinsames Startmenü: „+“ und alle vier Split-Richtungen zeigen Terminal, „Neuer Agent…“, die Favoriten und neu „Weitere Hosts“ mit allen übrigen registrierten Hosts. Aus einem Split heraus startet jeder Eintrag im neuen Pane, auch der Agent; Konto, Startabsicht und Prompt hängen an genau diesem Pane. Tab-spezifische Einträge (Tab-Konfigurationen, Docker-Sandbox, Worktree-Konfiguration, geschlossene Session) bleiben im „+“-Menü.
- Die Integrationssuite (#472) initialisiert englische Texte vor dem Start und bedient beim Teilen eines Panes den echten Hostpicker. SSH-Prüfungen nutzen eigene kurzlebige Konten auf einem lokalen CI-SSH-Server; Passwortanmeldung, Shell-Bootstrap und ProxyCommand bleiben Teil der Prüfung.
diff --git a/Cargo.lock b/Cargo.lock
index 15568d43e00..12b1621820b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -13791,7 +13791,7 @@ dependencies = [
[[package]]
name = "warp"
-version = "1.1.1"
+version = "1.2.0"
dependencies = [
"addr",
"aho-corasick",
diff --git a/README.md b/README.md
index 33330e7cf77..14e0d64d51b 100644
--- a/README.md
+++ b/README.md
@@ -75,7 +75,7 @@ zaplex is a fork of [Zap](https://github.com/zerx-lab/zap) — the open-source,
## Status & roadmap
-Zaplex 1.1.1 is the version prepared by this source tree. The table reflects
+Zaplex 1.2.0 is the version prepared by this source tree. The table reflects
the integrated source state; supported release artifacts are built, signed and
published by the release workflow:
@@ -101,7 +101,7 @@ Every designed item has a dated design doc in [`docs/superpowers/`](docs/superpo
## Install
-Once published, download Zaplex 1.1.1 from
+Once published, download Zaplex 1.2.0 from
[Releases](https://github.com/byte5ai/zaplex/releases). The macOS DMG is built
in GitHub Actions, signed with Developer ID, notarized by Apple, and shipped
together with its matching Linux host daemon. Nothing needs to be installed
diff --git a/VERSION b/VERSION
index 524cb55242b..26aaba0e866 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.1
+1.2.0
diff --git a/app/Cargo.toml b/app/Cargo.toml
index 80e448ef3c0..aa890f1d2d1 100644
--- a/app/Cargo.toml
+++ b/app/Cargo.toml
@@ -5,7 +5,7 @@ description = "The terminal cockpit for AI coding agents on remote machines"
edition = "2021"
autobins = false
name = "warp"
-version = "1.1.1"
+version = "1.2.0"
publish.workspace = true
license.workspace = true
diff --git a/app/DockTilePlugin/Info.plist b/app/DockTilePlugin/Info.plist
index f4cb780e793..87b7407b3b7 100644
--- a/app/DockTilePlugin/Info.plist
+++ b/app/DockTilePlugin/Info.plist
@@ -11,9 +11,9 @@
CFBundlePackageTypeBNDLCFBundleShortVersionString
- 1.1.1
+ 1.2.0CFBundleVersion
- 1.1.1
+ 1.2.0NSPrincipalClassZapDockTilePluginCFBundleInfoDictionaryVersion
diff --git a/app/assets/resources/mac/CLI-Info.plist b/app/assets/resources/mac/CLI-Info.plist
index 9468d18623d..b41382af196 100644
--- a/app/assets/resources/mac/CLI-Info.plist
+++ b/app/assets/resources/mac/CLI-Info.plist
@@ -16,9 +16,9 @@
CFBundlePackageTypeAPPLCFBundleShortVersionString
- 1.1.1
+ 1.2.0CFBundleVersion
- 1.1.1
+ 1.2.0LSBackgroundOnly
diff --git a/app/i18n/de/warp.ftl b/app/i18n/de/warp.ftl
index 7b6d3bb3a93..bf388c69938 100644
--- a/app/i18n/de/warp.ftl
+++ b/app/i18n/de/warp.ftl
@@ -4076,6 +4076,8 @@ workspace-remote-pty-already-open = Dieses Remote-PTY ist bereits geöffnet, abe
workspace-remote-fallback-split-target-changed = Der Remote-Fallback wurde abgebrochen, weil sich das ursprüngliche Split-Ziel geändert hat.
workspace-split-target-changed = Der Split wurde nicht geöffnet, weil sich seine Pane verschoben hat oder geschlossen wurde.
workspace-split-host-already-connecting = { $host } wird bereits verbunden. Öffne den Split erneut, sobald die Verbindung steht.
+workspace-split-agent-single-launch = Ein Split nimmt genau einen Agenten auf. Wähle ein einzelnes Konto.
+workspace-launch-more-hosts = Weitere Hosts
workspace-remote-agent-route-validation-unavailable = Der Daemon kann diese Agent-zu-PTY-Route nicht validieren.
workspace-remote-daemon-connection-unavailable = Die Daemon-Verbindung ist nicht verfügbar; aktualisiere die Agent-Sessions.
workspace-remote-pty-agent-changed = Der Vordergrund-Agent dieses PTYs hat sich geändert. Aktualisiere die Agent-Sessions, bevor du es erneut anhängst.
diff --git a/app/i18n/en/warp.ftl b/app/i18n/en/warp.ftl
index 207cfd70bbd..52b0a0880e6 100644
--- a/app/i18n/en/warp.ftl
+++ b/app/i18n/en/warp.ftl
@@ -4421,6 +4421,8 @@ workspace-remote-pty-already-open = This remote PTY is already open, but its exi
workspace-remote-fallback-split-target-changed = Remote fallback was cancelled because its original split target changed.
workspace-split-target-changed = The split was not opened because its pane moved or closed.
workspace-split-host-already-connecting = { $host } is already connecting. Open the split again once it is connected.
+workspace-split-agent-single-launch = A split holds exactly one agent. Choose a single account.
+workspace-launch-more-hosts = More hosts
workspace-remote-agent-route-validation-unavailable = The daemon cannot validate this agent-to-PTY route.
workspace-remote-daemon-connection-unavailable = The daemon connection is unavailable; refresh Agent Sessions.
workspace-remote-pty-agent-changed = This PTY's foreground agent changed. Refresh Agent Sessions before attaching again.
diff --git a/app/src/bin/zaplex.rs b/app/src/bin/zaplex.rs
index c16f29619dc..69d84c93906 100644
--- a/app/src/bin/zaplex.rs
+++ b/app/src/bin/zaplex.rs
@@ -81,9 +81,9 @@ embed_plist::embed_info_plist_bytes!(r#"
CFBundlePackageTypeAPPLCFBundleShortVersionString
- 1.1.1
+ 1.2.0CFBundleVersion
- 1.1.1
+ 1.2.0LSApplicationCategoryTypepublic.app-category.developer-toolsNSHighResolutionCapable
diff --git a/app/src/integration_testing/native_workspace.rs b/app/src/integration_testing/native_workspace.rs
index 2300f47618a..0421f08e6a2 100644
--- a/app/src/integration_testing/native_workspace.rs
+++ b/app/src/integration_testing/native_workspace.rs
@@ -264,13 +264,7 @@ pub fn split_local_right() -> TestStep {
TestStep::new("Split the real pane through its overflow menu and choose local")
.with_click_on_saved_position_fn(|app, window_id| overflow_id(app, window_id, 0))
.with_click_on_saved_position_fn(|_, _| crate::t!("keybinding-desc-pane-group-split-right"))
- .with_click_on_saved_position_fn(|_, _| {
- format!(
- "{} · {}",
- crate::t!("cockpit-spawn-card-host-local"),
- crate::t!("common-current")
- )
- })
+ .with_click_on_saved_position_fn(|_, _| crate::t!("workspace-new-session-terminal"))
}
#[derive(Clone, Debug, PartialEq, Eq)]
diff --git a/app/src/integration_testing/pane_group/step.rs b/app/src/integration_testing/pane_group/step.rs
index 32a7621414a..5b81d1dbf79 100644
--- a/app/src/integration_testing/pane_group/step.rs
+++ b/app/src/integration_testing/pane_group/step.rs
@@ -54,19 +54,13 @@ pub fn move_pane_by_indices(
})
}
-/// Completes the host picker opened by a split shortcut using the real local row.
+/// Completes the launch menu opened by a split shortcut with its local Terminal entry.
pub trait LocalSplitTarget {
fn with_local_split_target(self) -> Self;
}
impl LocalSplitTarget for TestStep {
fn with_local_split_target(self) -> Self {
- self.with_click_on_saved_position_fn(|_, _| {
- format!(
- "{} · {}",
- crate::t!("cockpit-spawn-card-host-local"),
- crate::t!("common-current")
- )
- })
+ self.with_click_on_saved_position_fn(|_, _| crate::t!("workspace-new-session-terminal"))
}
}
diff --git a/app/src/pane_group/mod.rs b/app/src/pane_group/mod.rs
index 3bacddf83aa..dc5806c2c4a 100644
--- a/app/src/pane_group/mod.rs
+++ b/app/src/pane_group/mod.rs
@@ -4743,13 +4743,13 @@ impl PaneGroup {
PaneEvent::CloseAndFocus { pane_to_focus } => {
self.close_pane_and_focus(pane_id, *pane_to_focus, ctx);
}
- // Pane-splitting events always create a new terminal pane, regardless of the original
- // pane's type. This makes it easy to get a terminal session next to a non-terminal
- // pane like a notebook. Once it's possible to open the same notebook more than once,
- // we may revisit this so that splitting from a terminal pane starts a new session, but
- // splitting from a notebook pane reopens the notebook side-by-side.
+ // Every split direction opens the workspace launch menu for the captured target; the
+ // chosen entry (local terminal, host, or agent) decides what the new pane runs.
PaneEvent::SplitLeft(chosen_shell) => {
- self.insert_terminal_pane(Direction::Left, pane_id, chosen_shell.clone(), ctx);
+ ctx.emit(Event::SplitLaunchRequested {
+ target: self.capture_split_target(pane_id, Direction::Left),
+ chosen_shell: chosen_shell.clone(),
+ });
}
PaneEvent::SplitRight(chosen_shell) => {
ctx.emit(Event::SplitLaunchRequested {
@@ -4758,7 +4758,10 @@ impl PaneGroup {
});
}
PaneEvent::SplitUp(chosen_shell) => {
- self.insert_terminal_pane(Direction::Up, pane_id, chosen_shell.clone(), ctx);
+ ctx.emit(Event::SplitLaunchRequested {
+ target: self.capture_split_target(pane_id, Direction::Up),
+ chosen_shell: chosen_shell.clone(),
+ });
}
PaneEvent::SplitDown(chosen_shell) => {
ctx.emit(Event::SplitLaunchRequested {
@@ -7221,18 +7224,11 @@ impl TypedActionView for PaneGroup {
None
}
};
- match direction {
- Direction::Right | Direction::Down => {
- let pane_id = self.focused_pane_id(ctx);
- ctx.emit(Event::SplitLaunchRequested {
- target: self.capture_split_target(pane_id, *direction),
- chosen_shell,
- });
- }
- Direction::Left | Direction::Up => {
- self.add_terminal_pane(*direction, chosen_shell, ctx);
- }
- }
+ let pane_id = self.focused_pane_id(ctx);
+ ctx.emit(Event::SplitLaunchRequested {
+ target: self.capture_split_target(pane_id, *direction),
+ chosen_shell,
+ });
}
Remove(view_id) => self.close_pane_with_confirmation(*view_id, ctx),
RemoveActive => self.close_active_pane_with_confirmation(ctx),
diff --git a/app/src/workspace/action.rs b/app/src/workspace/action.rs
index ab33da92961..6651de78205 100644
--- a/app/src/workspace/action.rs
+++ b/app/src/workspace/action.rs
@@ -159,6 +159,21 @@ pub enum WorkspaceAction {
OpenSshTerminalByNode {
node_id: String,
},
+ /// Launch-menu choice from a pane split: open a local terminal at the split
+ /// target captured when the split launch menu opened.
+ SplitLaunchLocal,
+ /// Launch-menu choice from a pane split: open a registered host at the
+ /// captured split target, resolving the connection by its `node_id`.
+ SplitLaunchHost {
+ node_id: String,
+ },
+ /// Launch-menu choice from a pane split: open the Spawn-Karte whose single
+ /// launch lands at the captured split target instead of a new tab.
+ /// `registry_node_id`/`host` pre-scope the card like [`Self::OpenSpawnCard`].
+ SplitLaunchSpawnCard {
+ registry_node_id: Option,
+ host: Option,
+ },
/// Open an SFTP file-manager pane for a registered SSH host, resolving the
/// connection by its stable registry node id. Dispatched by the visible
/// "Files" action on a Conductor host node.
@@ -1057,6 +1072,8 @@ impl WorkspaceAction {
| AddTerminalTab { .. }
| OpenSshTerminal { .. }
| OpenSshTerminalByNode { .. }
+ | SplitLaunchLocal
+ | SplitLaunchHost { .. }
| OpenSftpPaneByNode { .. }
| OpenLocalFileManager { .. }
| ToggleSshManager
@@ -1262,6 +1279,7 @@ impl WorkspaceAction {
| CreateReviewPr { .. }
| LaunchAgent { .. }
| OpenSpawnCard { .. }
+ | SplitLaunchSpawnCard { .. }
| RunCockpitPaletteTarget { .. }
| OpenFileInEditor { .. }
| OpenReadOnlyTextInEditor { .. }
diff --git a/app/src/workspace/view.rs b/app/src/workspace/view.rs
index 216066a8825..ad8c80c2f5d 100644
--- a/app/src/workspace/view.rs
+++ b/app/src/workspace/view.rs
@@ -62,8 +62,8 @@ use crate::app_state::{
bind_daemon_pty_claim_owner, claim_daemon_pty, daemon_pty_claim,
release_daemon_pty_claim_for_connection, release_daemon_pty_claim_for_terminal_view,
release_daemon_pty_claim_reservation, DaemonPtyClaimOutcome, DaemonPtyClaimOwner,
- DaemonPtyIdentity, FileManagerPaneMode, LeafContents, LeafSnapshot, LeftPanelDisplayedTab,
- LeftPanelSnapshot, NotebookPaneSnapshot, PaneNodeSnapshot, PaneUuid, PersistedDaemonRuntime,
+ DaemonPtyIdentity, LeafContents, LeafSnapshot, LeftPanelDisplayedTab, LeftPanelSnapshot,
+ NotebookPaneSnapshot, PaneNodeSnapshot, PaneUuid, PersistedDaemonRuntime,
RemoteTerminalIdentity, RemoteTerminalTransport, RightPanelSnapshot, SettingsPaneSnapshot,
TabSnapshot, WindowSnapshot, WorkflowPaneSnapshot,
};
@@ -851,6 +851,13 @@ struct PendingSplitLaunch {
inherited_remote_cwd: Option,
}
+/// A routed agent launch that opened its terminal: the token the Spawn-Karte
+/// records, and the terminal the agent runs in when it could be resolved.
+struct LaunchedAgent {
+ token: String,
+ terminal: Option>,
+}
+
#[cfg(unix)]
#[derive(Clone, Copy)]
struct PendingDaemonSurface {
@@ -2081,9 +2088,12 @@ pub struct Workspace {
// Same applies to "show_new_session_dropdown_menu"
new_session_dropdown_menu: ViewHandle