Skip to content

feat(core): add "Run with agent" action for inspector comments#101

Open
virang-nimrobo wants to merge 3 commits into
1weiho:mainfrom
virang-nimrobo:feat/superconnector-plugin
Open

feat(core): add "Run with agent" action for inspector comments#101
virang-nimrobo wants to merge 3 commits into
1weiho:mainfrom
virang-nimrobo:feat/superconnector-plugin

Conversation

@virang-nimrobo
Copy link
Copy Markdown

@virang-nimrobo virang-nimrobo commented May 11, 2026

Summary

  • Adds a Vite dev-server plugin (/__superconnector/*) for starting, polling, and canceling agent runs scoped to a single inspector comment.
  • Adds a "Run with agent" button to each comment in the inspector widget; status (running / done / error / canceled) streams back over HMR.
  • Localized for en, ja, zh-CN, zh-TW.
  • Adds @nimrobo/superconnector ^0.1.0 as a runtime dependency.

Notes for reviewers

  • pnpm typecheck fails on packages/core/src/app/components/player.tsx:53 — this is pre-existing on main and not introduced by this PR.

Test plan

  • pnpm check clean
  • pnpm test — 168 tests pass (incl. 4 new superconnector-plugin tests)
  • Manual: added a comment in the inspector, clicked "Run with agent", status transitions verified in browser

Summary by CodeRabbit

  • New Features

    • Added "Run with agent" action to inspector comments with per-comment run controls, live log lines, cancel/retry, and status indicators.
  • Localization

    • Inspector UI strings for agent actions and statuses added in English, Japanese, Simplified and Traditional Chinese.
  • Tests

    • Added test coverage for the agent integration behaviors and utilities.
  • Chores

    • Bumped package minor version and added runtime support for the agent integration.

Review Change Stack

Adds a Vite dev-server plugin exposing /__superconnector/* endpoints for
starting, polling, and canceling agent runs scoped to a single comment.
The inspector comment widget gains a "Run with agent" button that dispatches
the comment through @nimrobo/superconnector to a connected coding agent,
with live status (running / done / error / canceled) streamed back over HMR.
Localized strings added for en, ja, zh-CN, zh-TW.
@vercel
Copy link
Copy Markdown

vercel Bot commented May 11, 2026

@virang-nimrobo is attempting to deploy a commit to the Yiwei Ho Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Walkthrough

Adds a Vite dev /__superconnector API and client integration: a useAgentRuns hook, AgentLogLine/AgentRunButton UI, comment-widget wiring, localization, tests, Vite plugin implementation with run registry/streaming/cancel, Vite plugin registration, package dependency, and a changeset.

Changes

Superconnector Agent Integration

Layer / File(s) Summary
Type contracts and core run shapes
packages/core/src/vite/superconnector-plugin.ts, packages/core/src/app/components/inspector/comment-superconnect.tsx, packages/core/src/locale/types.ts
Define run status/types and extend Locale["inspector"] with agent UI keys.
Vite plugin utilities & helpers
packages/core/src/vite/superconnector-plugin.ts
JSON/body parsing, malformed-JSON detection, origin validation, pruneCompletedRuns, prompt/app/session id builders, and extractText normalization exported for plugin and tests.
Backend: Vite Superconnector Plugin
packages/core/src/vite/superconnector-plugin.ts
Middleware at /__superconnector to check availability, spawn runs (prompt construction), stream messages, poll run state, cancel runs, manage in-memory run registry with abort controllers and TTL/max-retained pruning, and broadcast HMR events.
Plugin unit tests
packages/core/src/vite/superconnector-plugin.test.ts
Tests for app/session id stability, prompt formatting, extractText normalization, malformed-JSON detection, allowed-mutation origin checks, and pruneCompletedRuns behavior.
Frontend: useAgentRuns hook and API integration
packages/core/src/app/components/inspector/comment-superconnect.tsx
Adds fetchWithTimeout API helper, availability/run/cancel endpoints integration, useAgentRuns(slideId, onDone) hook with polling and HMR listener, finish/cancel logic with localized toasts, and run lifecycle state including canceling.
Frontend: Agent UI components
packages/core/src/app/components/inspector/comment-superconnect.tsx
Export AgentLogLine for truncated log display and AgentRunButton rendering status-specific controls (run/stop/done/error/canceled) wired to run/cancel actions.
Comment Widget Integration
packages/core/src/app/components/inspector/comment-widget.tsx
Call useAgentRuns(slideId, refetch) in CommentWidget, render AgentLogLine and AgentRunButton per comment, and restructure controls layout to include agent UI alongside delete button.
Localization: Agent UI Strings
packages/core/src/locale/en.ts, packages/core/src/locale/ja.ts, packages/core/src/locale/zh-cn.ts, packages/core/src/locale/zh-tw.ts
Add agent-related strings (runWithAgent, agentRunning, agentDone, agentError, agentCanceled, stopAgent).
Vite config & dependency
packages/core/package.json, packages/core/src/vite/config.ts
Add @nimrobo/superconnector at ^0.1.0 to runtime dependencies; import and register superconnectorPlugin({ userCwd, slidesDir }) in Vite plugin array.
Changeset documentation
.changeset/superconnector-integration.md
Document minor version bump with new "Run with agent (Superconnected)" inspector action.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A rabbit hops through comments new,
With agents ready, sleek and true,
Prompts and streams across the wire,
HMR hums while logs aspire,
Click "Run" — edits bloom in view.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: a new "Run with agent" action for inspector comments, which is the primary change across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (4)
packages/core/src/app/components/inspector/comment-superconnect.tsx (4)

87-91: 💤 Low value

Cleanup only runs on unmount; pollTimers keeps growing across runs.

The unmount cleanup clears active timers, but completed runs are never removed from pollTimers.current because stopPolling is called from finishRun (which does delete the entry) — that part is fine. However, if slideId changes during the component's lifetime (e.g., navigating between slides while the inspector stays mounted), in-flight polls and pending state for the previous slide are not reset; status/log/runs Maps will continue to carry stale entries keyed by old comment IDs. Consider resetting state and clearing timers when slideId changes.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 87 - 91, The component only cleans timers on unmount, so when slideId
changes stale timers and entries in pollTimers.current and the Maps (status,
log, runs) persist; add a useEffect that depends on slideId which iterates
pollTimers.current and calls stopPolling (or clearInterval) for each active
timer, clears pollTimers.current, and resets the Maps (status, log, runs) to
empty states so in-flight polls and pending state for the previous slide are
removed whenever slideId changes; reference the existing pollTimers,
stopPolling, finishRun, and the Maps (status/log/runs) and ensure this new
effect runs before starting any new polls for the new slideId.

162-175: ⚡ Quick win

setInterval can stack overlapping polls; prefer recursive setTimeout.

If a pollStatus request takes longer than 2 s (slow network, server warm-up), setInterval will dispatch additional fetches in parallel rather than waiting for the previous one. This can lead to out-of-order log/status updates and unnecessary load. A recursive setTimeout ensures one in-flight poll at a time and is the standard pattern for this case.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 162 - 175, Replace the setInterval polling loop with a recursive
setTimeout pattern so only one pollStatus(runId) is in-flight at a time:
implement an async function (e.g., pollLoop) that calls pollStatus(runId),
updates setLogMap with the last message for commentId, calls
finishRun(commentId, status, error) when status !== 'pending', and on success
schedules itself with setTimeout(..., 2000); on errors call finishRun(commentId,
'error') and stop or schedule retry as appropriate; ensure you clear the
timer/stop the loop when the component unmounts or run completes.

181-192: 💤 Low value

cancel does not give immediate feedback or update local state.

When the user clicks Stop, the request is sent but status is not changed locally — the UI continues showing the in-flight stop button until either an HMR 'canceled' event arrives or the next poll picks it up. On a slow connection, this looks unresponsive. Also, on failure the toast is shown but the run keeps polling; consider either optimistically setting status to a transient "canceling" state, or at least leaving the button enabled with a clearer error path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 181 - 192, The cancel handler (cancel) currently only calls
cancelAgentRun(runId) and waits for a server event to update UI; update it to
optimistically update local state so the UI gives immediate feedback: when a
runId is found in runs, set that run's status to a transient "canceling" (or
similar) in the same state/store that the UI reads (the runs map or run status
state) before awaiting cancelAgentRun, and if cancelAgentRun throws revert that
status and show toast.error(t.inspector.agentError); also ensure the stop button
stays enabled/disabled appropriately by reading this transient status so the
button reflects canceling and allows retry if the API fails.

26-65: 💤 Low value

No request timeouts on dev-server fetches.

checkAgentAvailable, startAgentRun, pollStatus, and cancelAgentRun all fetch without an AbortController/timeout. If the dev-server endpoint hangs (broken plugin, agent stuck), the polling chain will block indefinitely and the cancel button itself can hang. Adding a modest AbortSignal.timeout(...) (or a manual AbortController) per call would make the UX more resilient.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 26 - 65, All four network helpers (checkAgentAvailable, startAgentRun,
pollStatus, cancelAgentRun) must use an AbortSignal with a modest timeout to
avoid hanging — wrap each fetch with AbortSignal.timeout(<ms>) or create an
AbortController and set a timer, pass its signal into fetch, and ensure you
handle the abort by catching the DOMException/AbortError and returning a
sensible fallback (false for checkAgentAvailable, throw a descriptive Error for
startAgentRun/pollStatus/cancelAgentRun). Update the fetch calls inside
checkAgentAvailable, startAgentRun, pollStatus, and cancelAgentRun to include
the signal and clear any timers after completion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/superconnector-integration.md:
- Line 5: Replace the current multi-sentence, implementation-heavy changeset
entry with a single present-tense, user-facing line describing the change; e.g.,
"Adds a 'Run with agent' action to inspector comments." Ensure the new line is
concise, present-tense, and does not mention implementation details like
`@nimrobo/superconnector` or HMR.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx`:
- Around line 148-179: The run function can leak stale intervals because
pollTimers.current.set(commentId, timer) overwrites without clearing an existing
timer; before setting a new timer, check pollTimers.current.get(commentId) and
if present call clearInterval(existing) and delete that entry (or call an
existing stopPolling helper) so the old interval is stopped; then set the new
timer and store it. Also add stopPolling (or the function you introduce that
clears timers) to the useCallback dependency array along with finishRun,
setStatus, slideId, and t.inspector.* so closures reference the latest helper.
- Around line 129-179: The race happens because both the HMR handler (handler in
the useEffect for import.meta.hot) and the poll interval inside run can call
finishRun for the same commentId; update both places to guard terminal
transitions by checking whether the run is still active before calling finishRun
(use pollTimers.current.has(commentId) or another active-run map like runsMap to
detect activity), and ensure you clear/delete the timer entry immediately when
handling a terminal event so the other path will skip calling finishRun; modify
the handler and the interval callback to first if
(!pollTimers.current.has(commentId)) return; (or the inverse check) and then
proceed to clear the timer and call finishRun.
- Around line 258-269: The retry button for status === 'canceled' uses the wrong
icon: it calls runs.run(commentId, line, note) but renders StopCircle (a "stop"
affordance) instead of a "play/retry" icon; update the JSX in the canceled
branch to render a Play (or RotateCw) icon component instead of StopCircle so
the visual matches the action triggered by runs.run (locate the conditional
block checking status === 'canceled' and replace the StopCircle element with the
chosen Play or RotateCw icon).

In `@packages/core/src/vite/superconnector-plugin.ts`:
- Around line 123-124: The Map runs (Map<string, AgentRun>) currently retains
every AgentRun forever; add bounded eviction by removing completed runs after a
configurable TTL (e.g., 5–30 minutes) and/or enforce a max size (LRU) to prevent
unbounded growth. Implement this by: when an AgentRun completes (all code paths
that call success/failure/abort in the run lifecycle), mark it completed and
schedule a delayed removal (setTimeout) that deletes runs.delete(runId) after
the TTL; also add a periodic cleanup/compaction routine or an LRU eviction
policy to prune oldest entries when the map exceeds maxEntries. Update all
places that create/finish runs to use the same finalize hook so completed runs
are consistently removed, and expose TTL/maxEntries as configuration constants
near the runs declaration. Ensure delete logic is idempotent and does not affect
still-active runs.
- Around line 149-154: The POST /runs handler currently assumes readBody(req)
succeeds and lets parse errors bubble to the global catch (500); update the
block that checks if (method === 'POST' && url.pathname === '/runs') to wrap the
readBody(req) call in a try/catch (or check its rejection) and, on JSON
parse/malformed errors, return json(res, 400, { error: 'malformed JSON' })
instead of throwing; do the same fix for the other occurrence around the second
readBody usage (the lines referenced 239-240). Ensure you reference the same
helper symbols: readBody, RunBody, and json so the handlers return 400 for
client-side malformed JSON.
- Around line 140-154: Add an origin/host check to the superconnector middleware
that rejects mutating requests unless they come from an allowed origin/host (or
have a valid CSRF token); specifically update the handler registered via
server.middlewares.use('/__superconnector', ...) and the POST branches for
'/runs' and '/runs/:runId/cancel' to verify req.headers.origin or
req.headers.host (or a configured allowlist) and return 403 for disallowed
requests before reading the body or performing actions; ensure the same guard is
applied to the other POST branch around lines handling cancel (the POST
'/runs/:runId/cancel' handler) so cross-site requests cannot trigger run
creation or cancellation.

---

Nitpick comments:
In `@packages/core/src/app/components/inspector/comment-superconnect.tsx`:
- Around line 87-91: The component only cleans timers on unmount, so when
slideId changes stale timers and entries in pollTimers.current and the Maps
(status, log, runs) persist; add a useEffect that depends on slideId which
iterates pollTimers.current and calls stopPolling (or clearInterval) for each
active timer, clears pollTimers.current, and resets the Maps (status, log, runs)
to empty states so in-flight polls and pending state for the previous slide are
removed whenever slideId changes; reference the existing pollTimers,
stopPolling, finishRun, and the Maps (status/log/runs) and ensure this new
effect runs before starting any new polls for the new slideId.
- Around line 162-175: Replace the setInterval polling loop with a recursive
setTimeout pattern so only one pollStatus(runId) is in-flight at a time:
implement an async function (e.g., pollLoop) that calls pollStatus(runId),
updates setLogMap with the last message for commentId, calls
finishRun(commentId, status, error) when status !== 'pending', and on success
schedules itself with setTimeout(..., 2000); on errors call finishRun(commentId,
'error') and stop or schedule retry as appropriate; ensure you clear the
timer/stop the loop when the component unmounts or run completes.
- Around line 181-192: The cancel handler (cancel) currently only calls
cancelAgentRun(runId) and waits for a server event to update UI; update it to
optimistically update local state so the UI gives immediate feedback: when a
runId is found in runs, set that run's status to a transient "canceling" (or
similar) in the same state/store that the UI reads (the runs map or run status
state) before awaiting cancelAgentRun, and if cancelAgentRun throws revert that
status and show toast.error(t.inspector.agentError); also ensure the stop button
stays enabled/disabled appropriately by reading this transient status so the
button reflects canceling and allows retry if the API fails.
- Around line 26-65: All four network helpers (checkAgentAvailable,
startAgentRun, pollStatus, cancelAgentRun) must use an AbortSignal with a modest
timeout to avoid hanging — wrap each fetch with AbortSignal.timeout(<ms>) or
create an AbortController and set a timer, pass its signal into fetch, and
ensure you handle the abort by catching the DOMException/AbortError and
returning a sensible fallback (false for checkAgentAvailable, throw a
descriptive Error for startAgentRun/pollStatus/cancelAgentRun). Update the fetch
calls inside checkAgentAvailable, startAgentRun, pollStatus, and cancelAgentRun
to include the signal and clear any timers after completion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4fce1461-efb7-4989-b460-8da1258c1350

📥 Commits

Reviewing files that changed from the base of the PR and between 5505c3b and 0a8a292.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (12)
  • .changeset/superconnector-integration.md
  • packages/core/package.json
  • packages/core/src/app/components/inspector/comment-superconnect.tsx
  • packages/core/src/app/components/inspector/comment-widget.tsx
  • packages/core/src/locale/en.ts
  • packages/core/src/locale/ja.ts
  • packages/core/src/locale/types.ts
  • packages/core/src/locale/zh-cn.ts
  • packages/core/src/locale/zh-tw.ts
  • packages/core/src/vite/config.ts
  • packages/core/src/vite/superconnector-plugin.test.ts
  • packages/core/src/vite/superconnector-plugin.ts

Comment thread .changeset/superconnector-integration.md Outdated
Comment thread packages/core/src/app/components/inspector/comment-superconnect.tsx
Comment thread packages/core/src/app/components/inspector/comment-superconnect.tsx
Comment thread packages/core/src/app/components/inspector/comment-superconnect.tsx
Comment thread packages/core/src/vite/superconnector-plugin.ts
Comment thread packages/core/src/vite/superconnector-plugin.ts
Comment thread packages/core/src/vite/superconnector-plugin.ts
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (6)
packages/core/src/vite/superconnector-plugin.ts (2)

192-196: 💤 Low value

Consider unref() on the cleanup timer.

The 10-minute setTimeout keeps a Node timer active and can hold the event loop open. While Vite's dev server lifecycle will usually keep the process alive anyway, calling unref() makes the cleanup non-blocking on graceful shutdown.

Suggested tweak
-        run.cleanupTimer = setTimeout(() => {
+        run.cleanupTimer = setTimeout(() => {
           const current = runs.get(run.runId);
           if (current && current.status !== 'pending') runs.delete(run.runId);
         }, COMPLETED_RUN_TTL_MS);
+        run.cleanupTimer.unref?.();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/vite/superconnector-plugin.ts` around lines 192 - 196, The
setTimeout assigned to run.cleanupTimer should be unref'd so the 10-minute
cleanup timer doesn't keep the Node event loop alive; after creating the timer
in the run.cleanupTimer = setTimeout(...) block (the code around
run.cleanupTimer, COMPLETED_RUN_TTL_MS and pruneCompletedRuns), call
run.cleanupTimer.unref() if that method exists (guard for environments where
unref may be undefined) so the cleanup becomes non-blocking on graceful
shutdown.

281-291: 💤 Low value

GET /runs/:runId path parsing also matches /runs/abc/cancel.

url.pathname.slice('/runs/'.length) greedily captures everything after /runs/, so a GET to /runs/foo/cancel would set runId = 'foo/cancel' and return 404 (rather than fall through or 405). Not exploitable, but tightening the match keeps the route surface predictable:

-          if (method === 'GET' && url.pathname.startsWith('/runs/')) {
-            const runId = url.pathname.slice('/runs/'.length);
+          if (method === 'GET' && /^\/runs\/[^/]+$/.test(url.pathname)) {
+            const runId = url.pathname.slice('/runs/'.length);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/vite/superconnector-plugin.ts` around lines 281 - 291, The
current GET handler uses url.pathname.startsWith('/runs/') and then slices
everything after '/runs/' into runId, which lets paths like '/runs/foo/cancel'
match; update the route guard to only accept a single-segment runId (no extra
slashes) before using runId and runs.get. Concretely, replace the startsWith +
slice logic with a stricter check (e.g., test url.pathname against
/^\/runs\/[^/]+$/ or compute const runId = url.pathname.slice('/runs/'.length);
if (runId.includes('/')) return to let other routes handle it) and then use
runs.get(runId) and the existing json responses.
packages/core/src/app/components/inspector/comment-superconnect.tsx (4)

305-338: ⚡ Quick win

Add aria-label to icon-only buttons for screen reader parity.

The stop button at line 286 sets both title and aria-label, but the error retry (line 307), canceled retry (line 319), and default run (line 330) buttons rely on title only. title is not consistently exposed as the accessible name by all screen readers/browsers, so icon-only buttons can end up announced as "button" with no purpose.

Suggested fix
       <button
         type="button"
         onClick={() => runs.run(commentId, line, note)}
         className="rounded p-1 text-red-600 hover:bg-muted"
         title={t.inspector.agentError}
+        aria-label={t.inspector.agentError}
       >
         <XCircle className="size-3.5" />
       </button>
...
       <button
         type="button"
         onClick={() => runs.run(commentId, line, note)}
         className="rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground"
         title={t.inspector.agentCanceled}
+        aria-label={t.inspector.agentCanceled}
       >
         <Play className="size-3.5" />
       </button>
...
     <button
       type="button"
       onClick={() => runs.run(commentId, line, note)}
       className="rounded p-1 text-muted-foreground hover:bg-muted hover:text-foreground"
       title={t.inspector.runWithAgent}
+      aria-label={t.inspector.runWithAgent}
     >
       <Play className="size-3.5" />
     </button>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 305 - 338, The icon-only buttons in comment-superconnect.tsx for status
'error' (the XCircle retry button), 'canceled' (the Play retry button), and the
default run button are missing aria-label attributes; add aria-label props to
each button using the same localized strings already used in title
(t.inspector.agentError, t.inspector.agentCanceled, t.inspector.runWithAgent) to
ensure screen readers announce the button purpose (leave existing title intact).

28-43: 💤 Low value

fetchWithTimeout silently drops a caller-supplied signal.

Spreading init first then overwriting signal: controller.signal means any external AbortSignal passed by a caller would be ignored. No caller currently passes one, but if future code wants composable cancellation, this will silently break. Worth either documenting or composing signals via AbortSignal.any([controller.signal, init?.signal]) (Node 20+/modern browsers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 28 - 43, fetchWithTimeout currently overwrites any caller-supplied
AbortSignal (init?.signal) by spreading init then setting signal:
controller.signal; change it to compose the signals instead of discarding the
caller's: create the timeout controller (controller) and combine
controller.signal with init?.signal using AbortSignal.any([controller.signal,
init?.signal]) when available, or implement a small fallback that forwards
abortion from either signal to a new controller; pass the composed signal to
fetch and keep the existing timeout/error behavior (throw `${label} timed out`
when the timeout controller aborts) while still clearing the timer in finally.
Ensure you reference fetchWithTimeout, controller, init?.signal, and
FETCH_TIMEOUT_MS when making the change.

237-250: 💤 Low value

Cancel error path can desync UI from server state.

On a failed cancelAgentRun, status is reverted from 'canceling' back to 'pending'. If the cancel actually reached the server but the response failed (timeout, transient 5xx), the server may still abort the run while the UI shows 'pending' — eventually the HMR canceled event or a poll will reconcile it, but the user just saw an error toast for a "failed" cancel that succeeded. Consider keeping 'canceling' and letting the terminal event reconcile, or only reverting on explicit non-cancellable responses (e.g. 404).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 237 - 250, The cancel handler (cancel) should not blindly revert status to
'pending' on any cancelAgentRun error; instead keep the status as 'canceling' so
the HMR-event/poll can reconcile unless the error explicitly indicates a
non-cancellable outcome (e.g., a 404 or an error payload saying the run doesn't
exist). Modify the catch block around cancelAgentRun(runId) to inspect the
thrown error (status/code/message) and only call setStatus(commentId, 'pending')
when the error clearly means "not found" or "already finished"; for all other
errors keep the 'canceling' status and still call
toast.error(t.inspector.agentError) so the user is informed without desync.
Ensure you reference cancel, cancelAgentRun, setStatus, runs and
t.inspector.agentError when updating the logic.

168-191: ⚡ Quick win

Refactor to use the status field instead of msgType for terminal detection.

The HMR handler currently mixes AgentMessageType (from agent stream messages) and AgentRunStatus (terminal statuses) in the msgType field. While collision risk is low in practice (typical agent SDKs use message types like 'text', 'tool_use' rather than lifecycle terms), a cleaner approach is available: the SuperconnectorEvent already includes a separate status field that directly indicates terminal states. Replace the msgType === 'done' | 'error' | 'canceled' checks with status !== 'pending' to be explicit about lifecycle logic, removing the overloading altogether.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/app/components/inspector/comment-superconnect.tsx` around
lines 168 - 191, The HMR handler currently checks msgType for terminal events;
switch it to use the SuperconnectorEvent.status field instead: in the handler
(inside useEffect) replace the msgType === 'done'|'error'|'canceled' branches
with a single branch that tests if status !== 'pending' and, if so, verifies
pollTimers.current.has(commentId), calls stopPolling(commentId) and then
finishRun(commentId, status, status === 'error' ? text : undefined); otherwise
(status === 'pending') keep the existing log/status update path that sets
setLogMap and setStatus; keep the import.meta.hot.on/off registration and all
referenced symbols (handler, pollTimers, stopPolling, finishRun, setLogMap,
setStatus) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/core/src/app/components/inspector/comment-superconnect.tsx`:
- Around line 305-338: The icon-only buttons in comment-superconnect.tsx for
status 'error' (the XCircle retry button), 'canceled' (the Play retry button),
and the default run button are missing aria-label attributes; add aria-label
props to each button using the same localized strings already used in title
(t.inspector.agentError, t.inspector.agentCanceled, t.inspector.runWithAgent) to
ensure screen readers announce the button purpose (leave existing title intact).
- Around line 28-43: fetchWithTimeout currently overwrites any caller-supplied
AbortSignal (init?.signal) by spreading init then setting signal:
controller.signal; change it to compose the signals instead of discarding the
caller's: create the timeout controller (controller) and combine
controller.signal with init?.signal using AbortSignal.any([controller.signal,
init?.signal]) when available, or implement a small fallback that forwards
abortion from either signal to a new controller; pass the composed signal to
fetch and keep the existing timeout/error behavior (throw `${label} timed out`
when the timeout controller aborts) while still clearing the timer in finally.
Ensure you reference fetchWithTimeout, controller, init?.signal, and
FETCH_TIMEOUT_MS when making the change.
- Around line 237-250: The cancel handler (cancel) should not blindly revert
status to 'pending' on any cancelAgentRun error; instead keep the status as
'canceling' so the HMR-event/poll can reconcile unless the error explicitly
indicates a non-cancellable outcome (e.g., a 404 or an error payload saying the
run doesn't exist). Modify the catch block around cancelAgentRun(runId) to
inspect the thrown error (status/code/message) and only call
setStatus(commentId, 'pending') when the error clearly means "not found" or
"already finished"; for all other errors keep the 'canceling' status and still
call toast.error(t.inspector.agentError) so the user is informed without desync.
Ensure you reference cancel, cancelAgentRun, setStatus, runs and
t.inspector.agentError when updating the logic.
- Around line 168-191: The HMR handler currently checks msgType for terminal
events; switch it to use the SuperconnectorEvent.status field instead: in the
handler (inside useEffect) replace the msgType === 'done'|'error'|'canceled'
branches with a single branch that tests if status !== 'pending' and, if so,
verifies pollTimers.current.has(commentId), calls stopPolling(commentId) and
then finishRun(commentId, status, status === 'error' ? text : undefined);
otherwise (status === 'pending') keep the existing log/status update path that
sets setLogMap and setStatus; keep the import.meta.hot.on/off registration and
all referenced symbols (handler, pollTimers, stopPolling, finishRun, setLogMap,
setStatus) unchanged.

In `@packages/core/src/vite/superconnector-plugin.ts`:
- Around line 192-196: The setTimeout assigned to run.cleanupTimer should be
unref'd so the 10-minute cleanup timer doesn't keep the Node event loop alive;
after creating the timer in the run.cleanupTimer = setTimeout(...) block (the
code around run.cleanupTimer, COMPLETED_RUN_TTL_MS and pruneCompletedRuns), call
run.cleanupTimer.unref() if that method exists (guard for environments where
unref may be undefined) so the cleanup becomes non-blocking on graceful
shutdown.
- Around line 281-291: The current GET handler uses
url.pathname.startsWith('/runs/') and then slices everything after '/runs/' into
runId, which lets paths like '/runs/foo/cancel' match; update the route guard to
only accept a single-segment runId (no extra slashes) before using runId and
runs.get. Concretely, replace the startsWith + slice logic with a stricter check
(e.g., test url.pathname against /^\/runs\/[^/]+$/ or compute const runId =
url.pathname.slice('/runs/'.length); if (runId.includes('/')) return to let
other routes handle it) and then use runs.get(runId) and the existing json
responses.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c54dc6cc-6323-4aa0-b693-992f3ed97ee5

📥 Commits

Reviewing files that changed from the base of the PR and between 0a8a292 and 90c4aaf.

📒 Files selected for processing (4)
  • .changeset/superconnector-integration.md
  • packages/core/src/app/components/inspector/comment-superconnect.tsx
  • packages/core/src/vite/superconnector-plugin.test.ts
  • packages/core/src/vite/superconnector-plugin.ts
✅ Files skipped from review due to trivial changes (1)
  • .changeset/superconnector-integration.md

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