Commit Graph
996 Commits
Author SHA1 Message Date
Michael Sloan 218c063480 Avoid re-querying language server completions when possible (#31872)
Also adds reuse of the markdown documentation cache even when
completions are re-queried, so that markdown documentation doesn't
flicker when `is_incomplete: true` (completions provided by rust
analyzer always set this)

Release Notes:

- Added support for filtering language server completions instead of
re-querying.
2025-06-02 22:19:09 +00:00
d987cda64e agent: Support vim-mode in the agent panel's editor (#31915)
Closes #30081

Release Notes:

- Added vim-mode support in the agent panel's editor

---------

Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
2025-06-02 22:10:31 +03:00
Oleksiy Syvokon 7d76a6b6a0 agent: Migrate thread storage to SQLite with zstd compression (#31741)
Previously, LMDB was used for storing threads, but it consumed excessive
disk space and was capped at 1GB.

This change migrates thread storage to an SQLite database. Thread JSON
objects are now compressed using zstd.

I considered training a custom zstd dictionary and storing it in a
separate table. However, the additional complexity outweighed the modest
space savings (up to 20%). I ended up using the default dictionary
stored with data.

Threads can be exported relatively easily from outside the application:

```
$ sqlite3 threads.db "SELECT hex(data) FROM threads LIMIT 5;" |
    xxd -r -p |
    zstd -d |
    fx
```

Benchmarks:
- Original heed database: 200MB
- Sqlite uncompressed: 51MB
- sqlite compressed (this PR): 4.0MB
- sqlite compressed with a trained dictionary: 3.8MB


Release Notes:

- Migrated thread storage to SQLite with compression
2025-06-02 17:01:34 +03:00
Alisina Bahadori 969ff5ec67 Increase terminal inline assistant block height (#31807)
Closes #31806
Closes #28969

Not sure if a static value is best. Maybe it is better to somehow use
`count_lines` function here too.

### Before
<img width="871" alt="449463234-ab1a33a0-2331-4605-aaee-cae60ddd0f9d"
src="https://github.com/user-attachments/assets/1e3bec86-4cad-426c-9f59-5ad3d14fc9d7"
/>


### After
<img width="861" alt="Screenshot 2025-05-31 at 1 12 33 AM"
src="https://github.com/user-attachments/assets/0c8219a9-0812-45af-8125-1f4294fe2142"
/>

Release Notes:

- Fixed terminal inline assistant clipping when cursor is at bottom of
terminal.
2025-06-02 10:55:40 -03:00
Umesh YadavandBennet Bo Fenner 7d4476a397 agent: Show actual file name and icon in context pill (#31813)
Previously in the agent context pill if we added images it showed
generic Image tag on the image context pill. This PR make sure if we
have a path available for a image context show the filename which is in
line with other context pills.


Before | After
--- | ---
![Screenshot 2025-05-31 at 3 14 07
PM](https://github.com/user-attachments/assets/b342f046-2c1c-4c18-bb26-2926933d5d34)
| ![Screenshot 2025-05-31 at 3 14 07
PM](https://github.com/user-attachments/assets/90ad4062-cdc6-4274-b9cd-834b76e8e11b)





Release Notes:

- N/A

---------

Co-authored-by: Bennet Bo Fenner <bennetbo@gmx.de>
2025-06-02 10:35:22 +00:00
Marshall Bowers ae821bf17d danger: Check for changes in prompt files (#31744)
This PR adds a Danger check to remind engineers that any changes to our
various prompts need to be verified against the LLM Worker.

When changes to the prompt files are detected, we will fail the PR with
a message:

<img width="929" alt="Screenshot 2025-05-30 at 8 40 58 AM"
src="https://github.com/user-attachments/assets/79afab4e-e799-45f1-a90e-0fd7c9a73706"
/>

Once the corresponding changes have been made (or no changes to the LLM
Worker have been determined to be necessary), including the indicated
attestation message will convert the errors into informational messages:

<img width="926" alt="Screenshot 2025-05-30 at 8 41 52 AM"
src="https://github.com/user-attachments/assets/ff51c17a-7a76-46a7-b468-a7d864d480c3"
/>

Release Notes:

- N/A
2025-05-30 13:46:41 +00:00
Michael Sloan 8562928579 Remove block_mouse_down in favor of stop_mouse_events_except_scroll (#30401)
This method was added in #20649 to be an alternative of `occlude` which
allows scroll events. It seems a bit arbitrary to only stop left mouse
downs, so this seems like it's probably an improvement.

Release Notes:

- N/A
2025-05-29 22:07:34 +00:00
Michael Sloan 63499bfa86 gpui: Support hitbox blocking mouse interaction except scrolling (#31712)
tl;dr: This adds `.block_mouse_except_scroll()` which should typically
be used instead of `.occlude()` for cases when the mouse shouldn't
interact with elements drawn below an element. The rationale for
treating scroll events differently:

* Mouse move / click / styles / tooltips are for elements the user is
interacting with directly.
* Mouse scroll events are about finding the current outer scroll
container.

Most use of `occlude` should probably be switched to this, but I figured
I'd derisk this change by minimizing behavior changes to just the 3 uses
of `block_mouse_except_scroll`.

GPUI changes:

* Added `InteractiveElement::block_mouse_except_scroll()`, and removes
`stop_mouse_events_except_scroll()`

* Added `Hitbox::should_handle_scroll()` to be used when handling scroll
wheel events.

* `Window::insert_hitbox` now takes `HitboxBehavior` instead of
`occlude: bool`.

    - `false` for that bool is now `HitboxBehavior::Normal`.

    - `true` for that bool is now `HitboxBehavior::BlockMouse`.
    
    - The new mode is `HitboxBehavior::BlockMouseExceptScroll`.

* Removes `Default` impl for `HitboxId` since applications should not
manually create `HitboxId(0)`.

Release Notes:

- N/A
2025-05-29 21:41:15 +00:00
Marshall BowersandBen Brandt 4f9b4b371d Pass up intent with completion requests (#31710)
This PR adds a new `intent` field to completion requests to assist in
categorizing them correctly.

Release Notes:

- N/A

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-05-29 20:43:12 +00:00
Danilo Leal 2bbebcb63a agent: Fix panel "go back" button (#31706)
Closes https://github.com/zed-industries/zed/issues/31652.

Release Notes:

- agent: Fixed a bug where the "go back" button wouldn't go back to the
Text Thread after visiting another view from it.
2025-05-29 16:00:37 -03:00
Danilo Leal 21beace2f5 agent: Rename PromptEditor to TextThread in the panel's ActiveView (#31705)
Was touching this part of the Agent Panel and thought it could be a
quick name consistency win here, so it is aligned with the terminology
we're currently actively using in the product/docs.

Release Notes:

- N/A
2025-05-29 15:31:35 -03:00
Umesh YadavandDanilo Leal 66238308bf Rename Max Mode to Burn Mode throughout code and docs (#31668)
Follow up to https://github.com/zed-industries/zed/pull/31470.

I started looking at config and changed preferred_completion_mode to
burn to only find its max so made changes to align it better with
rebrand. As this is in preview build now.

This doesn't touch zed_llm_client. Only the Zed changes the code and doc
to match the new UI of burn mode. There are still more things to be
renamed, though.

Release Notes:

- N/A

---------

Signed-off-by: Umesh Yadav <git@umesh.dev>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-05-29 13:12:42 +00:00
Kirill Bulatov d186411b4a Allow to reuse PickerPopoverMenu outside of the model selector (#31684)
LSP button preparation step: move out the component that will be used to
build the button's context menu.

Release Notes:

- N/A
2025-05-29 12:55:47 +00:00
Danilo Leal f01f2ab3fe agent: Add keybinding to toggle Burn Mode (#31630)
One caveat with this PR is that the keybinding still doesn't work for text threads. Will do that in a follow-up.

Release Notes:

- agent: Added a keybinding to toggle Burn Mode on and off.
2025-05-28 18:08:58 -03:00
Danilo Leal 3b30d303cc agent: Make clicking on the backdrop to dismiss message editing more reliable (#31614)
Previously, the click on the backdrop to dismiss the message editing was
unreliable. You would click on it and sometimes it would work and others
it wouldn't. This PR fixes that now.

Release Notes:

- agent: Fixes the previous message dismissal by clicking on the
backdrop
2025-05-28 15:29:52 -03:00
Danilo Leal b042d9db03 agent: Move focus to the panel after dismissing a user message edit (#31611)
Previously, when you clicked on a previous message to edit it and then
dismissed it, your focus would jump to the buffer. This caught me
several times as the most obvious place to return to for me was the
agent panel main message editor, so I can continue prompting something
else. And this is what this PR changes.

Release Notes:

- agent: Improved previous message editing UX by returning focus to the
main panel's text area after dismissing it.
2025-05-28 15:24:58 -03:00
Richard Feldman 552b1f468c Make language model deserialization more resilient (#31311)
This expands our deserialization of JSON from models to be more tolerant
of different variations that the model may send, including
capitalization, wrapping things in objects vs. being plain strings, etc.

Also when deserialization fails, it reports the entire error in the JSON
so we can see what failed to deserialize. (Previously these errors were
very unhelpful at diagnosing the problem.)

Finally, also removes the `WrappedText` variant since the custom
deserializer just turns that style of JSON into a normal `Text` variant.

Release Notes:

- N/A
2025-05-28 12:06:07 -04:00
Ben Brandt d2c0ccc0e1 Revert "agent: Namespace MCP server tools" (#31588)
Reverts zed-industries/zed#30600
2025-05-28 13:25:53 +00:00
Antonio ScandurraandBen Brandt 0d2798e61a Show progress as the agent locates which range it needs to edit (#31582)
Release Notes:

- Improved latency when the agent starts streaming edits.

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
2025-05-28 12:32:54 +00:00
c9160d0523 agent: Improve consecutive tool call UX and rebrand Max Mode (#31470)
This PR improves the consecutive tool call UX by allowing users to
quickly continue an interrupted with one-click. What we do here is
insert a hidden "Continue" message that will just nudge the LLM to keep
going. We're also using the opportunity to upsell the previously called
"Max Mode", now rebranded as "Burn Mode", which allows users to don't be
interrupted anymore if they ever have 25 consecutive tool calls again.

Release Notes:

- agent: Improve consecutive tool call UX by allowing users to quickly
continue an interrupted thread with one click.

---------

Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Agus Zubiaga <hi@aguz.me>
Co-authored-by: Agus Zubiaga <agus@zed.dev>
2025-05-27 19:44:10 -03:00
Richard FeldmanandDanilo Leal 5c83060246 Add warning message when editing a message in a thread (#31508)
<img width="479" alt="Screenshot 2025-05-27 at 9 42 44 AM"
src="https://github.com/user-attachments/assets/7bd9e1b9-26b4-4396-9f93-e92a5f4ac2e1"
/>

Release Notes:

- Added notice that editing a message in the agent panel will restart
the thread from that point.

---------

Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-05-27 16:26:47 -04:00
Bennet Bo Fenner 82a2f6d2e3 agent: Namespace MCP server tools (#30600)
This fixes an issue where requests were failing when MCP servers were
registering tools with the same name.
We now prefix the tool names with the context server name, in the UI we
still show the name that the MCP server gives us

Release Notes:

- agent: Fix an error were requests would fail if two MCP servers were
using an identical tool name
2025-05-27 17:47:44 +00:00
Marshall Bowers 0b98aefaa8 Rename assistant_settings to agent_settings (#31513)
This PR renames the `assistant_settings` crate to `agent_settings`, as
well a number of constructs within it.

Release Notes:

- N/A
2025-05-27 15:16:55 +00:00
Richard Feldman aab765ff76 Restore Checkpoint now appears if you press Cancel (#31310)
## Before


https://github.com/user-attachments/assets/0da54afd-78bb-4fee-ab0c-f6ff96f89550

## After


https://github.com/user-attachments/assets/e840e642-714b-4ed7-99cf-a972f50361ba

Release Notes:

- In the Agent Panel, Restore Checkpoint now appears if you press Cancel
during generation.
2025-05-27 09:22:42 -04:00
Joseph T. Lyons 7b39f232ec Use read-only access methods for read-only entity operations (#31479)
Another follow-up to #31254

Release Notes:

- N/A
2025-05-26 23:04:31 -04:00
Cole Miller b58ea98473 git: Fix hunk controls blocking scrolling (#31476)
Thanks @mgsloan for introducing `stop_mouse_events_except_scroll` which
is exactly what we want here!

Release Notes:

- Fixed being unable to scroll editors when the cursor is positioned on
diff hunk controls.
2025-05-27 01:35:00 +00:00
Danilo Leal b08e0f3a7c agent: Add sound notification when done generating (#31472)
This PR adds the ability to hear a sound notification when the agent is
done generating and/or needs user input. This setting is turned off by
default and can be used together with the visual notification. The
specific sound I'm using here comes from the [Material Design 2 Sound
Library](https://m2.material.io/design/sound/sound-resources.html#).

Release Notes:

- agent: Added the ability to have a sound notification when the agent
is done generating and/or needs user input.
2025-05-26 21:20:41 -03:00
Joseph T. Lyons 584792e850 Use read() over read_with() to improve readability in simple cases (#31455)
Follow up to: #31263 

Release Notes:

- N/A
2025-05-26 16:14:07 -04:00
Danilo Leal ebd80b9089 agent: Refine naming for the panel default_view setting (#31446)
Follow up to https://github.com/zed-industries/zed/pull/31353. Just
ensuring we're walking toward a more consistent use of the multiple
terms we have floating around in the AI realm. In this case, `thread` is
the term for the now default view, the one that has agentic features;
`text_thread` is the term for the original view, the one where it's just
text. The settings now reflect this. Also took advantage of the
opportunity to add some docs, too.

Release Notes:

- N/A
2025-05-26 15:09:13 -03:00
Michael Sloan c69a0c812e Add a live Rust style editor to inspector to edit a sequence of no-argument style modifiers (#31443)
Editing JSON styles is not very helpful for bringing style changes back
to the actual code. This PR adds a buffer that pretends to be Rust,
applying any style attribute identifiers it finds. Also supports
completions with display of documentation. The effect of the currently
selected completion is previewed. Warning diagnostics appear on any
unrecognized identifier.


https://github.com/user-attachments/assets/af39ff0a-26a5-4835-a052-d8f642b2080c

Adds a `#[derive_inspector_reflection]` macro which allows these methods
to be enumerated and called by their name. The macro code changes were
95% generated by Zed Agent + Opus 4.

Release Notes:

* Added an element inspector for development. On debug builds,
`dev::ToggleInspector` will open a pane allowing inspecting of element
info and modifying styles.
2025-05-26 17:43:57 +00:00
Alvaro Parker 49651df0a5 agent: Add a setting choose the default view (#31353)
Related discussions #30240 #30596

Release Notes:

- Added an option on the settings file to choose either the `agent`
panel or the `thread` panel as the default assistant panel when you
first open it. On `settings.json`:
```json
{
  "agent": {
    "default_view": "thread", // default is agent
    }
}
```
2025-05-26 16:33:18 +02:00
4eb5fb6291 agent: Add a whitespace after inserting @-mention to allow for continuous typing (#30381)
Release Notes:

- agent: Added a space after @-mentioning something in the message
editor to allow for continuous typing.

---------

Co-authored-by: Peter Tripp <peter@zed.dev>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
2025-05-26 09:55:19 -03:00
Mani Rash Ahmadi b5dc9f923c agent: Ensure context meter updates when context is cleared (#30320)
Addresses an issue where the agent context token meter in the panel
toolbar (showing usage like "X / Y tokens") failed to update its count
after the user cleared the current context via the context editor UI.
While the meter updated correctly when adding items, clearing them left
the display showing the old count.

The root cause was traced to the `ContextStore::clear` method in
`crates/agent/src/context_store.rs`. This method correctly cleared the
internal data structures holding the context items but neglected to call
`cx.notify()` to inform listeners of the state change. Consequently, the
UI components responsible for displaying the token count were not
triggered to re-render with the new (presumably lower) count.

This PR fixes the issue by adding the missing `cx.notify()` call to the
`ContextStore::clear` method. This ensures listeners are notified when
the context set is cleared, allowing the token meter UI to update
correctly.

Release Notes:

- Fixed an issue where the agent context token meter did not update when
the context was cleared.
2025-05-26 09:51:00 +02:00
Joseph T. Lyons 1cd065c82a Add agent: chat with follow action (experimental) (#31401)
This PR introduces a new `agent: chat with follow` action that
automatically enables "Follow Agent" when submitting a chat message with
`cmd-enter` or `ctrl-enter`. This is experimental. I'm not super
thrilled with the name, but the root action to submit a chat is called
`agent: chat`, so I'm following that wording. I'm also unsure if the
binding feels right or not.

Release Notes:

- Added an `agent: chat with follow` action via `cmd-enter` on macOS and
`ctrl-enter` on Linux
2025-05-25 20:15:06 -04:00
Marshall Bowers 9c4a074d8e agent: Don't show "Tools Unsupported" when no model is selected (#31321)
This PR makes it so we don't show "Tools Unsupported" when no model is
selected.

Release Notes:

- N/A
2025-05-24 01:45:10 +00:00
f6f0cae3ca Add initial element inspector for Zed development (#31315)
Open inspector with `dev: toggle inspector` from command palette or
`cmd-alt-i` on mac or `ctrl-alt-i` on linux.

https://github.com/user-attachments/assets/54c43034-d40b-414e-ba9b-190bed2e6d2f

* Picking of elements via the mouse, with scroll wheel to inspect
occluded elements.

* Temporary manipulation of the selected element.

* Layout info and JSON-based style manipulation for `Div`.

* Navigation to code that constructed the element.

Big thanks to @as-cii and @maxdeviant for sorting out how to implement
the core of an inspector.

Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Federico Dionisi <code@fdionisi.me>
2025-05-23 23:08:59 +00:00
Ben BrandtandMarshall Bowers 3165db8e68 Add overdue invoices check (#31290)
- Rename current_user_account_too_young to account_too_young for
consistency
- Add has_overdue_invoices field to track billing status
- Block edit predictions when user has overdue invoices
- Add overdue invoice warning to inline completion menu

Release Notes:

- N/A

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-05-23 20:02:02 +00:00
Richard Feldman 996024fd7f Don't always scroll to bottom on every new message (#31295)
This is a partial reversion of
https://github.com/zed-industries/zed/pull/30878 - having it always
scroll to bottom whenever a new message is added makes it so that when
you're scrolled up, you don't have time to read what you're trying to
read before it autoscrolls to the end.

@danilo-leal when you're back, we can pair on addressing that in a
different way!

Release Notes:

- Fixed bug where scrolling up in the agent panel didn't prevent
automatic scroll-to-end whenever a new message arrived.
2025-05-23 15:11:29 -04:00
Ben Brandt 45a2b3b4bd agent: Unfollow agent on completion cancellation (#31258)
Handle unfollowing agent and clearing agent location when completion
is canceled.

Release Notes:

- N/A
2025-05-23 14:55:08 +02:00
Joseph T. Lyons 65c9f97fea Use read() over read_with() to improve readability in simple cases (#31263)
Release Notes:

- N/A
2025-05-23 12:08:49 +00:00
tidely 3badd8fa29 terminal: Consume event during processing (#30869)
By consuming the event during processing we save a few clones during
event processing.

Overall in this PR we save one Clone each during:

- Paste to the terminal
- Writing to the terminal
- Setting the title
- On every terminal transaction
- On every ViMotion when not using shift

Release Notes:

- N/A
2025-05-23 14:28:53 +03:00
Joseph T. Lyons ce5566b3cd Use read-only access methods for read-only entity operations (#31254)
This PR replaces some `update()` calls with either `read()` or
`read_with()` when the `update()` call performed read-only operations on
the entity.

Many more likely exist, will follow-up with more PRs.

Release Notes:

- N/A
2025-05-23 06:13:49 -04:00
Ben BrandtandAntonio Scandurra 4797f2b03e Better messaging for accounts that are too young (#31212)
Right now you find this out the first time you try and submit a
completion.

These changes communicate much earlier to the user what the issue is
with their account and what they can do about it.

Release Notes:

- N/A

---------

Co-authored-by: Antonio Scandurra <me@as-cii.com>
2025-05-23 09:32:03 +00:00
Marshall Bowers 1b724a6b08 eval: Don't read the model from the user settings (#31230)
This PR fixes an issue where the eval was incorrectly pulling the
provider/model from the user settings, which could cause problems when
running certain evals.

Was introduced in #30168 due to the restructuring after the removal of
the `assistant` crate.

Release Notes:

- N/A
2025-05-23 00:21:35 +00:00
Marshall Bowers 40141a4e85 agent: Remove last turn after a refusal (#31220)
This is a follow-up to https://github.com/zed-industries/zed/pull/31217
that removes the last turn after we get a `refusal` stop reason, as
advised by the Anthropic docs.

Meant to include it in that PR, but accidentally merged it before
pushing these changes 🤦🏻‍♂️.

Release Notes:

- N/A
2025-05-22 21:38:33 +00:00
Marshall Bowers 6cad646f7a Handle new refusal stop reason from Claude 4 models (#31217)
This PR adds support for handling the new [`refusal` stop
reason](https://docs.anthropic.com/en/docs/test-and-evaluate/strengthen-guardrails/handle-streaming-refusals)
from Claude 4 models.

<img width="409" alt="Screenshot 2025-05-22 at 4 31 56 PM"
src="https://github.com/user-attachments/assets/707b04f5-5a52-4a19-95d9-cbd2be2dd86f"
/>

Release Notes:

- Added handling for `"stop_reason": "refusal"` from Claude 4 models.
2025-05-22 16:56:59 -04:00
Piotr Osiewicz 982453f35c chore: Make terminal_view own the TerminalSlashCommand (#31070)
This reduces 'touch crates/editor/src/editor.rs && cargo +nightly build'
from 8.9s to 8.5s. That same scenario used to take 8s less than a week
ago. :)
I'm measuring with nightly rustc, because it's compile times are better
than those of stable thanks to
https://github.com/rust-lang/rust/pull/138522

main (8.2s total):

![image](https://github.com/user-attachments/assets/767a2ac4-7bba-4147-bd16-9b09eed5b433)

[cargo-timing.html.zip](https://github.com/user-attachments/files/20364175/cargo-timing.html.zip)

#22be776 (7.5s total):

[cargo-timing-20250521T085303.892834Z.html.zip](https://github.com/user-attachments/files/20364391/cargo-timing-20250521T085303.892834Z.html.zip)

![image](https://github.com/user-attachments/assets/c4476df9-cb6e-4403-b0db-de00521f1fd0)


Release Notes:

- N/A
2025-05-21 09:27:54 +00:00
Kirill Bulatov 6f2725844a Use anyhow more idiomatically (#31052)
https://github.com/zed-industries/zed/issues/30972 brought up another
case where our context is not enough to track the actual source of the
issue: we get a general top-level error without inner error.

The reason for this was `.ok_or_else(|| anyhow!("failed to read HEAD
SHA"))?; ` on the top level.

The PR finally reworks the way we use anyhow to reduce such issues (or
at least make it simpler to bubble them up later in a fix).
On top of that, uses a few more anyhow methods for better readability.

* `.ok_or_else(|| anyhow!("..."))`, `map_err` and other similar error
conversion/option reporting cases are replaced with `context` and
`with_context` calls
* in addition to that, various `anyhow!("failed to do ...")` are
stripped with `.context("Doing ...")` messages instead to remove the
parasitic `failed to` text
* `anyhow::ensure!` is used instead of `if ... { return Err(...); }`
calls
* `anyhow::bail!` is used instead of `return Err(anyhow!(...));`

Release Notes:

- N/A
2025-05-20 23:06:07 +00:00
Richard Feldman a685c934f7 Accept wrapped text content from LLM providers (#31048)
Some providers sometimes send `{ "type": "text", "text": ... }` instead
of just the text as a string. Now we accept those instead of erroring.

Release Notes:

- N/A
2025-05-20 20:50:02 +00:00
5ceca6397b Add end of service notifications (#30982)
Release Notes:

- N/A

---------

Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
2025-05-20 00:20:00 +00:00