Skip to content

feat: in-session search with Cmd+F, keyboard nav, and resync perf fix#157

Merged
wesm merged 17 commits intowesm:mainfrom
MCBoarder289:search-within-session
Mar 15, 2026
Merged

feat: in-session search with Cmd+F, keyboard nav, and resync perf fix#157
wesm merged 17 commits intowesm:mainfrom
MCBoarder289:search-within-session

Conversation

@MCBoarder289
Copy link
Copy Markdown
Contributor

@MCBoarder289 MCBoarder289 commented Mar 12, 2026

Addresses #156. Adds find-in-session with backend search, inline
highlighting, and keyboard navigation. Also fixes a resync
performance regression found during testing.

Search

  • Find bar opens via Cmd+F, / key, or the breadcrumb search icon
  • Backend endpoint queries messages by session ID, returns matching
    ordinals
  • Matches highlight across text, code, thinking, and tool output
    blocks with a current-match indicator
  • Keyboard navigation: Enter/Shift+Enter from the input,
    Cmd+G/Cmd+Shift+G globally while the find bar is open, Esc to
    close
  • Auto-expands collapsed thinking/tool blocks when they contain
    matches; restores user collapse state when search ends
  • Reactively refreshes results when session content changes
    (streaming), preserving the user's current match position

Resync perf fix

  • Add missing index on tool_calls.subagent_session_id
    LinkSubagentSessions was doing a full table scan per session
    during resync, taking 327s on a 15K session / 575K message
    dataset. Now completes in under 1s. Total resync dropped from
    9+ minutes to ~37 seconds.

Test plan

  • Open a session, press Cmd+F or /, verify find bar appears
  • Type a query, verify matches highlight and counter updates
  • Navigate with Enter, Shift+Enter, Cmd+G, Cmd+Shift+G
  • Verify collapsed thinking/tool blocks auto-expand on match
  • Close find bar, verify blocks return to previous collapse state
  • Run agentsview sync --full and verify resync completes in
    under a minute

@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 12, 2026

roborev: Combined Review (9870aac)

Summary verdict: The
PR introduces a functional in-session search, but contains a few medium-severity state and logic bugs related to progressive loading, background reloads, and markdown highlighting.

Medium

  • Incomplete search scope due to progressive loading (frontend/src/lib/stores/inSessionSearch.svelte.ts :17)
    The search store only scans messages.messages. Since large sessions are intentionally only partially loaded at first, the find bar can return "No results" for older matches and has no way to navigate to them.
    Suggested fix: Make the search session-wide instead of loaded-window
    -only, or explicitly page/search older messages before declaring no matches.

  • Search state resets on message load (frontend/src/lib/stores/inSessionSearch.svelte.ts:36)
    Every time messages.messages changes, the effect rebuilds matches, resets currentMatch Index to 0, and immediately scrolls to the first hit. Consequently, loadOlder() or background reloads will yank the user back to the first match and lose their place mid-search.
    Suggested fix: Preserve the current match if its ordinal still exists after recomputing, and only auto-jump on
    a new query or session change.

  • Raw match vs. rendered highlight mismatch (frontend/src/lib/stores/inSessionSearch.svelte.ts:28, frontend/src/lib/components/content/MessageContent.svelte:131, frontend/src/lib /components/content/MessageContent.svelte:276)
    Matching is done against raw msg.content (raw markdown), but highlighting is only applied inside rendered text segments. Queries that hit markdown syntax (e.g., URLs, HTML attributes, code blocks, or hidden content) will still
    be counted as matches in the nav counter, but the user may see no visible highlight and, in some cases, no usable navigation target.
    Suggested fix: Derive matches from the same visible/rendered segments you highlight, or match against a stripped/plain-text version of the messages in the store.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@MCBoarder289
Copy link
Copy Markdown
Contributor Author

This is a pretty solid review with some good feedback for me to iterate on. Let me work on some updates.

@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 12, 2026

roborev: Combined Review (62beb45)

Summary: The in-session search feature introduces a high-severity Svelte reactivity bug during text
streaming, alongside several medium-severity state and content-model mismatches between the frontend and backend search implementations.

High

  • frontend/src/lib/components/content/CodeBlock.svelte, ThinkingBlock.svelte, ToolBlock.svelte
    The applyHighlight action
    splits text nodes to insert <mark> elements. For components using plain Svelte text interpolations ({content}), Svelte retains references to the original text nodes for fine-grained updates. During streaming, Svelte updates the now-detached text nodes, causing the visible content to freeze and drop new incoming text.

    Suggested fix: Prevent Svelte from retaining text node references by replacing {content} with {@html escapeHTML(content)} (or a similar sanitization utility) in these components, which forces Svelte to fully reset the container's innerHTML on updates.

Medium

  • **
    frontend/src/lib/stores/inSessionSearch.svelte.ts:22-43**
    The search effect only refetches when query changes. If the user keeps the same query open and switches to another session, messages.sessionId changes but queryChanged is
    false, so the store keeps stale matches from the previous session. next()/prev() will then navigate using old ordinals/session IDs.
    Suggested fix: Key the fetch off both query and sessionId (or clear/refetch whenever sessionId changes). Add a store/component test
    that switches sessions with the find bar open.

  • internal/db/search.go:114-119
    The new endpoint searches raw messages.content with LIKE, even though the UI highlights rendered/plain text. That means queries can match markdown syntax the
    user never sees, such as link URLs or formatting markers. The diff adds stripMarkdown() tests, but the endpoint never uses an equivalent normalization step, so users can land on a message with no visible highlight.
    Suggested fix: Search a normalized plain-text representation on the backend (ideally pre
    computed/indexed), and add tests for links/images/formatting cases.

  • internal/db/search.go:114-119, frontend/src/lib/components/content/ToolBlock.svelte:24-31
    The frontend now auto
    -expands and highlights toolCall.result_content, but the backend query only scans messages.content. Any match that exists only in tool output will never be returned by /sessions/{id}/search, making part of the new "search tool blocks" behavior unreachable.
    Suggested fix: Include
    tool_calls.result_content in the searchable corpus (join or index a derived searchable text field) and add an integration test with a result-only hit.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@MCBoarder289
Copy link
Copy Markdown
Contributor Author

My latest commits that I've pushed should address most of the constructive feedback from roborev's initial review.

The biggest change is that I implemented some backend changes as well, so that it leverages sqlite for the searching vs. bringing the session in memory as before. There are also some minor UI improvements on finding matches in collapsable blocks (tool inputs/outputs, thinking blocksnow automatically expand when they contain a search match) and highlighting formatted text.

Specific items that were addressed:

  • Search state no longer resets when messages reload (background refresh, loadOlder()) — previously it would snap back to the first match mid-navigation
  • Matching is now against plain text, not raw markdown — so queries like "import" won't ghost-match inside hidden markdown syntax (URLs, ** markers, etc.)

Because these new updates added more scope, I added tests for the new BE endpoint and FE updates:

  • Backend tests (DB + HTTP handler)
  • Frontend unit tests (stripMarkdown + applyHighlight)

... and as I typed all this, saw roborevs review come back in. Will check that out too and see if anything needs adjusting.

@MCBoarder289
Copy link
Copy Markdown
Contributor Author

Last push to address some of those feedback items, and then I'll probably wait for others to chime in maybe. I appreciate these automated reviews and hope it eases the load here 🙂

  • Regarding the streaming freeze issue, block components (CodeBlock, ThinkingBlock, ToolBlock) now use {@html escapeHTML(content)} instead of {content}, so Svelte resets innerHTML on update rather than patching a text node that applyHighlight has already split. Added a streaming-simulation test for this.

  • For the Session switch with same query issue, the store was only re-fetching when the query string changed, not when the session changed. Fixed by tracking prevSessionId alongside prevQuery.

  • Added in the tool result_content. The backend search now includes tool output in the searchable corpus, so matches inside collapsed tool blocks actually show up in the counter.

Open to any feedback as usual!

@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 12, 2026

roborev: Combined Review (d989305)

Verdict: The PR successfully implements in-session search and highlighting, but introduces a major search gap with tool arguments, stale results during live reloads, and backend/frontend mismatches when searching markdown content.

High

  • internal/ db/search.go:121: The SQL WHERE clause checks m.content and tc.result_content but ignores tool call arguments. Users cannot search for commands or parameters sent to tools (e.g., shell scripts), creating a major feature gap.
    Suggested
    fix
    : Add the arguments column (e.g., OR tc.arguments LIKE ? ESCAPE '\') to the SQL LIKE conditions.

Medium

  • internal/db/search.go:18 & frontend/src/lib/utils/markdown.ts:1: Backend
    matching runs against raw markdown (m.content), while the UI only highlights visible rendered text. This produces confusing false positive "ghost" matches where search returns a message but nothing visible is highlighted (e.g., matching a URL hidden inside an href). Additionally, the newly added stripMarkdown() function is unused dead
    code.
    Suggested fix: Remove the unused stripMarkdown code, search against the same stripped plain-text representation in the backend to align with visual highlights, and add integration coverage for links/emphasis cases.

  • frontend/src/lib/stores/inSessionSearch.svelte.ts: 23: The search store only refetches when query or messages.sessionId changes. If the active session reloads or streams new content while the find bar stays open, matches and currentMatchIndex are left stale even though messages.reload() keeps updating the session. This
    means the counter/navigation can miss new hits or point at ordinals that no longer match.
    Suggested fix: Make the effect depend on a message-version signal as well (for example, message count or reload generation), and add a store test for “query open + session reload”.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@MCBoarder289
Copy link
Copy Markdown
Contributor Author

MCBoarder289 commented Mar 12, 2026

Removing the vestigial markdown parsing logic after refactoring the search to happen on the backend instead of the original approach that was frontend only. I think this is at a good state with known limitations on edge cases that I think are lower priority.

@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 12, 2026

roborev: Combined Review (cc78891)

Summary: The changes implement the in-session search feature securely, but introduce functional bugs related to stale search results during active sessions and
mismatches between backend search and UI rendering.

Medium

  • Stale results within the same session: In frontend/src/lib/stores/inSessionSearch.svelte.ts (lines 23-45), the search effect only refetches when query or messages.sessionId changes. If the active session streams new content or reloads in place, the match list never refreshes, so the counter and next/prev navigation can point at outdated ordinals. Suggested fix: Invalidate/refetch on a same-session content/version change as well, and preserve the current ordinal when
    recomputing matches.
  • Backend search does not match visible UI text: internal/db/search.go (lines 121-126) searches raw messages.content plus tool_calls.result_content only, while the frontend highlights rendered markdown text in frontend /src/lib/components/content/MessageContent.svelte and can display synthesized tool input text from input_json in frontend/src/lib/components/content/ToolBlock.svelte. This creates false positives for invisible raw markdown/control syntax and false negatives for visible fallback tool params.
    Suggested fix: Search a normalized "visible text" representation server-side, or share the same parsing/plain-text extraction logic between backend search and frontend rendering.

Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@MCBoarder289
Copy link
Copy Markdown
Contributor Author

MCBoarder289 commented Mar 13, 2026

Hey @wesm, I'm thinking this PR is in a good spot for a human review or discussion. What are your thoughts on adding a feature like this?

@wesm
Copy link
Copy Markdown
Owner

wesm commented Mar 14, 2026

I will review in the next couple of days! Treading water trying to keep up with the flow of PRs

MCBoarder289 and others added 13 commits March 15, 2026 07:59
   Press / or click the search icon in the breadcrumb to open a search bar
   that searches within the currently-displayed session. Matches are
   highlighted inline with prev/next navigation and a live match counter.
   Press Escape to close.

   Closes wesm#156

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix 2: preserve current match ordinal when messages reload or
  loadOlder fires. Only reset to first match when the query itself
  changes. Prevents background reloads from yanking the user back
  to the start of their search.

- Fix 3: match against stripMarkdown(content) instead of raw markdown.
  Queries no longer spuriously match URLs inside [text](url), HTML
  attributes, or bare markdown syntax characters that are invisible
  in the rendered output. Adds stripMarkdown() to markdown.ts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Extract applyHighlight Svelte action to shared highlight.ts utility
- Pass highlightQuery/isCurrentHighlight props to CodeBlock, ToolBlock,
  ThinkingBlock from MessageContent
- CodeBlock: apply highlight to pre>code element
- ThinkingBlock: apply highlight to content div; auto-expand when a
  match exists in the block
- ToolBlock: apply highlight to all pre content areas (input, task
  prompt, fallback, output); auto-expand input/output sections when
  they contain a match

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add GET /api/v1/sessions/{id}/search?q=... which queries all messages
for the session using LIKE substring matching (consistent with browser
Cmd+F semantics), returning matching ordinals in document order.

The in-session search store now calls this endpoint instead of scanning
the in-memory message window, making find-in-session work across the
entire session regardless of how many messages are loaded. Navigation
uses ensureOrdinalLoaded() to fetch pages on demand when jumping to
matches outside the current viewport.

Changes:
- db.SearchSession(): LIKE query scoped to session_id, ordered by ordinal
- GET /api/v1/sessions/{id}/search handler
- api/client.ts: searchSession() function
- inSessionSearch store: debounced API fetch, proper abort on new query,
  loading state, ensureOrdinalLoaded before scroll
- SessionFindBar: show '...' counter while loading, suppress 'No results'
  during pending fetch
- Tests: TestSearchSession (db layer, 12 cases) and
  TestHandleSearchSession (HTTP handler, 7 cases)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- stripMarkdown: 23 cases covering links, images, bold/italic,
  headings, blockquotes, inline/fenced code, HTML tags, mixed content
- applyHighlight: 14 cases covering single/multiple matches,
  case-insensitivity, empty query, current-class toggling,
  nested elements, and update/clear lifecycle

Closes wesm#156

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fix 1 (streaming text node freeze): applyHighlight splits text nodes to
insert <mark> elements. When Svelte uses fine-grained text node updates
({content}), it retains the original node reference — which becomes
detached after splitting, causing visible content to freeze mid-stream.

Fix: add escapeHTML() to highlight.ts and switch all block components
(CodeBlock, ThinkingBlock, ToolBlock) to {@html escapeHTML(content)},
forcing Svelte to replace innerHTML on update rather than patch a
retained text node. applyHighlight.update() then re-marks the fresh DOM.

Fix 2 (stale matches on session switch): the store only refetched when
query changed, not when sessionId changed. Switching sessions with the
same query active left stale ordinals from the previous session in the
match list. Fix: track prevSessionId alongside prevQuery and trigger
re-fetch when either changes.

Add escapeHTML unit tests (7 cases) and a streaming-simulation test
that verifies applyHighlight survives an innerHTML reset.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The backend SearchSession query now LEFT JOINs tool_calls so that a
match in result_content surfaces the parent message ordinal. DISTINCT
collapses multiple tool calls on the same message into a single result.

Previously a query that matched only inside tool output would return
zero results from the API, even though the frontend would auto-expand
and highlight it once the message was loaded.

Added three new test cases:
- match in tool result_content only (message content has no match)
- tool result match scoped to correct session (no cross-session bleed)
- message not double-counted when both content and result match

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
stripMarkdown was written for an in-memory matching approach that was
replaced by the backend SQLite search endpoint.

Removes the function and its 23 unit tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Refetch search results when messageCount changes so streamed
  content updates the match list while a query is active
- Separate search-driven expansion from user-controlled collapse
  state in ThinkingBlock and ToolBlock so closing/changing the
  search query restores the original collapsed state
- Fix $derived(() => ...) to $derived.by(() => ...) in
  SessionFindBar so the counter text reactively updates on
  next/previous navigation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LinkSubagentSessions performs a correlated subquery joining
sessions to tool_calls on subagent_session_id. Without an
index, this is O(sessions × tool_calls) — 327 seconds on a
15K session / 575K message dataset. Adding a partial index
drops resync from 9+ minutes to ~37 seconds.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Content-only refreshes (messageCount change) preserve the
  current match position instead of resetting to the first hit
  and scrolling away from the user's location
- Click handlers toggle userCollapsed/userOutputCollapsed
  independently so user expand/collapse choices are recorded
  correctly even when search-driven expansion is active

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Intercept Cmd+F to open in-session find when a session is
  active, preventing the browser's native find from opening
- Add Cmd+G / Cmd+Shift+G for next/prev match navigation
  while the find bar is open
- Bump counter min-width from 52px to 72px to prevent layout
  shift when "No results" text is displayed
- Update shortcuts modal to show Cmd+F alongside /

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- When preservePosition is active and the previously selected
  match ordinal no longer exists in refreshed results, fall
  back to scrolling to the first match instead of silently
  pointing at index 0 without scrolling
- Gate Cmd+F behind ui.activeModal check so it does not
  suppress the browser's native find when a modal is open
- Gate Cmd+G behind modal and input-focus checks, allowing it
  only from the find input itself or when no input is focused

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@wesm wesm force-pushed the search-within-session branch from cc78891 to f0401a8 Compare March 15, 2026 18:36
@wesm wesm changed the title feat: add in-session search bar feat: in-session search with Cmd+F, keyboard nav, and resync perf fix Mar 15, 2026
Gate both shortcuts on router.route === "sessions" so they
only fire when the session view is active. Also apply the
isFindInput() exception to Cmd+F so it does not suppress
native browser find from unrelated inputs like the sidebar
typeahead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 15, 2026

roborev: Combined Review (f0401a8)

Summary Verdict: The in-session search functionality is generally
sound from a security perspective, but introduces several medium-severity issues regarding state management and search/highlighting mismatches.

Medium

  • Stale matches during pending searches
    In frontend/src/lib/stores/inSessionSearch.svelte.ts, the queryChanged/sessionChanged/ contentChanged branch schedules a debounced fetch but does not clear matches or currentMatchIndex first. This allows the counter and navigation (Enter/Cmd+G) to use the previous query's ordinals during the debounce window, or indefinitely if the new request fails.
    Suggested fix:
    Clear the active result set immediately when invalidating a search, and only restore the position after the replacement results arrive successfully.

  • Search semantics mismatch (raw markdown vs. rendered text)
    [internal/db/search.go](/home/roborev/.roborev/clones/
    wesm/agentsview/internal/db/search.go) searches raw markdown (m.content LIKE ?), while [frontend/src/lib/components/content/MessageContent.svelte](/home/roborev/.roborev/clones/wesm/agentsview/frontend/src/lib/
    components/content/MessageContent.svelte) highlights the rendered DOM. Queries matching only markdown syntax or link destinations will return an ordinal with no visible highlight in the UI.
    Suggested fix: Search the same plain-text representation the renderer exposes, or store a normalized plain-text column for session search.

  • Matches inside hidden blocks are unreachable
    In frontend/src/lib/components/content/MessageContent.svelte, thinking/tool/code segments are gated by ui.isBlockVisible(...), but the backend match set includes those segments. If a user hides a block type, the
    find bar can scroll to a message with no visible current hit.
    Suggested fix: Either force-show matching hidden segments while find is active, or exclude hidden segment types from the backend search.


Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

wesm and others added 3 commits March 15, 2026 13:52
- Clear matches immediately on query/session change during debounce
- Force-show hidden block types when search query is active
- Thread search props through ToolCallGroup to child ToolBlocks
- Add userOverride pattern so manual collapse takes effect during search
- Filter system messages and search tool input_json in session search

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Only reset userOverride when highlightQuery changes, not on
  content updates during streaming
- Include input_json in ToolBlock expand check so backend matches
  in tool parameters are reachable
- Set loading=true immediately when scheduling debounce to avoid
  transient "No results" flash during keystroke debounce window

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend search only covers fields the frontend renders and highlights
(message content and tool-call result_content). Searching raw input_json
produced matches that expanded the tool block but had no visible
highlighted text, confusing users.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@roborev-ci
Copy link
Copy Markdown

roborev-ci bot commented Mar 15, 2026

roborev: Combined Review (131434f)

Summary Verdict: The PR successfully implements an in-session find feature and backend search, but contains medium-severity issues related to search text-model mismatches and keyboard shortcut scoping.

Medium

  • Search Text-Model Mismatch (Hidden Markdown)

    • Files:
      internal/db/search.go (lines 124-133)
    • Details: SearchSession searches raw m.content, but the UI highlights rendered/plain-text content. Markdown-only text that is not visible (e.g., link destinations like
      example.com in [label](https://example.com)) can still produce matches that the frontend cannot highlight.
    • Suggested Fix: Search a normalized plain-text representation that matches what the user can actually see, and add a test for hidden markdown content.
  • Unsearchable Fallback Tool
    Text

    • Files: internal/db/search.go (lines 126-133), frontend/src/lib/components/content/ToolBlock.svelte (lines 166-170, 220-225),
      frontend/src/lib/utils/content-parser.ts (lines 428-466)
    • Details: The removal of input_json from session search prevents phantom matches, but makes visible fallback tool text (derived from input_json for structured-only
      tool calls) unsearchable.
    • Suggested Fix: Search the derived fallback string the UI actually renders instead of raw input_json, and add test coverage for a structured-only tool call whose only visible text comes from fallback rendering.
  • Keyboard Shortcut Scoping

    • Files:
      frontend/src/lib/utils/keyboard.ts
    • Details: The !isInputFocused() condition prevents Cmd+F and Cmd+G from triggering the custom session search when focus is in the main chat composer. This causes the browser's native find to open
      instead, which silently fails to search the virtualized message list.
    • Suggested Fix: Remove the !isInputFocused() check for the f and g shortcuts (or specifically exclude the main composer) so the custom find bar reliably opens while typing.

Synthesized from 3 reviews (agents: codex, gemini | types: default, security)

@wesm
Copy link
Copy Markdown
Owner

wesm commented Mar 15, 2026

"Here's my assessment of each finding:

  1. Hidden Markdown mismatch — Not applicable. This app renders message content as preformatted
    text (

     with white-space: pre-wrap), not as rendered HTML markdown. Markdown syntax like
    label is displayed verbatim, so the URL IS visible to the user and a search
    match on it would be highlighted correctly.

  2. Unsearchable fallback tool text — This is a real gap but the correct fix (storing a derived
    display_content column on tool_calls, populated during sync) is a schema change that's out of
    scope for this PR. The gap only affects structured-only tool calls from non-Claude agents where
    m.content is empty and the only visible text comes from fallbackContent derived client-side from
    input_json. The vast majority of searchable content is covered by m.content + tc.result_content.
    I'd note this as a known limitation.

  3. Keyboard shortcut scoping — Not applicable. Agentsview is a read-only session viewer — there is
    no "main chat composer" input. The only inputs are the sidebar search filter and the find bar
    itself. The !isInputFocused() || isFindInput() guard is correct: it lets Cmd+F work from the find
    bar (re-focus) while preserving native browser find in the sidebar search input where custom
    session search doesn't make sense."

I think this is good enough to merge.

@wesm wesm merged commit 861fa01 into wesm:main Mar 15, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants