[pull] main from danny-avila:main - #257
Merged
Merged
Conversation
The short-description warning in validateSkillDescription told users that "Claude" may miss triggering opportunities, although LibreChat skills run with any configured model. Say "the agent" instead, and align the doc comment that quotes the warning.
* feat: unified pinned section with drag interactions and sidebar polish - Pinned chats and favorite models/agents/specs render as one interleaved, reorderable list persisted via users.pinnedOrder - Drag conversations onto project rows to file them, onto Chats to unfile, and onto the Pinned section to pin (empty section materializes as a drop zone during a conversation drag) - Row-level unpin button on pinned chats matching the favorites' button, and the row action menu shares the same hover/focus treatment - Agent Marketplace entry moved under the New Chat button in the side rail - Bookmarks trigger sized to the search bar, search focus no longer swaps its border color, tag filtering shows a loading state, and opening a project shows row-shaped skeletons * fix: add pinnedOrder to IUser type and sort imports * fix: pinned drag threshold, unpin focus target, and marketplace link * fix: surface failed pinned reorders and skip no-op order writes * fix: address review findings on unified pinned section Move the pinned-order endpoints into packages/api as TypeScript handlers and route their URLs through the data-provider endpoint registry. Raise the entry and key caps so a valid model favorite and an unbounded pin count can both be persisted. Keep the marketplace entry reachable from the mobile drawer, which is the only sidebar surface on small screens. Merge a reorder into the stored order while a bookmark filter hides part of the list, instead of dropping the hidden keys. Add Alt+Arrow keyboard reordering with a live-region announcement, restore the focus handoff when a favorite is removed, and hold the local arrangement until the stored order catches up. Serialize overlapping order writes and discard the optimistic value when the first one fails. Derive the tag-filter loading state from isPreviousData rather than a flag that could stick on. * fix: release drag while renaming and dedupe repeated favorite keys A draggable ancestor swallows drag-select inside the rename input, so both the row's own drag source and the pinned wrapper's release while a title is being edited. The favorites payload validator accepts a repeated entry, and two rows keyed the same would collide in React, point every drag at the first copy, and fail the order endpoint's uniqueness check. Build the pinned list keyed-unique. * fix: address PR review bot findings Make the model favorite key injective. Joining endpoint and model on '::' collided for components containing the delimiter, so two distinct favorites keyed the same and the dedupe hid one; the endpoint is now length-prefixed. Replace the pinned-order entry cap with a total size guard. Pinning has no membership cap and the sidebar query drains every cursor, so any count limit rejects a legitimate list rather than bounding anything; what needs bounding is the user document. Let only the newest order write touch the cache. An earlier write failing rolled back over a newer arrangement that was still in flight, leaving the UI on a stale order while the server held the current one. A confirmed write now takes the server's answer, and a failed newest write discards the value that was never accepted. Persist the favorites array only once the order write succeeds, so a rejected write cannot leave the two stores disagreeing with the rolled-back display. * fix: address second round of PR review bot findings Read favorites membership at write time rather than capturing it at drag end. A favorite added or removed while the order request was in flight was undone by writing the older list back; only the relative order now comes from the drag. Move the pinned-order queue to module scope. The sidebar unmounts whole sections while a search is active, so a component-local ref let a remounted hook start a second queue alongside a request that was still running. Serialize project assignment per conversation. Every drop target owns its own mutation instance and the write is an unconditional update, so two quick drops let whichever request reached the database last decide the project. Read the pinned-order request body null-safely: destructuring a nullish body threw past the handler into Express's generic error path instead of returning the intended 400. * fix: address third round of PR review bot findings Drop the secondary favorites write. No consumer of the favorites array reads its order, so mirroring the arrangement there bought nothing while racing the membership mutations that share that whole-array endpoint; pinnedOrder is the single source of ordering. Always merge the committed order into the stored one. The visible list is not always the whole list, since a bookmark filter hides rows and the pinned query publishes partial results while draining its cursor, and replacing wholesale dropped every key it could not see. Release the local arrangement when the write settles instead of when the stored order matches it key for key. A pin arriving mid-request made that equality unreachable, stranding the snapshot and hiding the new row until remount. Abandon a queued pinned-order write if the signed-in user changed, so a deferred request cannot write one account's order into another's document. * fix: address fourth round of PR review bot findings Guard the pinned-order completion callbacks on the signed-in account. The pre-send check only covers a write that has not left yet; a response arriving after a session change would publish one account's order into the next one's cache, which this query never refetches on its own. Commit a reorder only when the pinned rows handled the drop. Dragging a pin onto a project row or into Chats sweeps the pointer across sibling rows, whose hover handlers shift the order, so a filing action was also saving a move the user never asked for. * fix: address fifth round of PR review bot findings Deselect pinnedOrder at schema level. It is display-only and allowed to grow large, but every authentication request loads the user document, so it was adding its whole payload to paths that never read it. Refuse to reorder until the stored order has loaded. Merging against an absent order and then cancelling its fetch posted only the visible keys and discarded saved positions for good. Prune keys only once the visible list is known to be the whole list. Merging unconditionally grew the array until the size guard rejected every write, so completeness now gates compaction rather than the filter flag alone. Track every renaming row, not just the most recent. RenameForm has no blur cancellation, so a second form can open while the first is still mounted and the single key reconnected the first row's drag source under its open input. Judge drop eligibility by the queued destination. A drag item carries the project its row had when the drag began, so re-dropping a chat back where it started while an assignment was queued read as a no-op. Take mutation ownership from the user atom AuthContext fills on login rather than the user query, which is still empty in that window, and never treat an unknown owner as a match. Restore the pinned section's 30vh cap. Matching the Projects section's 42vh put 84vh of non-shrinking content above Chats and starved it on short viewports. * fix: address sixth round of PR review bot findings Gate reordering and pruning on successful fetches rather than attempted ones. A failed pinned-order GET still reports as fetched, and a failed later page of the pinned drain still publishes partial data and stops fetching, so both gates were opening on exactly the states they were meant to exclude. Scope the post-unpin focus handoff to this section by its own marker. The whole conversations pane is a labelled region too, and the project lists inside it render the same row, where unpinning only clears the flag and the row stays put, so focus was being moved off a row that never went away. Clear the account tracker when the mutation hook unmounts. The sidebar drops that section during a search, leaving a stale non-null id that also shadowed the cache fallback, so a deferred write could pass its owner check after a session change. * fix: gate pruning on a delivered favorites list A favorites fetch that exhausted its retries leaves isLoading false with the list empty, so an otherwise complete pinned load enabled pruning and dropped every favorite key from the stored order. useFavorites now exposes the query's success state and the pruning gate requires it, matching the pinned-order and pinned-membership sources. * fix: address eighth round of PR review bot findings Identify queued assignments by token rather than by destination. Comparing destination values cannot tell two drops onto the same project apart, so a B, A, B run let the first B's cleanup discard an entry the still-queued later drops owned, and the next drop was then judged against a stale project. Report the rename ending when a row unmounts. A pinned row removed mid-rename, for instance by unpinning the same chat from the project list that also renders it, left its key in the renaming set and came back permanently undraggable. * fix: address ninth round of PR review bot findings Stand the keyboard reorder down wherever the pointer drag does. Alt/Option plus an arrow moves the caret word-wise inside a text field, so the shortcut was moving and saving the whole row out from under an open rename input. Hold a settled assignment destination until a drag item shows the new project. The mutation's cache invalidations are not awaited, so a row still reported its old project for a moment after the write succeeded and a quick drag back to where it started read as a no-op. * fix: address tenth round of PR review bot findings Serialize project assignment inside the mutation instead of at one caller. The drag targets, the row menu and the project dialog each hold their own instance, so a queued drop could still overwrite a newer menu write; moving the queue down covers every surface and lets the drag helper drop its own. Tie the live snapshot's release to the arrangement that created it. An older write settling mid-drag cleared the newer arrangement, snapping the rows back to a stale order while the drag still held its own, so releasing saved an order the user could no longer see. * fix: address eleventh round of PR review bot findings Move assignment destination tracking next to the queue that owns it. Keeping it in the drag helper meant a menu or dialog move left the drag helper still reporting its own older destination, with no row left to observe that would ever clear it, so a later move back was rejected for good. Resolve a conversation's project from the write the mutation confirmed rather than from whichever list rendered the row. The same chat appears in the Pinned section and its expanded project, and those caches refresh independently, so observing one of them was never a sound way to decide the other had caught up. The conversation cache is written synchronously on success, which makes the lazy self-clearing and its settled flag unnecessary. * fix: cancel an in-flight conversation refetch before confirming an assignment Navigation invalidates the exact conversation query, so a refetch that read the old project can be in flight when an assignment resolves and land afterwards, reverting the move in the cache that now answers where a conversation lives. * fix: keep queued pinned-order writes attributable across an unmount Refuse a queued write only when a different account is positively established. Clearing the identity on unmount stopped stale attributions but stranded work that belonged to the same account, since the sidebar drops the section that owns this hook whenever a search is active, and it denied that work its rollback as well. Correct the cache from the request rather than from onError. The observer callbacks do not run once that section unmounts, so an order the server never accepted could survive on a query that refetches on nothing. * fix: publish the session identity from the user atom Queued pinned-order writes were attributed by a tracker that only the pinned section's hook updated, and the sidebar unmounts that section during a search. A retained value went stale across a sign-in, and login clears the user query before the next account's fetch resolves, so a write queued by the previous account could pass its own check and post on the new account's credentials. A Recoil atom effect publishes the identity instead: it runs wherever the atom is set, including sign-out, so attribution comes from the state itself rather than from a component that happens to be mounted. That makes a signed-out session foreign to every owner and lets the check be a strict comparison again, rather than a rule that had to guess when identity was merely unreadable. * fix: discard reorders that ended on a refused external target A drop the pinned rows did not handle usually means a reorder, but a project row or the Chats section refusing one reports the same, so dragging a chat onto the project it already belongs to was saving the incidental shift its pointer caused on the way out. The rows and those targets now report their hovers, so the last one under the pointer settles it, which also allows for a drag that strays over a project and returns to reorder after all. * fix: attribute queued writes to the credentials they will travel with Publishing the account from React state, whether an effect or a Recoil atom effect, always lagged the credential change: setUserContext installs the new Authorization header in one synchronous call, and a write queued by the previous account and sent in that gap read its own owner back and went out as the new one. A test against the atom effect showed onSet is deferred too, so the atom was no better than the effect it replaced. The header is the thing that decides who the server sees, so ownership is read from it. The id claim is compared rather than the token, since a silent refresh rotates the token for the same account and discarding that work would strand something the user is still entitled to. Leaves AuthContext and the user atom untouched. * fix: attribute a reorder to the account that started it onMutate awaits cancelQueries before the request is built, and the mutation function was reading the session again afterwards, so credentials turning over inside that gap sent one account's order as the next. The owner is now recorded in onMutate's first synchronous statement and carried on the order itself, and the optimistic write is skipped when the session moved on, since that cache is shared and showing an order to the wrong account is the same mistake as sending it. Record a pinned hover before the guards rather than after. Hovering the dragged row is a no-op for ordering but still means the pointer is inside the list, so a drag that wandered onto a project and returned to its own position was being discarded as a filing action. * fix: address a further round of PR review bot findings Mark a hover anywhere in the pinned section as internal. The header and the padding around the rows are part of the list, so a drag that wandered onto a project and came back to rest on one of them ran no row hover and was discarded as a filing action. Hold off pruning while a favorites write is unsettled. The earlier GET's success stands through an optimistic removal, so pruning then dropped the ordering key of a write that had not landed, and a failed one came back without its saved position. Declare the reorder shortcut on the elements that take focus. The section's written hint is skipped by anyone tabbing straight to a row, leaving the only non-pointer way to reorder undiscoverable. * fix: reach a real New Chat control, and let the shortcut prop through the memo The unpin fallback looked for a test id no component carries, so once the last pinned row unmounted focus fell to the document rather than to New Chat. It now tries the controls that exist, in sidebar order. The test that covered this had fabricated the missing id, so it proved nothing. Convo is memoized on conversation fields and isGenerating alone, so the shortcut appearing once the pinned order loaded never reached the element that announces it. The comparator now accounts for it. * fix: identify OpenID sessions, and see favorites writes from every hook With OpenID token reuse the bearer is the provider's own id_token, which names its subject as sub under an issuer and carries no LibreChat id, so every such session resolved to nobody and two different accounts compared equal. That is the case the ownership guard exists for, so it read as safe while being exactly wrong. Sessions are identified by whatever the credential offers now, and an owner that cannot be identified is foreign to everything including itself. Count favorites writes across the query client rather than from one observer. A favorite row runs its own useFavorites, so a removal started there was invisible to the pinned section and its ordering key could still be pruned. * fix: close the assignment cache gap, and let a failed drain be retried The assignment released its pending destination as soon as the request settled, while the cache write waited on an awaited cancellation in onSuccess. A drag started in that gap saw neither, fell back to the stale row and refused a valid drop. The write now happens in the request, before the entry is released, which also survives the owning component unmounting. Also clear the pagination guard when the Chats section collapses. A drain that exhausted its retries leaves the conversations array unchanged, so the guard barred every later attempt and the remaining chats stayed unreachable for the session. Reopening the section now tries once more. That guard came from #14860 rather than this branch, so it can be split out if preferred. * fix: compose the marketplace link, and keep focus on a surviving row The marketplace control was a raw link with restated appearance classes, and in restating them it left out the focus ring entirely, so keyboard focus on it was invisible. It composes through the shared button now, which carries the ring, the hover fill and the theme timing. Unpinning from a project list leaves the row in place but removes the pin badge that had focus, and the pinned-section successor search deliberately returns nothing there, so focus fell to the document. It moves to the row's own link. Reconcile the pinned order on window focus and reconnect. It is one shared per-user record, so a second tab would otherwise show a stale arrangement and its next reorder would post a full array undoing the other tab's. * fix: keep a rename from restoring a conversation's other fields A rename request carries only a title, but its response is the whole conversation as the server saw it, and writing all of that back restores the pre-request value of every other field. An assignment confirmed while the rename was in flight was therefore reverted in the cache that now answers which project a conversation belongs to, and a drag back to the original project read as a no-op. Only the title and its timestamp are taken from the response. Cancelling queries cannot help here, since this is another mutation's write rather than a fetch. * fix: compose the unpin badge through the shared row-action button The badge restated a reusable icon control's sizing, radius, hover and focus classes. The client package already had a row-action variant and an icon-xs size that match it exactly, so it uses those instead of its own copy. * fix: reconcile before reordering, and scope assignments to their session A reorder stayed enabled while the order's focus refetch was in flight, so returning to a tab could cancel that refetch and post the arrangement it was about to replace. Pruning had the matching gap: the pinned list keeps its data fresh for five minutes, so a tab whose order had reconciled could prune against membership that had not, dropping the position of a conversation another tab pinned. Both now wait for data that is settled and not stale. Assignments carry the account that started them, like the order writes already did. Conversation ids are per-user, so a queued one travelling with the next account's credentials would act on whatever that id names over there, and its answer would describe one account's conversation to another in a cache that is not scoped by user. The row's overflow trigger derives from the shared row-action variant too, so the two actions in a row stop keeping separate copies of the same recipe. * fix: reject foreign assignment results, and share the section header An assignment settling after a session change returned normally, so the success path still ran: the caller reported success and the response could be applied to the next account's conversation, since ids repeat across accounts. It rejects now, so nothing downstream treats it as a result. The collapsible section header existed as three identical copies, Chats, Projects and Pinned, and this branch added the third. It moves into the shared button as a section-header variant and all three compose from it. * fix: let favorites membership reconcile between tabs The favorites query disabled focus, reconnect and mount refetches, so a second tab kept its old list indefinitely. Its pruning gate waits for a fetch, and none was ever going to happen, so a reorder there could delete the saved position of a favorite the first tab had added. It reconciles on focus and reconnect now, like the order it is arranged alongside. * fix: hold reconciling refetches off while a write is in flight Enabling focus and reconnect refetches on the order and favorites queries let one start after onMutate's single cancellation, read the pre-write state and land after the write, putting the old value back. Both now decline those refetches while a write for that resource is outstanding, keeping the cross-tab reconciliation itself. The check asks the query client at the moment the event fires rather than reading useIsMutating: that hook only reaches the query's options on the next render, which is a race against the very event being gated. A test that dispatches focus mid-write fails without it. * fix: release abandoned assignments and gate pruning on current membership An assignment rejected before entering the try block kept its pending entry forever, so a later session read a destination that was never sent. The ownership check now sits inside the block that releases it, and it runs again after the conversation query cancellation resolves, since the session can turn over while that await is pending. Pruning the pinned order now requires membership at least as current as the order it is pruned against. The pinned query holds its data for five minutes while the order has no such window, so focusing a tab reconciled the order alone and the next reorder dropped the key of a conversation another tab had pinned in between. The assignment spec resets its mocks between tests and gives each test its own conversation id, so one test's unconsumed mock and leftover queue entries no longer decide the next test's result. * fix: address the sixth round of review findings on the pinned section The section header recipe asked for the shared button variant without a size, so CVA emitted the default `h-10 px-4` after it and the merge kept it, putting a 40px control in a 32px header row. The variant opts out of default sizing through a compound now, since a heading is sized by its own text. Restore the search field's focus border. Removing it left keyboard focus signalled only by a background change that hover already uses, so the field had no distinguishable focus state at all. An assignment can reach the database before a concurrent rename and still answer after it, carrying a conversation that predates the rename. Only the project field is merged into the cached conversation and published to the active one now, matching what the rename handler already does. An order refetch that starts mid drag no longer lets the drop post an array built from the order that refetch is about to replace: the arrangement is held and written once the fresh order lands. Reorder writes superseded by a newer arrangement are skipped rather than sent, so holding the shortcut costs two writes instead of one per intermediate position. The order and favorites queries reconcile on mount as well, since a sidebar search unmounts the section and a query with no observer never sees the focus event. * fix: preserve pinned order until favorites membership catches up * fix: reconcile pinned membership and preserve auth and focus state * fix: preserve reconciled keys during active pinned arrangements * style: sort pinned order regression imports * fix: reconcile favorite rollbacks before pinned-order pruning
* 🧊 fix: Withhold Rerun Controls on Compaction Turns A compaction turn's response parents onto the leaf it summarized, not onto a user message, so the hover Edit's Rerun replayed an assistant message in the user slot: the request minted a user message under the existing assistant leaf's id and ran the turn with empty text, which fails. Editing offered nothing either, since SUMMARY is not an editable part type. Edit, Regenerate and Continue are now withheld on a compaction turn, and both rerun paths refuse a parent that is not user-created, matching the guard `useChatFunctions.regenerate` already applied. * 🧭 fix: Gate Rerun Controls on the Replayed Parent Turn Withholding Edit, Regenerate and Continue on summary-only content also hit an ordinary turn that auto-summarized and was cancelled before its first answer token: that response is parented to the user's message and is exactly the turn a rerun is for. The row now resolves the message it would replay and withholds the rerun shapes only when a model turn hangs off another model turn, which is the manual compaction shape. An unresolvable parent withholds nothing. `isCompactionTurn` is gone with it, and `isCompactedLeaf` keeps its original body; its docstring now says per part what it always measured per part. * 🧮 fix: Identify a Compaction Turn by Content and Parent Gating the rerun controls on parent authorship alone withheld Edit, Regenerate and Continue from any model turn hanging off another model turn. An imported conversation chains messages sequentially, so a skipped empty human message leaves an ordinary reply parented to the previous reply; its stored content is editable and its controls must stay. It also made every model row resolve its parent out of the flat message list: 100 full-thread scans while mounting a 200-message conversation. A manual compaction is now both halves of its shape — summary-only content and a parent that is not the user's turn — so only such a row consults the thread. `isSummaryOnlyContent` is the content half, in data-provider next to `isCompactedLeaf`. * 🧷 test: Pin the Rerun Refusal on a Chained Model Turn A rerun replays its parent as the user turn, so a model turn parented onto another model turn must submit nothing rather than mint a user message under an existing response's id. Removing the guard makes the case call `ask` once. * 🧱 fix: Gate the Editor on Content and the Rerun on the Parent Identifying a compaction turn by content shape missed the ones the server persists with an error part (a skipped or failed compaction keeps its explanation instead of a summary), which left Edit, Regenerate and Continue on a turn where every rerun shape is inert. The two controls answer two different questions now. A rerun replays the message's parent as the turn's user message, so Regenerate and Continue go whenever a model turn hangs off a model turn. The editor goes only when that turn also has no part to type in: an imported chain's reply is saved directly and stays editable, while a compaction — summary or error part — would open an empty editor with one inert Rerun. `findMessageById` indexes the messages array once per identity, so resolving the parent no longer scans the thread per row: 100 full-array walks while mounting a 200-message conversation become one. * 🏷️ fix: Honor the Server's Compaction Marker on Any Leaf Compact runs on whatever leaf the branch ends with, so a compaction can hang off a user message rather than off the answer it summarized. Inferring the turn from its position alone left the rerun controls on that one: replaying the parent would answer the user's earlier message again instead of redoing the compaction. `isUserInitiatedCompaction` reads the marker the server already stamps — `markCompactionSummary` sets `initiatedBy: 'user'`, and nothing else writes it, so an automatic summary detour keeps its controls. A marked turn is excluded from the rerun shapes wherever it hangs. * 🎨 fix: Ask the Editor What It Can Edit The hover row had its own idea of an editable part and counted artifact-bearing text as one, while `EditContentParts` keeps an artifact in its read-only renderer. A chained model turn whose only content is an artifact therefore still offered Edit, and opening it gave a read-only artifact, a disabled Save and a Rerun the guards refuse. `editableParts.ts` now owns that rule for both: `isEditablePart` is the editor's own filter, `hasEditablePart` asks it per message. The row resolves it lazily — the artifact check parses markdown, and only a turn with nothing to replay needs the answer — so a streaming row never pays for it. * 🚫 fix: Withhold the Editor's Rerun Instead of Refusing It Both editors resolved the parent inside the handler and returned when it was not a user turn, so a chained model turn — an imported thread with no user message between two replies — kept an enabled Rerun that did nothing, with Ctrl/Cmd+Enter bound to it. Each editor resolves that parent at render and withholds the action instead: the button is gone, the shortcut is inert and `aria-keyshortcuts` no longer advertises it, while Save keeps writing the edit. An unresolvable parent keeps the action, matching the hover row. * 🧹 style: Sort the New Imports in Both Editors CI's import-sort check failed on the two files the previous commit touched. * 💬 fix: Report Unsaved Changes When No Rerun Is Offered A save-only editor still warned about the rerun. An answer's draft is discarded by the rerun, and multi-part edits must be saved before one, but neither is true where the action is withheld — a model turn chained onto another model turn — so the status slot claimed a precondition for something the footer does not offer. Both statuses are gated on the same `canRerun` the button is: the plain-text editor reports unsaved changes, and `rerunRequiresSave` cannot hold without a rerun to require it. * 🧪 test: Exercise the Compaction Controls in the Browser Eight mock-harness scenarios drive the real row and the real editors: a finished, failed, error-part and user-parented compaction withhold Edit, Regenerate and Continue while Copy stays; a turn that only auto-summarized keeps all three; a reply chained onto a reply keeps a save-only editor whose status reports unsaved changes; an artifact-only chained reply loses the editor; and the context indicator still offers Compact after a failed compaction. `SeedMessage` carries `content`, `finish_reason` and `model` so a branch can be seeded in the shapes the mock model cannot produce — a persisted summary, an error part, an artifact.
* feat(insights): improve agent filter controls * feat(insights): add search and fixed agent selection controls * fix(insights): show search before all agents control * test(e2e): allow steer consumption before arm response
* fix: Use artifact titles for download filenames * fix: Match artifact filenames to downloaded content * fix: Preserve raw artifact extensions and GFM headings * fix: Download complete artifact files and retain filename provenance * fix: Distinguish cached artifact exports from originals * fix: Name unnamed artifact originals by their media type * fix: Recognize legacy CSV MIME in artifact filenames
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )