Skip to content

Add scriptable pane control via local UDS API and wp CLI#10255

Closed
Nikitzu wants to merge 4 commits intowarpdotdev:masterfrom
Nikitzu:add-local-api-and-wp-cli
Closed

Add scriptable pane control via local UDS API and wp CLI#10255
Nikitzu wants to merge 4 commits intowarpdotdev:masterfrom
Nikitzu:add-local-api-and-wp-cli

Conversation

@Nikitzu
Copy link
Copy Markdown

@Nikitzu Nikitzu commented May 6, 2026

Description

Adds a UDS-based local control plane plus a sibling wp CLI binary, giving Warp the same scripting affordance that iTerm2 ships through it2cli, kitty through kitty @, and wezterm through wezterm cli. External processes (build automations, dotfile managers, productivity tooling) can split panes, send text, list and close panes against the running Warp without going through the keyboard / event system.

Architecture

Mirrors iTermAPIServer's "background socket reads, main-thread mutations" pattern.

  • crates/warp_local_api/ — wire types and the ipc::Service definition. Typed LocalApiRequest / LocalApiResponse enums, address-publish-path helper.
  • app/src/local_api.rsLocalApiServer singleton entity registered at startup. Hosts an ipc::Server from crates/ipc/ on the background executor; forwards each request over an async_channel to the main thread, where spawn_stream_local dispatches it into the active workspace's active pane group and replies via a oneshot. This pattern avoids holding TerminalModel locks across awaits, the documented deadlock hazard from WARP.md.
  • crates/wp/ — thin clap-based client. Reads the published socket address, connects via ipc::Client, calls service_caller::<LocalApiService>. Subcommands: ping, split <dir>, send-text [--pane ID] TEXT, list-panes, active-pane, close-pane <ID>.
  • pane_group::PaneGroup gains three pub(crate) helpers used by the in-app handler: local_api_split_active_pane, local_api_terminal_pane_ids, local_api_close_pane.
  • pane_group::pane::TerminalPaneId gains pub(crate) to_local_api_string / parse_local_api for stable wire serialization.

Why

Every other terminal in the space (iTerm2, kitty, wezterm, alacritty + tmux) ships some external-control surface. Warp doesn't. This blocks scripts/automations that want to drive Warp from a sibling process: invoking a build in one pane while a watcher runs in another, opening a layout from a project's Justfile, integrating with productivity tools, etc. Today the only options are AppleScript (extremely limited and macOS-only) and the warp:// deeplink scheme (one-shot, fire-and-forget, no return values). This PR adds the missing capability without breaking either of those surfaces.

What this is not

This PR intentionally does not include:

  • A custom integration adapter for any specific external tool. The CLI is a generic primitive; consumers (CI scripts, AI tools, dotfile managers) write their own wrappers as needed.
  • Auth beyond same-UID UDS permissions. The address file lives under the user's data dir; only that user's processes can connect. If stronger auth is wanted (cookie-based, like iTerm2's API), that's a follow-up.
  • Versioning of the wire protocol. The current types are unversioned; before any third-party adoption a v1 namespace and protocol-version handshake should be added. Happy to do that here if reviewers prefer.

Linked Issue

None — this is a net-new capability that didn't have an existing tracking issue. Happy to open one if the team prefers that workflow before review.

  • The linked issue is labeled ready-to-spec or ready-to-implement.

Screenshots / Videos

No UI changes. The verification flow looks like:

$ wp ping
pong
$ wp split right
12345
$ wp send-text --pane 12345 "echo hello"
$ wp list-panes
12345
67890

Testing

  • cargo fmt --all -- --check — clean.
  • cargo clippy -p warp_local_api -p wp -p warp --all-targets --tests -- -D warnings — clean.
  • Manual end-to-end: launched the patched warp-oss, ran wp ping → pong, wp split right produced a new Warp pane and printed its id, wp send-text --pane <id> "ls<newline>" injected the keystrokes into the target terminal's PTY, wp close-pane <id> removed it.
  • The IPC server uses the same ipc::ServerBuilder pattern as PluginHost (see app/src/plugin/app/mod.rs). Lock-discipline tested by exercising rapid split + send-text + close cycles — no deadlocks observed.

I did not add automated tests in this PR because the request-dispatch path needs a running app context, and I didn't see an existing fixture for that pattern in the workspace. Happy to add cargo test coverage for the bincode wire format and any unit-testable helpers if reviewers point me at the right testing pattern.

Agent Mode

  • Warp Agent Mode - This PR was created via Warp's AI Agent Mode

CHANGELOG-NEW-FEATURE: Add scriptable pane control via local UDS API and wp CLI, comparable to iTerm2's it2cli.

@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 6, 2026

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: Nikitzu.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 6, 2026

@Nikitzu

I'm starting a first review of this pull request.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

@github-actions github-actions Bot added the external-contributor Indicates that a PR has been opened by someone outside the Warp team. label May 6, 2026
Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR adds a local IPC control plane and wp CLI for scripting pane operations in Warp.

Concerns

  • The published socket address is written with default filesystem permissions and points at a socket under /tmp, which does not enforce the same-user assumption for a mutating API that can write to PTYs and close panes.
  • The server accepts unbounded IPC payloads into an unbounded dispatch queue, making local denial of service possible with large or rapid send-text requests.
  • close-pane reports success for stale or nonexistent pane IDs because the helper delegates to close_pane, which silently no-ops.

Security

  • Harden address/socket publication with a private per-user directory or 0600 address file plus authentication before enabling mutating commands.
  • Add request-size and queue limits so local clients cannot exhaust Warp memory or main-thread processing.

Verdict

Found: 0 critical, 3 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/local_api.rs Outdated
Comment thread app/src/local_api.rs Outdated
Comment thread app/src/pane_group/mod.rs
@Nikitzu Nikitzu force-pushed the add-local-api-and-wp-cli branch from ee4a0e9 to 8844045 Compare May 6, 2026 14:19
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 6, 2026

Thank you for your pull request and welcome to our community. We require contributors to sign our Contributor License Agreement, and we don't seem to have the users @Nikitzu on file. In order for us to review and merge your code, each contributor must visit https://cla.warp.dev to read and agree to our CLA. Once you have done so, please comment @cla-bot check to trigger another check.

@Nikitzu
Copy link
Copy Markdown
Author

Nikitzu commented May 6, 2026

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed label May 6, 2026
@cla-bot
Copy link
Copy Markdown

cla-bot Bot commented May 6, 2026

The cla-bot has been summoned, and re-checked this pull request!

Adds a UDS-based local control plane plus a sibling `wp` CLI binary,
giving Warp the same scripting affordance that iTerm2 ships through
`it2cli`, kitty through `kitty @`, and wezterm through `wezterm cli`.
External processes (build automations, dotfile managers, productivity
tooling) can split panes, send text, list and close panes against the
running Warp without going through the keyboard / event system.

Architecture mirrors `iTermAPIServer`:

* New crate `warp_local_api` defines the wire protocol — typed
  `LocalApiRequest` / `LocalApiResponse` enums, `ipc::Service` impl,
  socket-address publish path under the platform's data-local dir.
* `app/src/local_api.rs` registers `LocalApiServer` as a singleton
  entity at startup. Hosts `ipc::Server` from `crates/ipc` on the
  background executor; forwards each request over an `async_channel`
  to the main thread, where `spawn_stream_local` dispatches it into
  the active workspace's active pane group and replies via a oneshot.
  This pattern avoids holding `TerminalModel` locks across awaits
  (the documented deadlock hazard from `WARP.md`).
* New crate `wp` is a thin clap-based client that reads the published
  socket address, connects via `ipc::Client`, and calls
  `service_caller::<LocalApiService>`. Subcommands: `ping`,
  `split <dir>`, `send-text [--pane ID] TEXT`, `list-panes`,
  `active-pane`, `close-pane <ID>`.
* `pane_group::PaneGroup` gains three `pub(crate)` helpers used by
  the in-app handler: `local_api_split_active_pane`,
  `local_api_terminal_pane_ids`, `local_api_close_pane`.
* `pane_group::pane::TerminalPaneId` gains `pub(crate)`
  `to_local_api_string` / `parse_local_api` for stable wire
  serialization round-tripping with the CLI.

Verified end-to-end: `wp ping → pong`, `wp split right` produces a
new Warp pane, `wp send-text --pane <id>` injects bytes into the
target terminal's PTY. `cargo fmt` + `cargo clippy --all-targets
--tests -- -D warnings` clean across the new and modified crates.

CHANGELOG-NEW-FEATURE: Add scriptable pane control via local UDS API and `wp` CLI.
@Nikitzu Nikitzu force-pushed the add-local-api-and-wp-cli branch from 8844045 to 8742d5a Compare May 6, 2026 15:16
@Nikitzu
Copy link
Copy Markdown
Author

Nikitzu commented May 6, 2026

@oz-agent check

@Nikitzu
Copy link
Copy Markdown
Author

Nikitzu commented May 6, 2026

/oz-review

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 6, 2026

@Nikitzu

I ran into an unexpected error while working on this.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

Adds a new local IPC control server plus a wp CLI for pane operations such as split, send-text, list, active-pane, and close-pane.

Security

  • The server is registered on every app startup, and possession of a 0600 same-UID cookie file is enough to inject bytes into terminal PTYs or close panes. This needs explicit user opt-in and/or a stronger authorization model before being enabled by default.

Concerns

  • The new module is compiled unconditionally but imports Unix-only filesystem APIs, which breaks Windows builds.
  • The socket path is fixed globally, so concurrent channels/instances can remove and rebind each other's local API endpoint.

Verdict

Found: 1 critical, 2 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/local_api.rs
Comment thread app/src/lib.rs Outdated
Comment thread app/src/local_api.rs Outdated
Address oz review on #10255:

- Gate `local_api` module and its singleton registration behind
  `cfg(unix)`. The module imports `std::os::unix::fs` and uses chmod-based
  0600 hardening, so it can't compile on Windows. Until a Windows transport
  / ACL-based permission model exists, exclude the module on non-Unix.
- Make the server opt-in via `WARP_ENABLE_LOCAL_API`. Until per-client
  authorization exists, exposing PTY writes and pane close on every
  same-UID launch is too broad a default; users who want it now flip the
  env, others stay unaffected.
- Namespace the socket and address file by `ChannelState::data_domain()`,
  and put the PID in the socket filename. Lets dev / preview / stable /
  oss channels run side-by-side without the second-launched instance
  removing the first's bind path. The address file remains per-domain so
  child shells can still discover their own Warp's socket.
- Plumb `WARP_LOCAL_API_ADDRESS` / `WARP_LOCAL_API_DOMAIN` into
  `warp_local_api::address_publish_path` for the wp CLI: env-overridable
  full path first, channel-domain default second, hardcoded
  `dev.warp.Warp` as last-resort fallback for ad-hoc invocations.

cargo fmt --all -- --check, cargo check + cargo clippy --all-targets
--tests -D warnings clean for warp_local_api, wp, and warp.
@Nikitzu
Copy link
Copy Markdown
Author

Nikitzu commented May 7, 2026

Pushed c39473a addressing the open oz review threads. Summary per concern:

Critical — std::os::unix::fs breaks Windows (app/src/local_api.rs:23)
mod local_api; and the singleton registration are now #[cfg(unix)]. The module relies on UDS + chmod 0600 for its same-UID hardening, neither of which has a clean Windows analogue, so this is a deliberate scope-bound rather than a stub. A Windows transport / ACL-based permission story can land in a follow-up.

Important — auto-start on every launch (app/src/lib.rs:1039)
The server is now opt-in via WARP_ENABLE_LOCAL_API=1. Until a per-client authorization model (e.g. iTerm2-style approval prompt or scoped capability tokens) exists, leaving mutating PTY/pane operations enabled by default for any same-UID process is too broad. Users who want the CLI today flip the env; everyone else is unaffected.

Important — fixed socket path across channels/instances (app/src/local_api.rs:175)
Both the socket and the address file are now namespaced by ChannelState::data_domain() so dev / preview / stable / oss channels coexist; the socket filename also embeds the PID so multiple instances of the same channel don't clobber each other's bind path. The shared lib (warp_local_api) gained WARP_LOCAL_API_ADDRESS (full-path override) and WARP_LOCAL_API_DOMAIN env hooks so the wp CLI can be steered to the right instance from a child shell.

Earlier-review items already in 8742d5a and unchanged here:

  • 0700 per-user $TMPDIR socket dir + 0600 socket / 0600 address file
  • Bounded dispatch queue (MAX_PENDING_COMMANDS = 256) + MAX_SEND_TEXT_BYTES = 256 KiB rejection at the boundary
  • Per-session random cookie validated server-side before dispatch
  • local_api_close_pane returns Err("pane not found") on stale ids (not the silent close_pane no-op)

Verification on this commit:

  • cargo fmt --all -- --check — clean.
  • cargo check -p warp_local_api -p wp -p warp — clean.
  • cargo clippy -p warp_local_api -p wp -p warp --all-targets --tests -- -D warnings — clean.

/oz-review

@oz-for-oss please take another look.

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 7, 2026

@Nikitzu

I'm re-reviewing this pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR adds a Unix-domain-socket local control plane and a wp CLI for pane operations. The overall shape follows existing IPC patterns, but the current diff has correctness and security issues around opt-in semantics, address discovery, and pre-auth payload handling.

Concerns

  • WARP_ENABLE_LOCAL_API=0 or any other value still enables the mutating local API despite the documented =1 opt-in.
  • wp defaults to dev.warp.Warp while the server publishes under ChannelState::data_domain(), so OSS/dev/profiled builds cannot find the address file by default and the promised shell env propagation is not present in this diff.

Security

  • The SendText size check happens after the generic IPC layer has already read, allocated, and deserialized the frame, so an unauthenticated local client can still force large allocations before the cookie is checked.

Verdict

Found: 0 critical, 3 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/lib.rs Outdated
Comment thread app/src/local_api.rs
Comment thread crates/warp_local_api/src/lib.rs Outdated
…iscover address file

- WARP_ENABLE_LOCAL_API now requires a truthy value (1/true/yes/on);
  =0/=false/empty leave it disabled.
- ipc::ServerBuilder gains with_max_request_bytes; receive_message
  rejects oversized frames at the framing layer before any payload
  read or deserialize, so an unauthenticated peer can't force a large
  allocation by lying about its size. Local API caps frames at
  MAX_SEND_TEXT_BYTES + 4 KiB envelope overhead.
- wp resolves the address file via WARP_LOCAL_API_ADDRESS, then
  WARP_LOCAL_API_DOMAIN, then auto-discovers a single live channel
  under the data-local dir. Multiple live instances surface as an
  ambiguity error naming each candidate path. Removes the inaccurate
  doc claim that Warp injects WARP_LOCAL_API_ADDRESS into spawned
  shells (not implemented in this PR scope).
@Nikitzu
Copy link
Copy Markdown
Author

Nikitzu commented May 7, 2026

Pushed 21220e3 addressing the open oz review threads.

Important — WARP_ENABLE_LOCAL_API=0 (or any value) still enabled the API
The check was env::var_os(...).is_some(), which fires on =0, =false, or empty. Replaced with a truthy parse: only 1 / true / yes / on (case-insensitive, trimmed) flip the singleton on. Anything else — including unset — keeps the server dormant. Helper at app/src/lib.rs:328 (local_api_opt_in_enabled).

Important — wp defaulted to dev.warp.Warp while the server published under ChannelState::data_domain()
Removed the inaccurate doc claim that Warp injects WARP_LOCAL_API_ADDRESS into spawned shells — that propagation was aspirational and not part of this diff. Replaced with auto-discovery in wp:

  1. WARP_LOCAL_API_ADDRESS (full path) — explicit override.
  2. WARP_LOCAL_API_DOMAIN (domain only) — resolved through address_publish_path_for.
  3. Auto-discover: scan <data-local-dir>/*/local-api.address and pick the single existing match. Multiple live channels surface as an Ambiguous error that lists each candidate path and tells the user which env to set. Zero matches falls back to the default-domain path so the existing "is Warp running?" error stays useful.

resolve_address_path returns the new AddressResolution::{Single, Ambiguous}; the legacy address_publish_path() is kept for back-compat but defers to the resolver.

Important — SendText size cap fired only after the IPC layer had already read+deserialized the frame
Added ServerBuilder::with_max_request_bytes(usize) (opt-in; existing consumers stay unbounded). The cap is enforced inside receive_message before any payload allocation: a frame whose announced length exceeds the cap is rejected as ProtocolError::Other without ever sizing the buffer. The local-API server passes MAX_REQUEST_BYTES = MAX_SEND_TEXT_BYTES + 4 KiB (envelope/cookie overhead margin), so an unauthenticated peer can no longer force a large allocation by lying about its size before the cookie check runs. The post-deserialize text.len() check stays as defense-in-depth for callers that miswire the cap.

Verification on this commit (with the workspace rust-toolchain 1.92.0):

  • cargo fmt --all -- --check — clean.
  • cargo check -p ipc -p warp_local_api -p wp -p warp — clean.
  • cargo clippy -p ipc -p warp_local_api -p wp -p warp --all-targets --tests -- -D warnings — clean.

(cargo check --workspace fails on command-signatures-v2/build.rs because of a missing local Node toolchain — unrelated to this diff.)

/oz-review

@oz-for-oss please take another look.

@oz-for-oss
Copy link
Copy Markdown
Contributor

oz-for-oss Bot commented May 7, 2026

@Nikitzu

I'm re-reviewing this pull request in response to a review request.

You can view the conversation on Warp.

I completed the review and no human review was requested for this pull request.

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Copy link
Copy Markdown
Contributor

@oz-for-oss oz-for-oss Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overview

This PR adds an opt-in local UDS control API and a wp CLI for scripting pane operations. The overall direction is clear, but the new unauthenticated IPC boundary needs stronger failure handling before merge.

Concerns

  • The local API handler relies on typed IPC deserialization before cookie validation, so malformed service bytes can panic the handler before auth runs.
  • The address-file writer can expose a fresh cookie through a previously loose file mode before it tightens permissions.
  • Oversized-frame handling returns before consuming payload bytes, but the server loop continues on the same stream.

Security

  • The two local API authentication/cookie handling issues are security-sensitive because this feature deliberately exposes mutating PTY and pane operations to sibling local processes.

Verdict

Found: 0 critical, 3 important, 0 suggestions

Request changes

Comment /oz-review on this pull request to retrigger a review (up to 3 times on the same pull request).

Powered by Oz

Comment thread app/src/local_api.rs
Comment thread app/src/local_api.rs Outdated
Comment thread crates/ipc/src/server.rs
… write, close stream on oversized frame

- Replace .expect-panic in AnyServiceImpl deserialize with a fallible
  signature; bad request bytes now flow through Response::Failure
  instead of crashing the connection task. The cookie check still
  runs on the typed envelope, but a malformed frame can no longer
  panic the worker before auth.
- publish_address now writes through a sibling temp file opened with
  create_new + .mode(0o600) and atomically renames over the target.
  Previous code reused an existing inode, so OpenOptions::mode never
  fired and the cookie could be world-readable for the window
  between write_all and set_permissions.
- Promote ProtocolError::Other("frame too large") to a structured
  ProtocolError::FrameTooLarge variant. The server loop closes the
  connection on it because the announced payload bytes were never
  consumed and the stream is misaligned; previous behaviour logged
  and continued, leaving subsequent reads parsing payload bytes as
  the next frame's header.
@Nikitzu
Copy link
Copy Markdown
Author

Nikitzu commented May 7, 2026

Pushed d115c3f addressing the three new oz threads.

Important — typed deserialization could panic the handler before auth runs
The IPC framework (crates/ipc/src/server.rs) ran bincode::deserialize::<S::Request>(...).expect(...) inside the per-connection worker. A same-UID peer who only knew the socket path (not the cookie) could send any byte string ≤ MAX_REQUEST_BYTES and panic the task — DoS'ing that connection before the cookie check ever fired.

AnyServiceImpl::handle_request now returns Result<Vec<u8>, String>. The dispatcher in handle_incoming_requests wraps Err in the existing framework-level Response::Failure path (same code path used today for "no such service"), so malformed bytes turn into a clean error response and the connection stays up. Cookie check still runs in LocalApiServiceImpl::handle_request once typed deserialization succeeds; the difference is that bad bytes can no longer crash the worker.

The response-side bincode::serialize is also now fallible (returned as the same string error) — symmetric, and the only programmer-bug case left would be a Service whose Response is non-serializable, which fails at cargo check.

Important — address-file writer could expose a fresh cookie under loose perms
Previous code did OpenOptions::new().create(true).truncate(true).mode(0o600).open(&path) then set_permissions(0o600) after write_all. The OpenOptions::mode flag only applies on file creation — if a prior Warp version had left <data-local-dir>/<domain>/local-api.address at, say, 0644, the open re-used that inode, the cookie bytes were written under the looser mode, and only then were perms tightened.

publish_address (app/src/local_api.rs:199) now writes through a sibling temp file:

  1. Open .local-api.address.<pid>.tmp in the same directory with create_new(true).mode(0o600)O_CREAT | O_EXCL so the kernel creates a fresh inode at 0600, no race against pre-existing content or symlinks.
  2. write_all(...) then sync_all().
  3. Atomic rename(2) over the destination.

The destination's old perms are irrelevant because the new inode replaces it; the cookie bytes are never resident in a file with looser-than-0600 mode.

Important — oversized-frame handling desynced the stream
receive_message returned the error before consuming the announced payload. The server loop's catch-all e => arm logged and continued, so the next iteration would read 8 bytes that were actually the head of the unconsumed payload, mis-parse them as a length header, and either spin on bincode::deserialize failures or trigger another spurious FrameTooLarge.

Two coordinated changes:

  • ProtocolError::Other("frame too large…") → structured ProtocolError::FrameTooLarge { announced, cap } (crates/ipc/src/protocol.rs).
  • handle_incoming_requests now matches that variant explicitly and breaks the per-connection loop. The Serialization arm continues as before because at that point the framing layer has already consumed payload_len bytes, so the stream is still aligned for the next frame.

Verification on this commit:

  • cargo fmt --all -- --check — clean.
  • cargo check -p ipc -p warp_local_api -p wp -p warp — clean.
  • cargo clippy -p ipc -p warp_local_api -p wp -p warp --all-targets --tests -- -D warnings — clean.

/oz-review

@oz-for-oss please take another look.

@Nikitzu Nikitzu closed this by deleting the head repository May 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed external-contributor Indicates that a PR has been opened by someone outside the Warp team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant