Skip to content

feat(desktop): add QuantLab desktop shell prototype#190

Merged
Whiteks1 merged 2 commits intomainfrom
codex/quantlab-desktop-shell
Mar 27, 2026
Merged

feat(desktop): add QuantLab desktop shell prototype#190
Whiteks1 merged 2 commits intomainfrom
codex/quantlab-desktop-shell

Conversation

@Whiteks1
Copy link
Copy Markdown
Owner

@Whiteks1 Whiteks1 commented Mar 27, 2026

Summary

This PR introduces the first QuantLab Desktop shell as a focused prototype.

It adds:

  • an Electron-based desktop app under desktop/
  • automatic startup of research_ui/server.py from the desktop main process
  • a chat-centered command bus
  • a command palette and runtime strip
  • context tabs for Launch, Runs, Compare, and Paper Ops

Why This Exists

QuantLab already has useful local surfaces, but they are still fragmented across browser flows and manual process management.

This block starts moving the product toward a single desktop workspace by:

  • giving QuantLab one entry point
  • reusing the existing research_ui instead of rewriting too much at once
  • creating the first shell for chat + tabs + runtime visibility

What This Block Delivers

  • One desktop entry point instead of multiple browser windows.
  • A first shell with sidebar + chat + tabs + runtime strip.
  • Embedded reuse of the current research_ui surfaces.
  • Deterministic local commands like open runs, open compare, open latest run, and show runtime status.

Out Of Scope

This PR does not try to do all of QuantLab Desktop at once.

Still out of scope:

  • full AI reasoning inside the desktop chat
  • deep Stepbit delegation from the shell
  • a rewritten native run explorer or compare surface
  • replacing research_ui

Files Of Interest

  • desktop/main.js
  • desktop/preload.js
  • desktop/renderer/index.html
  • desktop/renderer/app.js
  • desktop/renderer/styles.css
  • desktop/README.md
  • docs/quantlab-desktop-v1.md

Validation

  • npm install in desktop/
  • npm exec electron -- --version
  • node --check desktop/main.js
  • node --check desktop/preload.js
  • node --check desktop/renderer/app.js
  • python -m pytest test/test_research_ui_server.py

Notes

This is intentionally a v0 shell.

The goal is not to finish QuantLab Desktop in one PR, but to establish the first desktop foundation so the next blocks can add:

  • smarter chat actions
  • tighter runtime management
  • richer tab behavior
  • optional Stepbit-powered reasoning without making Stepbit the shell

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai bot commented Mar 27, 2026

Reviewer's Guide

Adds an initial Electron-based QuantLab Desktop shell that auto-starts the existing research_ui server, exposes a chat-centric command bus, and embeds Launch/Runs/Compare/Paper Ops as tabs with a runtime status strip, plus documentation on how to run and position this prototype.

Sequence diagram for QuantLab Desktop startup and research_ui server integration

sequenceDiagram
    participant OS
    participant ElectronApp as Electron_app
    participant Main as Electron_main_process
    participant Window as BrowserWindow_renderer
    participant Preload as Preload_bridge
    participant ResearchServer as research_ui_server.py

    OS->>ElectronApp: user runs npm start (electron .)
    ElectronApp->>Main: initialize main.js

    Main->>Main: createMainWindow()
    Main->>Window: new BrowserWindow(preload=preload.js, index.html)
    Window->>Preload: load preload.js
    Preload->>Window: expose window.quantlabDesktop API

    Main->>Main: startResearchUiServer()
    Main->>ResearchServer: spawn(python, server.py)
    Main->>Main: workspaceState.status = starting
    Main-->>Window: IPC quantlab:workspace-state(status=starting)

    ResearchServer-->>Main: stdout "URL: http://localhost:PORT"
    Main->>Main: extractServerUrl(line)
    Main->>Main: workspaceState.status = ready
    Main->>Main: workspaceState.serverUrl = discoveredUrl
    Main-->>Window: IPC quantlab:workspace-state(status=ready, serverUrl)

    Note over Window: Renderer setup after DOMContentLoaded
    Window->>Preload: window.quantlabDesktop.getWorkspaceState()
    Preload->>Main: IPC quantlab:get-workspace-state
    Main-->>Preload: workspaceState
    Preload-->>Window: workspaceState

    Window->>Window: renderWorkspaceState()
    Window->>Preload: window.quantlabDesktop.onWorkspaceState(callback)

    alt serverUrl present
        Window->>Preload: window.quantlabDesktop.requestJson("/outputs/runs/runs_index.json")
        Preload->>Main: IPC quantlab:request-json(relativePath)
        Main->>ResearchServer: HTTP GET serverUrl + relativePath
        ResearchServer-->>Main: JSON runs_index
        Main-->>Preload: runs_index JSON
        Preload-->>Window: runs_index JSON
        Window->>Window: update snapshot, runtime strip, tabs
    end

    OS-->>ElectronApp: app close signal
    ElectronApp->>Main: before-quit
    Main->>Main: stopResearchUiServer()
    Main->>ResearchServer: kill()
Loading

Sequence diagram for chat command handling and tab opening

sequenceDiagram
    actor User
    participant Renderer as Renderer_app.js
    participant Preload as Preload_bridge
    participant Main as Electron_main_process
    participant ResearchUI as Embedded_research_ui_iframe

    User->>Renderer: type "open runs" in chat and submit
    Renderer->>Renderer: handleChatPrompt(prompt)
    Renderer->>Renderer: pushMessage(role=user, content=prompt)
    Renderer->>Renderer: normalized = prompt.toLowerCase()

    alt prompt matches "open runs"
        Renderer->>Renderer: openResearchTab(kind=runs, title=Runs, hash="#/")
        alt workspaceState.serverUrl not set
            Renderer->>Renderer: pushMessage(assistant, "surface is still starting")
        else serverUrl ready
            Renderer->>Renderer: id = "runs:#/"
            Renderer->>Renderer: check existing tab
            Renderer->>Renderer: state.tabs.push({ id, kind, title, url })
            Renderer->>Renderer: state.activeTabId = id
            Renderer->>Renderer: renderTabs()
            Renderer->>Renderer: pushMessage(assistant, "Opened the run explorer.")
            Renderer->>ResearchUI: create iframe src="{serverUrl}/research_ui/index.html#/"
        end
    else other deterministic command
        Renderer->>Renderer: route to openResearchTab / openLatestRunTab / summarizeRuntimeInChat
    else unknown command
        Renderer->>Renderer: pushMessage(assistant, deterministic help message)
    end

    User->>Renderer: click "Open In Browser"
    Renderer->>Preload: window.quantlabDesktop.openExternal(serverUrl + "/research_ui/index.html#/")
    Preload->>Main: IPC quantlab:open-external(url)
    Main->>Main: shell.openExternal(url)
Loading

File-Level Changes

Change Details Files
Introduce Electron desktop shell that launches and manages the research_ui server process and exposes workspace state to the renderer via IPC.
  • Add Electron main process that spawns research_ui/server.py using a best-effort Python resolver and tracks workspace status, URL, logs, and errors.
  • Stream and parse server stdout to detect the served URL, update workspace status to ready, and broadcast state changes to the renderer.
  • Handle child-process exit and error events to reflect stopped/error states and retain recent logs for visibility.
  • Expose IPC handlers for getting workspace state, fetching JSON from the running server with relative paths, and opening external URLs in the system browser.
  • Wire Electron app lifecycle to create the main window on ready/activate, and to stop the research server on app quit.
desktop/main.js
Expose a minimal, hardened renderer API and implement a chat-centered desktop UI that embeds existing research_ui surfaces as tabs and shows runtime status.
  • Bridge a small quantlabDesktop API into the renderer context for workspace state, server JSON fetches, external link opening, and workspace-state subscriptions.
  • Implement renderer logic for chat handling, deterministic command parsing (open launch/runs/compare/ops/latest run, show runtime status), and palette-driven actions that call into the embedded surfaces.
  • Maintain local UI state for workspace status, tabs, chat messages, and runtime snapshot data pulled from the running research_ui APIs and runs index JSON.
  • Render context tabs as iframes into the existing research_ui frontend (Launch/Runs/Compare/Paper Ops and latest run), with tab management and nav sync to the sidebar.
  • Summarize QuantLab and Stepbit runtime health into a runtime strip using snapshot data from new JSON endpoints and render a dark-themed, responsive shell layout with chat, tabs, and command palette.
  • Define the Electron preload script to expose the quantlabDesktop API via contextBridge for secure IPC from the renderer.
desktop/preload.js
desktop/renderer/app.js
desktop/renderer/index.html
desktop/renderer/styles.css
Add desktop package metadata and documentation for the QuantLab Desktop prototype and how it fits into the broader product.
  • Create a desktop-specific package.json with Electron as a dev dependency and npm scripts for starting the desktop shell.
  • Introduce a desktop README explaining scope, commands to start the shell, and currently available tabs and behaviors.
  • Update the root README to describe the Desktop Shell Prototype, how to start it, and where to find additional docs on QuantLab Desktop v1 direction.
  • Check in the npm lockfile for the desktop package for reproducible installs.
desktop/package.json
desktop/README.md
desktop/package-lock.json
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 10 security issues, 1 other issue, and left some high level feedback:

Security issues:

  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a elements.runtimeChips.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a elements.chatLog.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a elements.tabsBar.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a elements.tabContent.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities (link)
  • User controlled data in a elements.paletteResults.innerHTML is an anti-pattern that can lead to XSS vulnerabilities (link)

General comments:

  • In main.js, the quantlab:request-json handler relies on a global fetch in the Electron main process; to avoid runtime surprises across Node/Electron versions, consider explicitly importing a fetch implementation (e.g., node:undici or node-fetch) or using the built‑in https module instead.
  • The quantlab:request-json IPC handler currently accepts an arbitrary relativePath from the renderer and concatenates it directly onto serverUrl; you may want to validate/normalize this argument (e.g., enforce a leading / and restrict to expected prefixes) to reduce the risk of unexpected or malformed requests.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `main.js`, the `quantlab:request-json` handler relies on a global `fetch` in the Electron main process; to avoid runtime surprises across Node/Electron versions, consider explicitly importing a fetch implementation (e.g., `node:undici` or `node-fetch`) or using the built‑in `https` module instead.
- The `quantlab:request-json` IPC handler currently accepts an arbitrary `relativePath` from the renderer and concatenates it directly onto `serverUrl`; you may want to validate/normalize this argument (e.g., enforce a leading `/` and restrict to expected prefixes) to reduce the risk of unexpected or malformed requests.

## Individual Comments

### Comment 1
<location path="desktop/renderer/app.js" line_range="379-382" />
<code_context>
+  if (target) target.classList.add("is-active");
+}
+
+function pushMessage(role, content) {
+  state.chatMessages.push({ role, content });
+  renderChat();
+}
</code_context>
<issue_to_address>
**suggestion (performance):** Consider bounding the chat history length to avoid unbounded in-memory growth over long sessions.

`pushMessage` always appends to `state.chatMessages` so long-running sessions may grow this array indefinitely and hurt performance or memory. Consider keeping only the last N messages (e.g., 100–200), for example:

```js
state.chatMessages = [
  ...state.chatMessages.slice(-99),
  { role, content },
];
```

before calling `renderChat()`.

```suggestion
function pushMessage(role, content) {
  // Keep only the last 100 messages (99 previous + the new one)
  state.chatMessages = [
    ...state.chatMessages.slice(-99),
    { role, content },
  ];
  renderChat();
}
```
</issue_to_address>

### Comment 2
<location path="desktop/renderer/app.js" line_range="166-173" />
<code_context>
  elements.runtimeChips.innerHTML = [
    runtimeChip("QuantLab", status === "ready" ? "up" : status === "starting" ? "starting" : "down", status === "ready" ? "up" : status === "starting" ? "warn" : "down"),
    runtimeChip("Runs", `${runs.length} indexed`, runs.length ? "up" : "warn"),
    runtimeChip("Paper", String(paperCount), paperCount ? "up" : "warn"),
    runtimeChip("Broker", String(brokerCount), brokerCount ? "up" : "warn"),
    runtimeChip("Stepbit app", stepbit.frontend_reachable ? "up" : "down", stepbit.frontend_reachable ? "up" : "down"),
    runtimeChip("Stepbit core", stepbit.core_ready ? "ready" : stepbit.core_reachable ? "up" : "down", stepbit.core_ready ? "up" : stepbit.core_reachable ? "warn" : "down"),
  ].join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 3
<location path="desktop/renderer/app.js" line_range="166-173" />
<code_context>
  elements.runtimeChips.innerHTML = [
    runtimeChip("QuantLab", status === "ready" ? "up" : status === "starting" ? "starting" : "down", status === "ready" ? "up" : status === "starting" ? "warn" : "down"),
    runtimeChip("Runs", `${runs.length} indexed`, runs.length ? "up" : "warn"),
    runtimeChip("Paper", String(paperCount), paperCount ? "up" : "warn"),
    runtimeChip("Broker", String(brokerCount), brokerCount ? "up" : "warn"),
    runtimeChip("Stepbit app", stepbit.frontend_reachable ? "up" : "down", stepbit.frontend_reachable ? "up" : "down"),
    runtimeChip("Stepbit core", stepbit.core_ready ? "ready" : stepbit.core_reachable ? "up" : "down", stepbit.core_ready ? "up" : stepbit.core_reachable ? "warn" : "down"),
  ].join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `elements.runtimeChips.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 4
<location path="desktop/renderer/app.js" line_range="177-186" />
<code_context>
  elements.chatLog.innerHTML = state.chatMessages
    .map(
      (message) => `
        <article class="message ${message.role}">
          <div class="message-role">${escapeHtml(message.role)}</div>
          <div class="message-body">${escapeHtml(message.content)}</div>
        </article>
      `
    )
    .join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 5
<location path="desktop/renderer/app.js" line_range="177-186" />
<code_context>
  elements.chatLog.innerHTML = state.chatMessages
    .map(
      (message) => `
        <article class="message ${message.role}">
          <div class="message-role">${escapeHtml(message.role)}</div>
          <div class="message-body">${escapeHtml(message.content)}</div>
        </article>
      `
    )
    .join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `elements.chatLog.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 6
<location path="desktop/renderer/app.js" line_range="204-213" />
<code_context>
  elements.tabsBar.innerHTML = state.tabs
    .map(
      (tab) => `
        <button class="tab-pill ${tab.id === state.activeTabId ? "is-active" : ""}" data-tab-id="${escapeHtml(tab.id)}" type="button">
          <span>${escapeHtml(tab.title)}</span>
          <span class="tab-close" data-close-tab="${escapeHtml(tab.id)}">×</span>
        </button>
      `
    )
    .join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 7
<location path="desktop/renderer/app.js" line_range="204-213" />
<code_context>
  elements.tabsBar.innerHTML = state.tabs
    .map(
      (tab) => `
        <button class="tab-pill ${tab.id === state.activeTabId ? "is-active" : ""}" data-tab-id="${escapeHtml(tab.id)}" type="button">
          <span>${escapeHtml(tab.title)}</span>
          <span class="tab-close" data-close-tab="${escapeHtml(tab.id)}">×</span>
        </button>
      `
    )
    .join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `elements.tabsBar.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 8
<location path="desktop/renderer/app.js" line_range="220-222" />
<code_context>
  elements.tabContent.innerHTML = activeTab.kind === "placeholder"
    ? `<div class="tab-placeholder">${escapeHtml(activeTab.content)}</div>`
    : `<iframe class="tab-frame" src="${escapeHtml(activeTab.url)}" title="${escapeHtml(activeTab.title)}"></iframe>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 9
<location path="desktop/renderer/app.js" line_range="220-222" />
<code_context>
  elements.tabContent.innerHTML = activeTab.kind === "placeholder"
    ? `<div class="tab-placeholder">${escapeHtml(activeTab.content)}</div>`
    : `<iframe class="tab-frame" src="${escapeHtml(activeTab.url)}" title="${escapeHtml(activeTab.title)}"></iframe>`;
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `elements.tabContent.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 10
<location path="desktop/renderer/app.js" line_range="243-252" />
<code_context>
  elements.paletteResults.innerHTML = paletteActions
    .map(
      (action) => `
        <button class="palette-item" data-palette-action="${escapeHtml(action.id)}" type="button">
          <strong>${escapeHtml(action.label)}</strong>
          <span>${escapeHtml(action.description)}</span>
        </button>
      `
    )
    .join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-document-method):** User controlled data in methods like `innerHTML`, `outerHTML` or `document.write` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

### Comment 11
<location path="desktop/renderer/app.js" line_range="243-252" />
<code_context>
  elements.paletteResults.innerHTML = paletteActions
    .map(
      (action) => `
        <button class="palette-item" data-palette-action="${escapeHtml(action.id)}" type="button">
          <strong>${escapeHtml(action.label)}</strong>
          <span>${escapeHtml(action.description)}</span>
        </button>
      `
    )
    .join("");
</code_context>
<issue_to_address>
**security (javascript.browser.security.insecure-innerhtml):** User controlled data in a `elements.paletteResults.innerHTML` is an anti-pattern that can lead to XSS vulnerabilities

*Source: opengrep*
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +379 to +382
function pushMessage(role, content) {
state.chatMessages.push({ role, content });
renderChat();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion (performance): Consider bounding the chat history length to avoid unbounded in-memory growth over long sessions.

pushMessage always appends to state.chatMessages so long-running sessions may grow this array indefinitely and hurt performance or memory. Consider keeping only the last N messages (e.g., 100–200), for example:

state.chatMessages = [
  ...state.chatMessages.slice(-99),
  { role, content },
];

before calling renderChat().

Suggested change
function pushMessage(role, content) {
state.chatMessages.push({ role, content });
renderChat();
}
function pushMessage(role, content) {
// Keep only the last 100 messages (99 previous + the new one)
state.chatMessages = [
...state.chatMessages.slice(-99),
{ role, content },
];
renderChat();
}

Comment on lines +166 to +173
elements.runtimeChips.innerHTML = [
runtimeChip("QuantLab", status === "ready" ? "up" : status === "starting" ? "starting" : "down", status === "ready" ? "up" : status === "starting" ? "warn" : "down"),
runtimeChip("Runs", `${runs.length} indexed`, runs.length ? "up" : "warn"),
runtimeChip("Paper", String(paperCount), paperCount ? "up" : "warn"),
runtimeChip("Broker", String(brokerCount), brokerCount ? "up" : "warn"),
runtimeChip("Stepbit app", stepbit.frontend_reachable ? "up" : "down", stepbit.frontend_reachable ? "up" : "down"),
runtimeChip("Stepbit core", stepbit.core_ready ? "ready" : stepbit.core_reachable ? "up" : "down", stepbit.core_ready ? "up" : stepbit.core_reachable ? "warn" : "down"),
].join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +166 to +173
elements.runtimeChips.innerHTML = [
runtimeChip("QuantLab", status === "ready" ? "up" : status === "starting" ? "starting" : "down", status === "ready" ? "up" : status === "starting" ? "warn" : "down"),
runtimeChip("Runs", `${runs.length} indexed`, runs.length ? "up" : "warn"),
runtimeChip("Paper", String(paperCount), paperCount ? "up" : "warn"),
runtimeChip("Broker", String(brokerCount), brokerCount ? "up" : "warn"),
runtimeChip("Stepbit app", stepbit.frontend_reachable ? "up" : "down", stepbit.frontend_reachable ? "up" : "down"),
runtimeChip("Stepbit core", stepbit.core_ready ? "ready" : stepbit.core_reachable ? "up" : "down", stepbit.core_ready ? "up" : stepbit.core_reachable ? "warn" : "down"),
].join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a elements.runtimeChips.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +177 to +186
elements.chatLog.innerHTML = state.chatMessages
.map(
(message) => `
<article class="message ${message.role}">
<div class="message-role">${escapeHtml(message.role)}</div>
<div class="message-body">${escapeHtml(message.content)}</div>
</article>
`
)
.join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +177 to +186
elements.chatLog.innerHTML = state.chatMessages
.map(
(message) => `
<article class="message ${message.role}">
<div class="message-role">${escapeHtml(message.role)}</div>
<div class="message-body">${escapeHtml(message.content)}</div>
</article>
`
)
.join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a elements.chatLog.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +204 to +213
elements.tabsBar.innerHTML = state.tabs
.map(
(tab) => `
<button class="tab-pill ${tab.id === state.activeTabId ? "is-active" : ""}" data-tab-id="${escapeHtml(tab.id)}" type="button">
<span>${escapeHtml(tab.title)}</span>
<span class="tab-close" data-close-tab="${escapeHtml(tab.id)}">×</span>
</button>
`
)
.join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a elements.tabsBar.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +220 to +222
elements.tabContent.innerHTML = activeTab.kind === "placeholder"
? `<div class="tab-placeholder">${escapeHtml(activeTab.content)}</div>`
: `<iframe class="tab-frame" src="${escapeHtml(activeTab.url)}" title="${escapeHtml(activeTab.title)}"></iframe>`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +220 to +222
elements.tabContent.innerHTML = activeTab.kind === "placeholder"
? `<div class="tab-placeholder">${escapeHtml(activeTab.content)}</div>`
: `<iframe class="tab-frame" src="${escapeHtml(activeTab.url)}" title="${escapeHtml(activeTab.title)}"></iframe>`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a elements.tabContent.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +243 to +252
elements.paletteResults.innerHTML = paletteActions
.map(
(action) => `
<button class="palette-item" data-palette-action="${escapeHtml(action.id)}" type="button">
<strong>${escapeHtml(action.label)}</strong>
<span>${escapeHtml(action.description)}</span>
</button>
`
)
.join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-document-method): User controlled data in methods like innerHTML, outerHTML or document.write is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

Comment on lines +243 to +252
elements.paletteResults.innerHTML = paletteActions
.map(
(action) => `
<button class="palette-item" data-palette-action="${escapeHtml(action.id)}" type="button">
<strong>${escapeHtml(action.label)}</strong>
<span>${escapeHtml(action.description)}</span>
</button>
`
)
.join("");
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security (javascript.browser.security.insecure-innerhtml): User controlled data in a elements.paletteResults.innerHTML is an anti-pattern that can lead to XSS vulnerabilities

Source: opengrep

@Whiteks1 Whiteks1 merged commit 5197537 into main Mar 27, 2026
2 checks passed
@Whiteks1 Whiteks1 deleted the codex/quantlab-desktop-shell branch March 27, 2026 22:43
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.

1 participant