Update runtimed to fix compatibility issue with the Ark kernel (#40889)

Lionel Henry and Conrad Irwin created

Closes #40888

This updates runtimed to the latest version, which handles the
"starting" variant of `execution_state`. It actually handles a bunch of
other variants that are not documented in the protocol (see
https://jupyter-client.readthedocs.io/en/stable/messaging.html#kernel-status),
like "starting", "terminating", etc. I added implementations for these
variants as well.

Release Notes:

- Fixed issue that prevented the Ark kernel from working in Zed
(#40888).

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>

Change summary

Cargo.lock                                       | 44 +++++---
Cargo.toml                                       | 10 +-
crates/repl/src/kernels/mod.rs                   |  7 +
crates/repl/src/outputs.rs                       |  7 +
crates/repl/src/session.rs                       |  7 +
crates/zed/src/zed/quick_action_bar/repl_menu.rs | 88 +++++++++++------
6 files changed, 109 insertions(+), 54 deletions(-)

Detailed changes

Cargo.lock 🔗

@@ -1461,6 +1461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "879b6c89592deb404ba4dc0ae6b58ffd1795c78991cbb5b8bc441c48a070440d"
 dependencies = [
  "aws-lc-sys",
+ "untrusted 0.7.1",
  "zeroize",
 ]
 
@@ -8658,23 +8659,25 @@ dependencies = [
 
 [[package]]
 name = "jupyter-protocol"
-version = "0.6.0"
-source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9c047f6b5e551563af2ddb13dafed833f0ec5a5b0f9621d5ad740a9ff1e1095"
 dependencies = [
- "anyhow",
  "async-trait",
  "bytes 1.10.1",
  "chrono",
  "futures 0.3.31",
  "serde",
  "serde_json",
+ "thiserror 2.0.17",
  "uuid",
 ]
 
 [[package]]
 name = "jupyter-websocket-client"
-version = "0.9.0"
-source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4197fa926a6b0bddfed7377d9fed3d00a0dec44a1501e020097bd26604699cae"
 dependencies = [
  "anyhow",
  "async-trait",
@@ -8683,6 +8686,7 @@ dependencies = [
  "jupyter-protocol",
  "serde",
  "serde_json",
+ "tokio",
  "url",
  "uuid",
 ]
@@ -10233,8 +10237,9 @@ dependencies = [
 
 [[package]]
 name = "nbformat"
-version = "0.10.0"
-source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
+version = "0.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "89c7229d604d847227002715e1235cd84e81919285d904ccb290a42ecc409348"
 dependencies = [
  "anyhow",
  "chrono",
@@ -14274,7 +14279,7 @@ dependencies = [
  "cfg-if",
  "getrandom 0.2.16",
  "libc",
- "untrusted",
+ "untrusted 0.9.0",
  "windows-sys 0.52.0",
 ]
 
@@ -14455,25 +14460,26 @@ dependencies = [
 
 [[package]]
 name = "runtimelib"
-version = "0.25.0"
-source = "git+https://github.com/ConradIrwin/runtimed?rev=7130c804216b6914355d15d0b91ea91f6babd734#7130c804216b6914355d15d0b91ea91f6babd734"
+version = "0.30.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "481b48894073a0096f28cbe9860af01fc1b861e55b3bc96afafc645ee3de62dc"
 dependencies = [
- "anyhow",
  "async-dispatcher",
  "async-std",
+ "aws-lc-rs",
  "base64 0.22.1",
  "bytes 1.10.1",
  "chrono",
  "data-encoding",
- "dirs 5.0.1",
+ "dirs 6.0.0",
  "futures 0.3.31",
  "glob",
  "jupyter-protocol",
- "ring",
  "serde",
  "serde_json",
  "shellexpand 3.1.1",
  "smol",
+ "thiserror 2.0.17",
  "uuid",
  "zeromq",
 ]
@@ -14741,7 +14747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
 dependencies = [
  "ring",
- "untrusted",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -14753,7 +14759,7 @@ dependencies = [
  "aws-lc-rs",
  "ring",
  "rustls-pki-types",
- "untrusted",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -14983,7 +14989,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
 dependencies = [
  "ring",
- "untrusted",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -18576,6 +18582,12 @@ version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
 
+[[package]]
+name = "untrusted"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
+
 [[package]]
 name = "untrusted"
 version = "0.9.0"

Cargo.toml 🔗

@@ -534,8 +534,8 @@ itertools = "0.14.0"
 json_dotpath = "1.1"
 jsonschema = "0.30.0"
 jsonwebtoken = "9.3"
-jupyter-protocol = { git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
-jupyter-websocket-client = {  git = "https://github.com/ConradIrwin/runtimed" ,rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
+jupyter-protocol = "0.10.0"
+jupyter-websocket-client = "0.15.0"
 libc = "0.2"
 libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
 linkify = "0.10.0"
@@ -548,7 +548,7 @@ minidumper = "0.8"
 moka = { version = "0.12.10", features = ["sync"] }
 naga = { version = "25.0", features = ["wgsl-in"] }
 nanoid = "0.4"
-nbformat = {  git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734" }
+nbformat = "0.15.0"
 nix = "0.29"
 num-format = "0.4.4"
 num-traits = "0.2"
@@ -619,8 +619,8 @@ reqwest = { git = "https://github.com/zed-industries/reqwest.git", rev = "c15662
     "stream",
 ], package = "zed-reqwest", version = "0.12.15-zed" }
 rsa = "0.9.6"
-runtimelib = {  git = "https://github.com/ConradIrwin/runtimed", rev = "7130c804216b6914355d15d0b91ea91f6babd734", default-features = false, features = [
-    "async-dispatcher-runtime",
+runtimelib = { version = "0.30.0", default-features = false, features = [
+    "async-dispatcher-runtime", "aws-lc-rs"
 ] }
 rust-embed = { version = "8.4", features = ["include-exclude"] }
 rustc-hash = "2.1.0"

crates/repl/src/kernels/mod.rs 🔗

@@ -213,6 +213,13 @@ impl From<&Kernel> for KernelStatus {
             Kernel::RunningKernel(kernel) => match kernel.execution_state() {
                 ExecutionState::Idle => KernelStatus::Idle,
                 ExecutionState::Busy => KernelStatus::Busy,
+                ExecutionState::Unknown => KernelStatus::Error,
+                ExecutionState::Starting => KernelStatus::Starting,
+                ExecutionState::Restarting => KernelStatus::Restarting,
+                ExecutionState::Terminating => KernelStatus::ShuttingDown,
+                ExecutionState::AutoRestarting => KernelStatus::Restarting,
+                ExecutionState::Dead => KernelStatus::Error,
+                ExecutionState::Other(_) => KernelStatus::Error,
             },
             Kernel::StartingKernel(_) => KernelStatus::Starting,
             Kernel::ErroredLaunch(_) => KernelStatus::Error,

crates/repl/src/outputs.rs 🔗

@@ -476,6 +476,13 @@ impl ExecutionView {
                         self.status = ExecutionStatus::Executing;
                     }
                     ExecutionState::Idle => self.status = ExecutionStatus::Finished,
+                    ExecutionState::Unknown => self.status = ExecutionStatus::Unknown,
+                    ExecutionState::Starting => self.status = ExecutionStatus::ConnectingToKernel,
+                    ExecutionState::Restarting => self.status = ExecutionStatus::Restarting,
+                    ExecutionState::Terminating => self.status = ExecutionStatus::ShuttingDown,
+                    ExecutionState::AutoRestarting => self.status = ExecutionStatus::Restarting,
+                    ExecutionState::Dead => self.status = ExecutionStatus::Shutdown,
+                    ExecutionState::Other(_) => self.status = ExecutionStatus::Unknown,
                 }
                 cx.notify();
                 return;

crates/repl/src/session.rs 🔗

@@ -673,6 +673,13 @@ impl Render for Session {
                 Kernel::RunningKernel(kernel) => match kernel.execution_state() {
                     ExecutionState::Idle => Color::Success,
                     ExecutionState::Busy => Color::Modified,
+                    ExecutionState::Unknown => Color::Modified,
+                    ExecutionState::Starting => Color::Modified,
+                    ExecutionState::Restarting => Color::Modified,
+                    ExecutionState::Terminating => Color::Disabled,
+                    ExecutionState::AutoRestarting => Color::Modified,
+                    ExecutionState::Dead => Color::Disabled,
+                    ExecutionState::Other(_) => Color::Modified,
                 },
                 Kernel::StartingKernel(_) => Color::Modified,
                 Kernel::ErroredLaunch(_) => Color::Error,

crates/zed/src/zed/quick_action_bar/repl_menu.rs 🔗

@@ -388,16 +388,55 @@ fn session_state(session: Entity<Session>, cx: &mut App) -> ReplMenuState {
         }
     };
 
-    match &session.kernel {
-        Kernel::Restarting => ReplMenuState {
-            tooltip: format!("Restarting {}", kernel_name).into(),
-            icon_is_animating: true,
-            popover_disabled: true,
+    let transitional =
+        |tooltip: SharedString, animating: bool, popover_disabled: bool| ReplMenuState {
+            tooltip,
+            icon_is_animating: animating,
+            popover_disabled,
             icon_color: Color::Muted,
             indicator: Some(Indicator::dot().color(Color::Muted)),
             status: session.kernel.status(),
             ..fill_fields()
-        },
+        };
+
+    let starting = || transitional(format!("{} is starting", kernel_name).into(), true, true);
+    let restarting = || transitional(format!("Restarting {}", kernel_name).into(), true, true);
+    let shutting_down = || {
+        transitional(
+            format!("{} is shutting down", kernel_name).into(),
+            false,
+            true,
+        )
+    };
+    let auto_restarting = || {
+        transitional(
+            format!("Auto-restarting {}", kernel_name).into(),
+            true,
+            true,
+        )
+    };
+    let unknown = || transitional(format!("{} state unknown", kernel_name).into(), false, true);
+    let other = |state: &str| {
+        transitional(
+            format!("{} state: {}", kernel_name, state).into(),
+            false,
+            true,
+        )
+    };
+
+    let shutdown = || ReplMenuState {
+        tooltip: "Nothing running".into(),
+        icon: IconName::ReplNeutral,
+        icon_color: Color::Default,
+        icon_is_animating: false,
+        popover_disabled: false,
+        indicator: None,
+        status: KernelStatus::Shutdown,
+        ..fill_fields()
+    };
+
+    match &session.kernel {
+        Kernel::Restarting => restarting(),
         Kernel::RunningKernel(kernel) => match &kernel.execution_state() {
             ExecutionState::Idle => ReplMenuState {
                 tooltip: format!("Run code on {} ({})", kernel_name, kernel_language).into(),
@@ -413,16 +452,15 @@ fn session_state(session: Entity<Session>, cx: &mut App) -> ReplMenuState {
                 status: session.kernel.status(),
                 ..fill_fields()
             },
+            ExecutionState::Unknown => unknown(),
+            ExecutionState::Starting => starting(),
+            ExecutionState::Restarting => restarting(),
+            ExecutionState::Terminating => shutting_down(),
+            ExecutionState::AutoRestarting => auto_restarting(),
+            ExecutionState::Dead => shutdown(),
+            ExecutionState::Other(state) => other(state),
         },
-        Kernel::StartingKernel(_) => ReplMenuState {
-            tooltip: format!("{} is starting", kernel_name).into(),
-            icon_is_animating: true,
-            popover_disabled: true,
-            icon_color: Color::Muted,
-            indicator: Some(Indicator::dot().color(Color::Muted)),
-            status: session.kernel.status(),
-            ..fill_fields()
-        },
+        Kernel::StartingKernel(_) => starting(),
         Kernel::ErroredLaunch(e) => ReplMenuState {
             tooltip: format!("Error with kernel {}: {}", kernel_name, e).into(),
             popover_disabled: false,
@@ -430,23 +468,7 @@ fn session_state(session: Entity<Session>, cx: &mut App) -> ReplMenuState {
             status: session.kernel.status(),
             ..fill_fields()
         },
-        Kernel::ShuttingDown => ReplMenuState {
-            tooltip: format!("{} is shutting down", kernel_name).into(),
-            popover_disabled: true,
-            icon_color: Color::Muted,
-            indicator: Some(Indicator::dot().color(Color::Muted)),
-            status: session.kernel.status(),
-            ..fill_fields()
-        },
-        Kernel::Shutdown => ReplMenuState {
-            tooltip: "Nothing running".into(),
-            icon: IconName::ReplNeutral,
-            icon_color: Color::Default,
-            icon_is_animating: false,
-            popover_disabled: false,
-            indicator: None,
-            status: KernelStatus::Shutdown,
-            ..fill_fields()
-        },
+        Kernel::ShuttingDown => shutting_down(),
+        Kernel::Shutdown => shutdown(),
     }
 }