* feat(web): single header MonitoringToggle + Prompts-style Tools results (#1661)
Consolidate the monitoring column's open/close affordances into one header
toggle, and align the Tools/Prompts result panes and the sidebar log layout.
- Add a single `MonitoringToggle` in the header, to the right of the theme
icon. It opens/closes the monitoring column and only shows when a server is
connected OR a connect attempt failed (wide viewport + a monitor tab
available) — the same availability rule the column uses.
- Remove the scattered pin/close icons: delete `PinColumnButton`; drop `onPin`
from the Logs/Protocol/Network/Console screens and their stream panels; drop
`onOpenMonitor` from the server list; remove the close button from
`MonitoringControls`/`MonitoringScreen`.
- Tools screen: remove the "Results will appear here" placeholder pane. Results
now replace the input form in a single content pane (the Prompts pattern),
with a top-left X (ToolResultPanel) that dismisses them back to the form;
form values are preserved for a re-run.
- Prompts screen: the argument form fills the content pane width (drop the 40%
cap), matching the Tools input.
- LogEntry: add a `compact` two-line layout (time/level/logger on line one,
message wrapping below) used by the embedded monitoring-column Logs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95
* polish(web): tooltips on icon buttons + rename "monitoring column" → "monitoring sidebar" (#1661)
- Add Mantine `Tooltip`s to the icon-only controls: Client settings, Theme
(dynamic light/dark label), the monitoring-sidebar toggle, the list-level and
per-entry Expand/Collapse toggles, the Pin/Unpin toggle, and the Replay
button. Labels mirror each control's existing aria-label.
- Rename the feature term "monitoring column" → "monitoring sidebar" across the
user-facing labels (Open/Close/Resize), comments, and tests, so the UI calls
it a sidebar consistently.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95
* review: consistent sidebar wording + reuse MonitoringToggleProps (#1661)
Address the two optional notes from the PR #1662 review:
- Make the MonitoringToggle JSDoc voice consistent ("sidebar" throughout,
no lingering "column").
- Drop ViewHeader's duplicate `MonitorToggleProps` and reuse the element's
exported `MonitoringToggleProps` as the single source of truth.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95
* feat(web): slide-in/out animation for the monitoring-sidebar toggle (#1661)
The header MonitoringToggle now animates in/out via a Mantine Transition whose
in/out styles drive width + margin-left (plus opacity/translateX): as its slot
grows from 0 → the 36px icon, the flex-end header row reflows and pushes the
theme + client-settings buttons one slot to the left; the exit reverses and they
slide back over. A negative margin-left while collapsed cancels the row gap so
the theme icon stays flush-right when the toggle is absent. Only appearance/
disappearance (connect / disconnect / narrow viewport) animates — opening or
closing the sidebar leaves the toggle in place.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sMW1YZXkM7fDkdPtHpE95
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(web): audit branch-coverage outliers, raise per-file gate to 70 (#1271)
The web per-file coverage gate had drifted red: the recently-landed EMA
auth feature (core/auth/ema/*) and ClientSettings components shipped
undertested, and the prior 50% branch floor let business-logic branches
go untested. CI does not run the coverage gate, so this accumulated.
Add tests to bring every failing file above the gate and push branch
coverage well past 70 across the board, then raise the per-file branches
threshold 50 -> 70 in clients/web/vite.config.ts.
- EMA core (emaFlow, resourceContext, jwt, wire): 50-88% -> 86-100% branch
- EMA OIDC/transport (idpOidc, tokenEndpoint, transportProvider): -> 97-100%
- oauthManager / discovery: 73-83% -> 88-92%
- ClientSettingsModal/Form, ConnectionInfoContent: 0-88% -> 96-100%
- useClientSettingsDraft / useEmaIdpLoginState hooks: 20% -> 100%
- TaskStatusBadge / SortableServerCard outliers: 50% -> 100%
Coverable branches reached by mocking useComputedColorScheme (dark theme),
dnd-kit useSortable (isDragging), and fetch/OIDC paths. Remaining sub-100
branches are genuinely-unreachable defensive guards or happy-dom-inherent
(portal / useMediaQuery / typeof window) and documented in test comments.
No source files changed. Global web branch coverage 88.73% -> 90.63%.
AGENTS.md updated; cli/tui/launcher stay at 50 (out of scope).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test: raise per-file coverage gate to 90/90/90/90 across all clients
Follows the #1271 web branch-coverage audit (50 -> 70) by raising the
whole per-file gate to >=90 on all four dimensions — lines, statements,
functions, branches — for web, cli, tui, and launcher (core/ is measured
under the web suite). A codebase-wide audit added real tests for every
outlier and brought global coverage up across the board.
Config: all four vitest/vite coverage configs set to 90/90/90/90.
Two pure-type modules (core/mcp/import/types.ts, clients/web/server/
types.ts) added to the web coverage exclude list, matching the existing
type-only exclusions.
Tests: ~50 test files extended/created across core (auth, ema, mcp,
remote, state, storage, react), web components/screens/server, and the
cli/tui clients. Highlights: full EMA OAuth flow + transport coverage,
inspectorClient/remote server backfill, every Mantine control's handler
branches, and the cli unsupported-method / argv-fallback paths.
Genuinely-unreachable branches are annotated at the source with justified
`/* v8 ignore -- <reason> */` comments rather than lowering the gate:
happy-dom-inherent paths (Mantine portal, useMediaQuery, typeof window
SSR guards), React StrictMode effect replay, and provably-dead defensive
guards (?? fallbacks the types make impossible, Select.onChange values
outside the allowed list). No runtime logic changed; the only structural
edits are two behavior-preserving refactors (ResourceTemplatePanel hoists
the field value to a local so the ignore applies in JSX; ToolsScreen
swaps a ternary for an if) and prettier line-wrapping.
Also fixed a flaky real-timer debounce assertion in PromptArgumentsForm
(asserted an exact sibling-typing interleaving that raced the 300ms
debounce; now asserts the load-bearing fact — a non-empty fire-time
sibling capture).
AGENTS.md updated to describe the uniform 90 gate and the v8-ignore
policy. All four client coverage gates, root validate, storybook (370),
and smoke pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(web): make connect-crash SSE reader stop on the terminal event
`readSseEvents` looped until the server closed the stream (`done`). The
server closes the events stream immediately after writing the terminal
`transport_error`, but under the heavy parallel scheduler pressure of a
full `coverage` run (v8 instrumentation across all workers) that close
can lag far enough behind the event to trip the 30s test timeout — a
hang, not a wrong result. This made the test intermittently fail under
`npm run coverage` (it passed in isolation and under CI's lighter
`test:integration`).
Stop reading as soon as the terminal `transport_error` event arrives
(cancelling the reader) instead of waiting only for `done`. That event is
always the last one the session queue emits, so nothing is lost, and the
test no longer depends on stream-close timing. The `done` break is kept
for any stream that closes first.
Verified green across two consecutive full `npm run test:coverage` runs
(3094 tests) where it previously hung, plus isolation (~0.5s).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(web): hide resource subscription UI when server lacks subscribe capability (#1478)
Thread a `subscriptionsSupported` flag derived from
`capabilities?.resources?.subscribe === true` from App through
InspectorView → ResourcesScreen to the leaf components. When false:
- ResourcePreviewPanel hides the Subscribe/Unsubscribe button (Refresh
stays).
- ResourceControls omits the Subscriptions accordion section entirely,
dropping it from `allSections` so the expand/collapse-all toggle and
open-section bookkeeping stay correct even if a stale "subscriptions"
entry persists from a prior subscription-capable session.
The flag defaults to true at the leaf components so existing callers,
tests, and stories keep rendering the subscription controls unless a
server is explicitly marked unsupported.
Adds unit tests and Storybook stories covering the hidden and shown
states across all three components.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(web): give the Servers screen scroll the same gutter/idle-hidden treatment (#1474)
The server grid's ScrollArea.Autosize used the default type="hover" with no
offsetScrollbars, so the scrollbar popped in on hover and overlaid the right
edge of the server cards (occluding their action icons / status badges) — the
same problem #1474 fixed for the History/Network/Logging list panels.
Apply the same `type="scroll"` + `offsetScrollbars` treatment, and reuse the
shared `expectScrollbarGutterIdleHidden` story assertion to regression-protect
the gutter + idle-hidden behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(web): stop the InspectorView shell from scrolling as a whole
AppShell.Main carried Mantine's default `padding="md"` on top of the
fixed-header offset, but every screen already sizes itself to
`calc(100vh - header)` and supplies its own `xl` padding (with no
allowance for Main's padding). That extra inset pushed screen content
past the viewport, so the whole InspectorView gained a page-level
scrollbar instead of confining overflow to each screen's inner
ScrollArea.
Set the shell `padding` to 0 (Main now contributes only the header
offset, matching what the screens were built for) and clamp the Main
slot to `height: 100dvh` with `overflow: hidden` in the theme, so the
view can never scroll regardless of content — only the inner ScrollArea
regions do.
Adds an InspectorView story play assertion guarding the invariant
(Main clips + is viewport-clamped) and a ManyServers fixture that
confirms it holds under enough content to overflow, with the inner
server-grid ScrollArea absorbing the overflow.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(web): address review — align viewport units + drop stale subscriptions intent
Responding to the @claude review on #1479:
- Align all screen height calcs from `100vh` to `100dvh` so they match the
Main slot's `100dvh` clamp. On a mobile viewport where `dvh < vh` a `100vh`
child would have exceeded Main's `100dvh` content box and been clipped by
`overflow: hidden`; the units are now in lockstep.
- Restrict `intendedButEmptySections` in ResourceControls to `allSections` so a
stale "subscriptions" entry persisted from a prior subscription-capable
session is dropped from persisted open-sections instead of being perpetually
re-appended once the section is no longer rendered. Adds a regression test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(web): tool progress toasts + persist tool selection/result across navigation (#1414)
Surface incoming notifications/progress as toasts so the user can watch a
long-running tool's progress without leaving the tool view — the v2 replacement
for v1's always-visible "Server Notifications" shelf. Toasts are keyed by
progress stream and updated (not stacked) per tick so a chatty server updates
one toast rather than flooding the corner. Progress notifications still land in
the History tab via the existing transport-level tracking.
Companion change: lift the selected tool and its form values into App.tsx
alongside the already-lifted toolCallState, make ToolsScreen controlled, and
drop the clear-on-unmount effect. Leaving the Tools tab and returning now
preserves selection, inputs, and result. All three reset together on
disconnect via resetSessionScopedUiState, preserving the #1368/#1394 behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(web): persist per-screen selection/search/filter across navigation (#1417)
Lift every screen's selection, form, search, and filter state out of the
screen components into session-scoped state owned by App, passed down as
controlled props. The screens unmount on tab switch, so this is what keeps
the user's context in place when they navigate away and back within a live
session. State is cleared only on disconnect (resetSessionScopedUiState) or
an explicit user action — never on plain navigation.
Lifted per screen:
- Tools: sidebar search (selection/form/result were lifted in #1414)
- Prompts: selected prompt, argument values, submitted marker, search
- Resources: selected resource/template URI, originating-template marker,
search, accordion open-sections
- Apps: selected app, form values, search (running/maximized stay local —
they're tied to the live iframe/bridge that is torn down on unmount)
- Tasks: search + status filter
- Logs: filter text + visible-level set
- History: search + method filter
- Network: filter text + visible-category set
The four sidebar *Controls (Tool/Prompt/App/Resource) become controlled for
search; ResourceControls also controls accordion open-sections. Level/category
default maps move to logLevels.ts / fetchCategories.ts so the screen files
keep a single component export.
Pagination already persists (it lives in the App-level Paged*State managers),
so no work was needed there.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(web): persist list scroll position across navigation + reset tests (#1417)
Add useScrollMemory: a module-keyed hook that remembers a Mantine ScrollArea's
offset across unmount/remount (the screens unmount on tab switch). Scroll lives
in a module-scope map rather than threaded App state — it's ephemeral DOM state,
and threading ~16 more props would balloon the surface for no benefit. App calls
clearScrollMemory() in resetSessionScopedUiState so offsets clear on disconnect
alongside the lifted selection/filter state.
Wired into the four main list panels (Logs, History, Network, Tasks) and the
Tools/Prompts/Apps sidebar lists. Pagination already persists via the App-level
Paged*State managers.
Tests: useScrollMemory unit test (save/restore, key isolation, clear), and the
App disconnect test now also exercises representative lifted UI state (tool
search, prompt selection, log filter) clearing on disconnect.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* refactor(web): collapse per-screen lifted state into one {screen}Ui object
Replace the ~46 individual selection/search/filter props threaded App →
InspectorView → screen with one `{screen}Ui` object + one `on{Screen}UiChange`
setter per screen (8 pairs). Each screen reads its fields from `ui` and updates
via `onUiChange({ ...ui, field })`; the in-flight result panels
(toolCallState / getPromptState / readResourceState) stay separate since
they're written by App's async action handlers, not the screens.
The `*UiState` interfaces live with their screens; the empty-state defaults are
gathered in screenUiState.ts so the screen files keep a single component export
(react-refresh), mirroring logLevels.ts / fetchCategories.ts.
Trims InspectorView's prop surface substantially and keeps the persistence
behavior identical. Tests/stories collapse their stateful wrappers to a single
ui object; added Tools/Tasks/History interaction tests to keep per-file
coverage above the gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(web): dismiss visible progress toasts on client teardown (#1414 review)
The progressNotification effect cleanup cleared its id-tracking set but left
on-screen "Tool progress" toasts to auto-close up to 5s later — they could
linger into the next session, and the lingering toast's onClose could delete an
id from the new session's set and trigger a duplicate-id re-show. Hide each
tracked toast in cleanup so both gaps close. Addresses @claude review note #2.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(web): clear the tool result when a different tool is selected
The Tools result panel renders `toolCallState` regardless of which tool is
selected, so selecting a new tool used to leave the previous tool's result
showing beneath it. Route tools UI changes through an App handler that drops
`toolCallState` whenever `selectedToolName` changes; search/form edits keep the
selection (and the result) intact. Tests cover both the clear-on-switch and
keep-on-search paths.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* Port resource preview UX improvements to PromptsScreen (#1328)
Brings the prompt-fetching flow up to parity with the resource preview
work from #1326:
- Cap the argument-form pane at maw=40% so a bare input + button doesn't
stretch across wide displays.
- Auto-fetch no-argument prompts the moment they're picked from the
sidebar (handleSelectPrompt routes them straight to onGetPrompt({})),
and hide the form once the user clicks Get Prompt — the result panel
takes the same fixed-height column the resource preview uses.
- Apply the PreviewCard variant=preview pattern: card sizes to content
but caps at viewport, PromptMessagesDisplay pins its header (flex 0 0
auto) and lets the inner ScrollArea (flex 0 1 auto, mih 0) absorb
overflow.
- Tag getPromptState with the prompt name in App.tsx so the screen can
ignore a stale result whose name no longer matches the selection.
- MessageBubble now routes each content block through ContentViewer
(markdown for text via mimeType="text/markdown", image/audio/resource
via existing ContentViewer branches). Non-renderable block types
(tool_use, tool_result) are filtered out; the role-label header keeps
the bubble visible regardless.
- PromptArgumentsForm gains onCompleteArgument + completionsSupported;
when both are set, each input becomes Mantine Autocomplete with the
same per-arg AbortController + per-arg debounce timer pattern as
ResourceTemplatePanel. PromptsScreen + InspectorView + App.tsx wire
the callback to inspectorClient.getCompletions with a
ref/prompt envelope.
Closes#1328.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add close (X) buttons to ResourcePreviewPanel and PromptMessagesDisplay
A top-left CloseButton dismisses the preview panel. The host screen
decides what to fall back to:
- ResourcesScreen remembers the originating template URI when the user
reads from a template form (originatingTemplateUri); closing the
preview restores the template form. Plain-resource reads (sidebar
selection) just empty the selection and return to the empty state.
Picking a different template / resource from the sidebar clears the
back-trail.
- PromptsScreen flips submittedFor back to undefined when the closed
prompt has arguments — the argument form re-renders with the
user's values preserved so they can edit and re-submit. No-arg
prompts have nothing to fall back to, so the selection is dropped
and the empty state appears.
The X button is hidden when the host omits onClose, so callers that
don't want a dismiss control keep their existing rendering.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Add close button to pending and error preview states
The OK-state preview already had its X button (inside the panel
component itself). Pending and error states were inline cards in
renderReadState / renderPreview with no way to dismiss them, so a
user who submitted bad input to a resource template or prompt was
stuck staring at the error until they picked a different sidebar
item. Adds a top-left CloseButton row to both states on both screens,
wired to the same handleClosePreview handler — so the template form
or argument form re-appears on close just like it does from the OK
state.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fire prompt completions on focus and send every sibling in context
Two fixes to the PromptArgumentsForm autocomplete:
- Focusing an argument input now fires completion/complete immediately
(handleFocus) — the dropdown is populated as soon as the user clicks
in, not only after they start typing. Any in-flight debounce timer
for the same arg is cancelled so a stale keystroke request can't
overwrite the fresh focus response.
- The completion context now includes every declared prompt argument
(with "" for ones the user hasn't typed into yet), minus the one
being completed. Previously the context only carried args the user
had touched, so servers that disambiguate based on co-arguments
couldn't see the full picture on the first keystroke.
Tests cover both: a focus-only path that fires before any keystroke,
and a typing path that asserts the empty sibling is sent through.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fire resource-template completions on focus
Mirrors the prompt-side change: focusing a template variable input
now fires completion/complete immediately so the dropdown populates
the moment the user clicks in, rather than waiting for the first
keystroke + 300ms debounce. Any pending debounce timer for the same
variable is cancelled first so a stale keystroke response can't
overwrite the focus response.
The sibling-context coverage was already correct here — `variables`
is seeded with empty strings for every declared template variable at
mount and on template switch, so the context payload always carries
the full variable set minus the one being completed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Style Autocomplete dropdowns to match the rest of the app
Two fixes so the completion dropdowns on prompt-argument and
resource-template inputs look like every other dropdown in the app:
- App.css: the dark-mode dropdown / option-hover rules used to target
.mantine-Select-* only, so the Autocomplete dropdowns shipped with
Mantine's default surface color and a different hover background.
Re-scoped to .mantine-Combobox-* so every Combobox-built input
(Select, Autocomplete, MultiSelect, …) inherits the same styling.
- theme/Autocomplete.ts: new theme module setting `radius: "md"` so
Autocomplete matches the default Select / TextInput corner radius.
Wired through theme/index.ts and theme/theme.ts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Fix dropdown styling — Select and Autocomplete need separate selectors
The previous commit re-scoped the dark-mode dropdown rules from
`.mantine-Select-*` to `.mantine-Combobox-*` on the assumption that
both Select and Autocomplete share a Combobox class on the dropdown
root. They don't — Mantine's Combobox factory takes
`__staticSelector` from the parent component, so Select emits
`mantine-Select-dropdown` and Autocomplete emits
`mantine-Autocomplete-dropdown` with no shared `Combobox` class on
that element. The `.mantine-Combobox-*` selector matched nothing,
so the TaskControls filter (and every other Select) lost its gray
surface and reverted to Mantine's default brown-ish dark background.
List both selectors so Select dropdowns keep their styling and
Autocomplete dropdowns pick it up.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address review feedback: canSubmit, fire-time context, re-click guard
- PromptArgumentsForm: add a canSubmit guard that disables Get Prompt
until every required argument has a value, matching the resource
template form's symmetry. Optional args may stay blank.
- Both forms: capture sibling context inside the debounce callback,
not at schedule time. Hold the latest argumentValues / variables
in a ref + sync via useEffect, and call buildContext() at fire
time. Without this, typing in arg A then arg B within the 300ms
window would ship A's request with B's pre-keystroke value.
- PromptsScreen.handleSelectPrompt: early-return when the user
re-clicks the already-selected prompt — sidebar is for navigation,
✕ is for dismiss. Previously a re-click wiped form values and
re-fired the auto-fetch for no-arg prompts.
- MessageBubble: expand the comment on effectiveMimeForBlock to flag
the unconditional markdown promotion as a known asymmetry with
the resource side (which only promotes when the server signals it),
pending a per-block mimeType in the spec.
- New tests: canSubmit disabled / enabled transitions, fire-time
context capture across siblings, abort-path verification (a stale
in-flight response must not overwrite the fresh one), and the
no-op re-click guard on PromptsScreen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Address follow-up review nits: ghost suggestions, dead previewActive branch
- Clear `completions[name]` at the top of handleChange in both
PromptArgumentsForm and ResourceTemplatePanel so the dropdown
doesn't show stale options from the previous prefix during the
300ms debounce + network window.
- Simplify previewActive in PromptsScreen to drop the unreachable
`!getPromptState?.promptName` fallback. App.tsx tags every prompt
state transition with `promptName`, so the fallback was dead code
that obscured the actual runtime invariant.
- Add a focused test for each form that asserts stale dropdown
options vanish the instant a new keystroke arrives.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(coverage): bootstrap vitest unit infra and add tests at 90%+ per file (#1245)
Establishes the unit-test runtime AGENTS.md mandates: a vitest "unit"
project alongside the existing storybook project, RTL + jest-dom +
happy-dom, a Mantine-aware render helper, and a 90%-line per-file
coverage gate enforced by CI. Adds 66 test files covering all 62
components under elements/groups/screens/views, plus core/mcp and
clients/web/src/utils. Total: 577 tests, 98.7% line coverage globally.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test(coverage): address PR #1269 review feedback
- AGENTS.md: correct coverage gate description (lines ≥ 90, statements ≥ 85,
functions ≥ 80, branches ≥ 50) with rationale for the relaxed branch
threshold
- InspectorView.test.tsx: document what the Math.random() mock values
(0.1 / 0.99) control vs. STUB_SUCCESS_RATE in InspectorView.tsx
- vite.config.ts / tsconfig.test.json: drop unused `globals: true` and the
`vitest/globals` type now that every test file imports describe/it/expect/vi
explicitly; manual `afterEach(cleanup)` in setup.ts remains required because
testing-library auto-cleanup relies on globalThis.afterEach
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ToolsScreen, PromptsScreen, and ResourcesScreen each tracked the user's
current selection via `selectedXxxName` / `onSelectXxx` props, hoisting
screen-local UI state into whatever rendered them. InspectorView never
threaded those callbacks anywhere, so clicks in the controls panel did
not display the matching detail panel — the detail panel only rendered
if a parent fed selection back in.
Move selection into `useState` inside each screen and drop the
`selectedXxxName` / `onSelectXxx` props. MCP-derived data (`callState`,
`getPromptState`, `readState`) keeps flowing in from `InspectorView` as
props. ResourcesScreen wraps `onReadResource` so a template-expanded URI
becomes the selected resource for preview rendering.
Update each screen's stories to drop the deleted props. Stories that
need a pre-selected item use a `play` function to click it — no
component coupling to Storybook.
Add Phase 4.3 to the interfaces plan describing the rule.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Show a loader when GetPromptState status is "pending" and a red alert
when status is "error". Add Loading and WithError stories.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace ad hoc local types with MCP SDK schema types across the Prompts
group components and PromptsScreen, per the v2 UX interfaces plan.
- PromptListItem: accept `prompt: Prompt` instead of flat `name`/`description`;
render `title ?? name` as primary label
- PromptControls: accept `Prompt[]` + `selectedName` instead of `PromptItem[]`;
no-op on clicking already-selected prompt; search includes title field
- PromptArgumentsForm: accept `prompt: Prompt` instead of flat props;
read `prompt.arguments` directly; display `title ?? name` as heading
- PromptMessagesDisplay: narrow type from `(PromptMessage | SamplingMessage)[]`
to `PromptMessage[]` per spec
- PromptsScreen: accept `Prompt[]` + `selectedPromptName` + `GetPromptState`;
derive selected prompt via `prompts.find()`; own `argumentValues` state
locally; reset arguments on tool switch
- Delete local `PromptItem`, `SelectedPrompt`, `PromptArgument` types
- Update all stories with real SDK `Prompt` fixtures
- Update ConnectedView PromptsActive story
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Theme & styling:
- Add custom "inspector" color palette with dark navy primary
- Change primaryShade to { light: 7, dark: 8 }
- Add Input theme override to apply --inspector-input-background globally
- Add --inspector-input-background token (white in light, dark-9 in dark)
- Override --mantine-color-body in dark mode via cssVariablesResolver
in both main.tsx and Storybook preview.tsx
- Add dark-mode CSS overrides for Select dropdown and option hover
- Add dark-mode CSS override for Accordion control hover
- Rename CSS variable --inspector-status-failed → --inspector-status-error
Component changes:
- CopyButton: increase icon font size to 24px, use --inspector-text-primary
for high-contrast color (black/white per theme)
- TaskControls: remove onClearHistory (moved to TaskListPanel), fix Select
clear button not disappearing by passing null instead of undefined
- TaskListPanel: add onClearCompleted callback, render "Clear" button
next to Completed section header
- HistoryListPanel: move "Clear" button from toolbar to History section
header, rename from "Clear All"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- ToolControls and PromptControls now manage searchText as local state
and filter their lists internally (matches on name + title/description)
- Removed searchText/onSearchChange props from ToolsScreen, PromptsScreen,
and their associated stories
- HistoryListPanel search now also matches against stringified response
payloads
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Place ListChangedIndicator on same line as section titles using Group with space-between in ToolControls, ResourceControls, and PromptControls
- Add ListChanged stories for ResourceControls and show indicators in ConnectedView stories
- Normalize ScreenLayout gap from "xl" to "md" across all screens for consistent spacing
- Rename ResultPanel to ToolResultPanel (component, interface, files, and stories)
- Replace Grid layout in ToolsScreen with equal-width flex children for detail and result panels
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract ToolControls group from ToolsScreen (search, list, list-changed indicator)
- Extract PromptControls and PromptListItem groups for PromptsScreen sidebar
- Refactor PromptsScreen to sidebar + detail layout (matching ResourcesScreen pattern)
- Refactor PromptArgumentsForm to accept a single prompt instead of a dropdown
- Normalize all screen sidebar widths to 340px (Tools, Resources, Prompts, Logs, Tasks, History)
- Convert ToolsScreen from Grid-only to sidebar + Grid layout
- Replace LogControls checkboxes with full-width toggle buttons
- Move Clear/Export buttons from LogControls to LogStreamPanel toolbar
- Make PromptArgumentsForm "Get Prompt" button right-aligned and compact
- Update all affected stories and ConnectedView
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>