@molecule/app-ide-react 1.17.1 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/dist/components/ActivityCard.d.ts.map +1 -1
  2. package/dist/components/ActivityCard.js +5 -1
  3. package/dist/components/ActivityCard.js.map +1 -1
  4. package/dist/components/AutoCommitBadge.d.ts +6 -4
  5. package/dist/components/AutoCommitBadge.d.ts.map +1 -1
  6. package/dist/components/AutoCommitBadge.js +13 -36
  7. package/dist/components/AutoCommitBadge.js.map +1 -1
  8. package/dist/components/BackgroundTasksStrip.d.ts +17 -0
  9. package/dist/components/BackgroundTasksStrip.d.ts.map +1 -0
  10. package/dist/components/BackgroundTasksStrip.js +56 -0
  11. package/dist/components/BackgroundTasksStrip.js.map +1 -0
  12. package/dist/components/ChatPanel.d.ts.map +1 -1
  13. package/dist/components/ChatPanel.js +179 -206
  14. package/dist/components/ChatPanel.js.map +1 -1
  15. package/dist/components/DeviceFrameSelector.d.ts.map +1 -1
  16. package/dist/components/DeviceFrameSelector.js +12 -2
  17. package/dist/components/DeviceFrameSelector.js.map +1 -1
  18. package/dist/components/FileExplorer.d.ts.map +1 -1
  19. package/dist/components/FileExplorer.js +11 -8
  20. package/dist/components/FileExplorer.js.map +1 -1
  21. package/dist/components/FileExplorerContextMenu.d.ts.map +1 -1
  22. package/dist/components/FileExplorerContextMenu.js +4 -1
  23. package/dist/components/FileExplorerContextMenu.js.map +1 -1
  24. package/dist/components/HelpCard.d.ts.map +1 -1
  25. package/dist/components/HelpCard.js +5 -1
  26. package/dist/components/HelpCard.js.map +1 -1
  27. package/dist/components/KeyboardShortcutsPanel.d.ts.map +1 -1
  28. package/dist/components/KeyboardShortcutsPanel.js +31 -9
  29. package/dist/components/KeyboardShortcutsPanel.js.map +1 -1
  30. package/dist/components/MarkdownContent.d.ts.map +1 -1
  31. package/dist/components/MarkdownContent.js +10 -7
  32. package/dist/components/MarkdownContent.js.map +1 -1
  33. package/dist/components/PreviewPanel.d.ts.map +1 -1
  34. package/dist/components/PreviewPanel.js +52 -27
  35. package/dist/components/PreviewPanel.js.map +1 -1
  36. package/dist/components/QuickPicker.d.ts.map +1 -1
  37. package/dist/components/QuickPicker.js +11 -4
  38. package/dist/components/QuickPicker.js.map +1 -1
  39. package/dist/components/RelevantSkillSuggestion.d.ts.map +1 -1
  40. package/dist/components/RelevantSkillSuggestion.js +24 -7
  41. package/dist/components/RelevantSkillSuggestion.js.map +1 -1
  42. package/dist/components/ReportModal.d.ts.map +1 -1
  43. package/dist/components/ReportModal.js +4 -1
  44. package/dist/components/ReportModal.js.map +1 -1
  45. package/dist/components/ScriptsCard.d.ts.map +1 -1
  46. package/dist/components/ScriptsCard.js +6 -4
  47. package/dist/components/ScriptsCard.js.map +1 -1
  48. package/dist/components/SearchPanel.d.ts.map +1 -1
  49. package/dist/components/SearchPanel.js +65 -54
  50. package/dist/components/SearchPanel.js.map +1 -1
  51. package/dist/components/SettingsCard.d.ts.map +1 -1
  52. package/dist/components/SettingsCard.js +1 -1
  53. package/dist/components/SettingsCard.js.map +1 -1
  54. package/dist/components/ShareLinkManager.d.ts.map +1 -1
  55. package/dist/components/ShareLinkManager.js +5 -5
  56. package/dist/components/ShareLinkManager.js.map +1 -1
  57. package/dist/components/ShareModal.js +1 -1
  58. package/dist/components/ShareModal.js.map +1 -1
  59. package/dist/components/SidebarTabs.d.ts.map +1 -1
  60. package/dist/components/SidebarTabs.js +7 -5
  61. package/dist/components/SidebarTabs.js.map +1 -1
  62. package/dist/components/SkillsCard.d.ts.map +1 -1
  63. package/dist/components/SkillsCard.js +15 -7
  64. package/dist/components/SkillsCard.js.map +1 -1
  65. package/dist/components/TabBar.d.ts.map +1 -1
  66. package/dist/components/TabBar.js +11 -6
  67. package/dist/components/TabBar.js.map +1 -1
  68. package/dist/components/TestsCard.js +4 -4
  69. package/dist/components/TestsCard.js.map +1 -1
  70. package/dist/components/TipCard.d.ts.map +1 -1
  71. package/dist/components/TipCard.js +6 -2
  72. package/dist/components/TipCard.js.map +1 -1
  73. package/dist/components/ToolCallCard.d.ts.map +1 -1
  74. package/dist/components/ToolCallCard.js +89 -46
  75. package/dist/components/ToolCallCard.js.map +1 -1
  76. package/dist/components/UserAvatar.d.ts.map +1 -1
  77. package/dist/components/UserAvatar.js +9 -1
  78. package/dist/components/UserAvatar.js.map +1 -1
  79. package/dist/components/tool-call-utilities.d.ts.map +1 -1
  80. package/dist/components/tool-call-utilities.js +46 -2
  81. package/dist/components/tool-call-utilities.js.map +1 -1
  82. package/package.json +3 -3
@@ -16,8 +16,9 @@ import { useCoarsePointer, useNarrowViewport } from '../hooks/useViewport.js';
16
16
  import { activityFromEvent } from './activity-utilities.js';
17
17
  import { ActivityCard } from './ActivityCard.js';
18
18
  import { AutoCommitBadge } from './AutoCommitBadge.js';
19
+ import { BackgroundTasksStrip } from './BackgroundTasksStrip.js';
19
20
  import { AUTO_COMMIT_DISABLED, autoCommitReducer, isAutoCommitArmed, isAutoCommitDue, isAutoCommitEnabled, parseAutoCommitCommand, resolveAutoCommitSeconds, } from './chat-autocommit-utilities.js';
20
- import { CHAT_CARD_ICON_SIZE, chatCardBorder, chatCardStyle } from './chat-card-style.js';
21
+ import { CHAT_CARD_ICON_SIZE, chatCardStyle } from './chat-card-style.js';
21
22
  import { COMMAND_CATEGORIES, COMMANDS, matchesSideChannelCommand, } from './chat-commands.js';
22
23
  import { stripCommitCoauthorTrailer } from './chat-commit-utilities.js';
23
24
  import { cachedPromptTokens, formatTokenTotal } from './chat-cost-utilities.js';
@@ -477,7 +478,9 @@ function ThinkingBlock({ content, durationMs, isStreaming, }) {
477
478
  : durationMs != null
478
479
  ? formatThinkingDuration(durationMs)
479
480
  : t('ide.chat.thoughtBriefly', undefined, { defaultValue: 'Thought briefly' });
480
- return (_jsxs("div", { style: { marginBottom: '6px' }, children: [_jsxs("button", { type: "button", onClick: () => setManualToggle((v) => !(v ?? isStreaming === true)), style: {
481
+ return (_jsxs("div", { style: { marginBottom: '6px' }, children: [_jsxs("button", {
482
+ /* mol-bespoke-button: thinking disclosure toggle — chevron + muted label, a summary/details affordance with no button frame */
483
+ type: "button", onClick: () => setManualToggle((v) => !(v ?? isStreaming === true)), style: {
481
484
  display: 'inline-flex',
482
485
  alignItems: 'center',
483
486
  gap: '4px',
@@ -586,7 +589,9 @@ function CollapsibleUserMessage({ content, isLight, }) {
586
589
  ? 'linear-gradient(transparent, var(--mol-color-surface-secondary, #f5f5f5))'
587
590
  : 'linear-gradient(transparent, var(--mol-color-surface-secondary, #1e1e1e))',
588
591
  pointerEvents: 'none',
589
- } })), overflows && (_jsx("button", { type: "button", onClick: () => setExpanded((v) => !v), onMouseEnter: (e) => {
592
+ } })), overflows && (_jsx("button", {
593
+ /* mol-bespoke-button: overflow disclosure strip — full-width unlabelled chevron that expands a clipped card */
594
+ type: "button", onClick: () => setExpanded((v) => !v), onMouseEnter: (e) => {
590
595
  ;
591
596
  e.currentTarget.style.background = isLight
592
597
  ? 'rgba(99,102,241,0.12)'
@@ -675,7 +680,9 @@ function VerificationBadge({ status, output, categories, }) {
675
680
  border: `1px solid ${borderColor}`,
676
681
  background: bgColor,
677
682
  overflow: 'hidden',
678
- }, children: [_jsxs("button", { type: "button", onClick: () => setExpanded((v) => !v), className: cm.cn(cm.textSize('xs'), cm.w('full')), style: {
683
+ }, children: [_jsxs("button", {
684
+ /* mol-bespoke-button: verify-error card header — the card's own expand/collapse header, tinted by severity; a disclosure, not an action */
685
+ type: "button", onClick: () => setExpanded((v) => !v), className: cm.cn(cm.textSize('xs'), cm.w('full')), style: {
679
686
  display: 'flex',
680
687
  alignItems: 'center',
681
688
  gap: 6,
@@ -719,10 +726,26 @@ const NOTICE_TONE = {
719
726
  success: { accent: '#3fb950', icon: 'check-circle' },
720
727
  signup: { accent: 'var(--mol-color-primary, #6366f1)', icon: 'sign-in' },
721
728
  };
729
+ /**
730
+ * The SEMANTIC button colour each notice tone falls back to when the host gives
731
+ * an action no explicit `color`. Every notice-card action is a design-system
732
+ * button; this is only about which semantic it takes when the caller did not
733
+ * say. Without it a coloured action and a colourless one rendered side by side
734
+ * in the SAME card with two different box models (13px/3px vs a hand-rolled
735
+ * 12px/6px) — the exact mismatch this treatment exists to prevent.
736
+ */
737
+ const NOTICE_TONE_BUTTON_COLOR = {
738
+ info: 'primary',
739
+ gold: 'warning',
740
+ upgrade: 'warning',
741
+ success: 'success',
742
+ signup: 'primary',
743
+ };
722
744
  /**
723
745
  * The single shared notice-card treatment: a matched-weight accent {@link Icon},
724
- * an optional composable body (or plain text), and a left-aligned row of accent
725
- * outline action buttons. EVERY inline notice renders through this — the system
746
+ * an optional composable body (or plain text), and a left-aligned row of
747
+ * design-system action buttons (`cm.button`, `sm`) whose semantic colour comes
748
+ * from the action or, failing that, the tone. EVERY inline notice renders through this — the system
726
749
  * tip/notice cards AND the resource-limit / upgrade banners (see
727
750
  * {@link ResourceLimitBanner}) — so their icon + buttons can never drift apart
728
751
  * again. The host owns the button routes/copy; it passes them in as `action`.
@@ -732,24 +755,13 @@ const NOTICE_TONE = {
732
755
  */
733
756
  function NoticeCard({ tone, text, content, action, icon: iconOverride, }) {
734
757
  const cm = getClassMap();
735
- const isCoarse = useCoarsePointer();
736
758
  const { accent, icon: defaultIcon } = NOTICE_TONE[tone];
737
759
  const icon = iconOverride ?? defaultIcon;
738
760
  const actions = action ? (Array.isArray(action) ? action : [action]) : [];
739
761
  const multiLine = (text ?? '').includes('\n');
740
- // Buttons sit ON the card's tint, so they need their OWN opaque background to read
741
- // as real buttons (a transparent "ghost" fill blends into the card). Opaque surface
742
- // + a stronger accent border than the card frame + a hairline shadow.
743
- const buttonBg = 'var(--mol-color-surface, transparent)';
744
- const buttonHoverBg = `color-mix(in srgb, ${accent} 15%, var(--mol-color-surface, transparent))`;
745
- const onEnter = (e) => {
746
- ;
747
- e.currentTarget.style.background = buttonHoverBg;
748
- };
749
- const onLeave = (e) => {
750
- ;
751
- e.currentTarget.style.background = buttonBg;
752
- };
762
+ // The semantic colour an action takes when the host did not name one, so every
763
+ // action on the card renders the same design-system button.
764
+ const defaultActionColor = NOTICE_TONE_BUTTON_COLOR[tone];
753
765
  return (_jsxs("div", { "data-mol-id": "chat-notice-card", "data-tone": tone, className: cm.textSize('xs'), style: {
754
766
  display: 'flex',
755
767
  alignItems: 'flex-start',
@@ -758,41 +770,20 @@ function NoticeCard({ tone, text, content, action, icon: iconOverride, }) {
758
770
  ...chatCardStyle(accent),
759
771
  lineHeight: 1.5,
760
772
  }, children: [_jsx(Icon, { name: icon, size: CHAT_CARD_ICON_SIZE, "aria-hidden": "true", style: { flexShrink: 0, marginTop: 1, color: accent } }), _jsxs("div", { style: { flex: 1, minWidth: 0 }, children: [content ? (content.map((seg, i) => renderCardSegment(seg, i))) : (_jsx("span", { style: multiLine ? { whiteSpace: 'pre-wrap' } : undefined, children: text })), !content && actions.length > 0 && (_jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: 8, marginTop: 8 }, children: actions.map((act, i) => {
761
- // An action with a semantic `color` renders as a REAL design-system
762
- // button (`cm.button`, sm) so the same CTA looks identical wherever
763
- // the app shows it (auth page, banners, chat cards). No inline
764
- // colors — the ClassMap owns the look, including hover states.
765
- // Colorless actions keep the legacy accent-outline treatment.
766
- if (act.color) {
767
- // touchTargetCompact (36px), not the full 44px touchTarget — these
768
- // sit inside a dense chat card (the floor agreed for its actions).
769
- const className = cm.cn(cm.button({ color: act.color, size: 'sm' }), cm.touchTargetCompact);
770
- const coloredStyle = {
771
- textDecoration: 'none',
772
- fontFamily: act.code ? 'var(--mol-font-mono, monospace)' : 'inherit',
773
- };
774
- return act.href ? (_jsx("a", { href: act.href, target: act.href.startsWith('http') ? '_blank' : undefined, rel: act.href.startsWith('http') ? 'noopener noreferrer' : undefined, className: className, style: coloredStyle, children: act.label }, i)) : (_jsx("button", { type: "button", onClick: act.onClick, className: className, style: coloredStyle, children: act.label }, i));
775
- }
776
- const style = {
777
- display: 'inline-flex',
778
- alignItems: 'center',
779
- fontSize: 12,
780
- fontWeight: 600,
781
- padding: '4px 10px',
782
- // Secondary inline actions: 36px is the touch floor agreed for
783
- // these (44 would overwhelm the compact card).
784
- ...(isCoarse ? { minHeight: 36 } : {}),
785
- borderRadius: 6,
786
- cursor: 'pointer',
773
+ // EVERY action is a REAL design-system button (`cm.button`, sm) so the
774
+ // same CTA looks identical wherever the app shows it (auth page,
775
+ // banners, chat cards) — and so two actions on the SAME card can't
776
+ // render two different box models. The host names the semantic colour
777
+ // when it has one; otherwise the tone supplies it. No inline colors —
778
+ // the ClassMap owns the look, including hover/active/focus states.
779
+ // touchTargetCompact (36px), not the full 44px touchTarget — these sit
780
+ // inside a dense chat card (the floor agreed for its actions).
781
+ const className = cm.cn(cm.button({ color: act.color ?? defaultActionColor, size: 'sm' }), cm.touchTargetCompact);
782
+ const actionStyle = {
787
783
  textDecoration: 'none',
788
784
  fontFamily: act.code ? 'var(--mol-font-mono, monospace)' : 'inherit',
789
- border: `1px solid ${chatCardBorder(accent, 55)}`,
790
- color: accent,
791
- background: buttonBg,
792
- boxShadow: '0 1px 2px rgba(0, 0, 0, 0.08)',
793
- transition: 'background 100ms',
794
785
  };
795
- return act.href ? (_jsx("a", { href: act.href, target: act.href.startsWith('http') ? '_blank' : undefined, rel: act.href.startsWith('http') ? 'noopener noreferrer' : undefined, style: style, onMouseEnter: onEnter, onMouseLeave: onLeave, children: act.label }, i)) : (_jsx("button", { type: "button", onClick: act.onClick, style: style, onMouseEnter: onEnter, onMouseLeave: onLeave, children: act.label }, i));
786
+ return act.href ? (_jsx("a", { href: act.href, target: act.href.startsWith('http') ? '_blank' : undefined, rel: act.href.startsWith('http') ? 'noopener noreferrer' : undefined, className: className, style: actionStyle, children: act.label }, i)) : (_jsx("button", { type: "button", onClick: act.onClick, className: className, style: actionStyle, children: act.label }, i));
796
787
  }) }))] })] }));
797
788
  }
798
789
  // ResourceLimitBanner — upgrade prompt when sandbox runs out of memory / a limit hits
@@ -855,7 +846,9 @@ export function CommitCardItem({ card, onRevert, }) {
855
846
  setIsReverting(false);
856
847
  }
857
848
  }, [canRevert, isReverting, isReverted, revertHash, card.hash, onRevert]);
858
- return (_jsx("div", { style: { marginBottom: TIMELINE_ITEM_GAP }, children: _jsxs("div", { style: { marginBottom: '4px' }, children: [_jsxs("button", { type: "button", onClick: hasFiles ? () => setExpanded((e) => !e) : undefined, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), style: {
849
+ return (_jsx("div", { style: { marginBottom: TIMELINE_ITEM_GAP }, children: _jsxs("div", { style: { marginBottom: '4px' }, children: [_jsxs("button", {
850
+ /* mol-bespoke-button: commit card header — expand/collapse disclosure for the commit's file list */
851
+ type: "button", onClick: hasFiles ? () => setExpanded((e) => !e) : undefined, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), style: {
859
852
  display: 'flex',
860
853
  alignItems: 'flex-start',
861
854
  gap: '6px',
@@ -884,7 +877,9 @@ export function CommitCardItem({ card, onRevert, }) {
884
877
  }, children: isRunning ? (t('ide.chat.committing', undefined, { defaultValue: 'Committing' })) : (_jsxs(_Fragment, { children: [t('ide.chat.commitLabel', undefined, { defaultValue: 'Commit' }), ' ', _jsx("code", { style: {
885
878
  fontFamily: '"SF Mono", Menlo, Consolas, "Courier New", monospace',
886
879
  fontSize: 'inherit',
887
- }, children: stripCommitCoauthorTrailer(card.message) })] })) }), canRevert && (_jsx("span", { role: "button", tabIndex: 0, title: isReverted
880
+ }, children: stripCommitCoauthorTrailer(card.message) })] })) }), canRevert && (_jsx("span", {
881
+ /* mol-bespoke-button: icon-only revert affordance — 20px (32px coarse) hit box inside a dense commit row, no label */
882
+ role: "button", tabIndex: 0, title: isReverted
888
883
  ? t('ide.chat.redoCommit', undefined, {
889
884
  defaultValue: 'Re-apply this commit',
890
885
  })
@@ -952,7 +947,9 @@ export function CommitCardItem({ card, onRevert, }) {
952
947
  */
953
948
  function AuthorNameButton({ onClick, children, }) {
954
949
  const [hover, setHover] = useState(false);
955
- return (_jsx("button", { type: "button", onClick: onClick, onMouseEnter: () => setHover(true), onMouseLeave: () => setHover(false), onFocus: () => setHover(true), onBlur: () => setHover(false), "data-mol-id": "chat-user-name-button",
950
+ return (_jsx("button", {
951
+ /* mol-bespoke-button: author name — a full <button> reset so the name renders byte-identical to the bold span it replaced; hover underline is the only affordance */
952
+ type: "button", onClick: onClick, onMouseEnter: () => setHover(true), onMouseLeave: () => setHover(false), onFocus: () => setHover(true), onBlur: () => setHover(false), "data-mol-id": "chat-user-name-button",
956
953
  // Full button reset so it is byte-identical to the former bold span at
957
954
  // rest — the underline affordance is the only visual change on hover.
958
955
  style: {
@@ -1579,7 +1576,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
1579
1576
  }
1580
1577
  onFileChange?.(path, content);
1581
1578
  }, [onFileChange, onFileOpen, autoFixCountdown]);
1582
- const { messages, isLoading, isRemoteStreaming, noteRemoteStreamEvent, error, errorMeta, mode, fastMode, streamingStatus, setMode, setFastMode, sendMessage, abort, clearHistory, editQueuedMessage, deleteQueuedMessage, clearQueuedForFile, applyRemoteEvent, reconcileHistory, retryCountdown, cancelRetry, } = useChat({
1579
+ const { messages, isLoading, isRemoteStreaming, noteRemoteStreamEvent, error, errorMeta, mode, fastMode, streamingStatus, backgroundTasks, setMode, setFastMode, sendMessage, abort, clearHistory, editQueuedMessage, deleteQueuedMessage, clearQueuedForFile, applyRemoteEvent, reconcileHistory, retryCountdown, cancelRetry, } = useChat({
1583
1580
  endpoint,
1584
1581
  projectId,
1585
1582
  agentName,
@@ -5922,14 +5919,12 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
5922
5919
  textAlign: 'center',
5923
5920
  }, children: [_jsx(Icon, { name: "logo-mark", size: 28, "aria-hidden": "true", style: { opacity: 0.5 } }), _jsx("span", { style: { maxWidth: 320 }, children: t('ide.chat.emptyState', undefined, {
5924
5921
  defaultValue: 'Describe what you want to build...',
5925
- }) })] })), timeline.length > maxVisibleItems && (_jsx("div", { style: { textAlign: 'center', padding: '8px 0' }, children: _jsx("button", { onClick: () => setMaxVisibleItems((n) => n + 40), className: cm.cn(cm.textSize('xs'), cm.textMuted), style: {
5926
- background: 'none',
5927
- border: '1px solid currentColor',
5928
- borderRadius: 4,
5929
- padding: '4px 12px',
5930
- cursor: 'pointer',
5931
- opacity: 0.7,
5932
- }, children: t('ide.chat.showEarlier', undefined, {
5922
+ }) })] })), timeline.length > maxVisibleItems && (_jsx("div", { style: { textAlign: 'center', padding: '8px 0' }, children: _jsx("button", { type: "button", "data-mol-id": "chat-show-earlier", onClick: () => setMaxVisibleItems((n) => n + 40),
5923
+ // A quiet, non-committal timeline action — SECONDARY, the semantic
5924
+ // DESIGN.md reserves for what sits beside the real CTAs. Box model,
5925
+ // type scale and hover come from the ClassMap instead of the
5926
+ // hand-rolled 4px-radius currentColor frame this used to be.
5927
+ className: cm.cn(cm.button({ variant: 'solid', color: 'secondary', size: 'xs' }), cm.touchTargetCompact), children: t('ide.chat.showEarlier', undefined, {
5933
5928
  defaultValue: 'Show earlier messages',
5934
5929
  }) }) })), renderedTimeline.map((item) => (_jsx(ChatItemBoundary, { onError: onRenderError, render: () => withTimelineTimestamp(item, (() => {
5935
5930
  if (item.kind === 'commit')
@@ -5982,7 +5977,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
5982
5977
  // from `count` if a caller passed none.
5983
5978
  const skillsLoadedLabel = item.card.text ||
5984
5979
  t('ide.chat.skills.loadedCount', { count: item.card.count ?? 0 }, { defaultValue: '🧠 Loaded {{count}} skills' });
5985
- return (_jsx("div", { style: { textAlign: 'center', marginBottom: TIMELINE_ITEM_GAP }, children: _jsx("button", { type: "button", "data-mol-id": "chat-skills-loaded", onClick: () => openPanelOverlay('skills'), className: cm.cn(cm.textSize('xs'), cm.textMuted), style: {
5980
+ return (_jsx("div", { style: { textAlign: 'center', marginBottom: TIMELINE_ITEM_GAP }, children: _jsx("button", {
5981
+ /* mol-bespoke-button: skills-loaded notice — deliberately a plain centered phase message that happens to be clickable; a button frame would make it shout */
5982
+ type: "button", "data-mol-id": "chat-skills-loaded", onClick: () => openPanelOverlay('skills'), className: cm.cn(cm.textSize('xs'), cm.textMuted), style: {
5986
5983
  // Plain text like the build-phase notice — no border/fill/pill.
5987
5984
  background: 'none',
5988
5985
  border: 'none',
@@ -6121,7 +6118,7 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6121
6118
  pointerEvents: showActivity ? 'auto' : 'none',
6122
6119
  transition: 'opacity 0.18s ease-out',
6123
6120
  }, children: showActivity && (_jsx(StreamingIndicator, { label: label, tokens: streamingLike ? turnTokens : undefined, startedAt: streamingLike ? turnStartedAt : undefined })) }));
6124
- })(), _jsx("div", { ref: messagesEndRef })] }), autoFixCountdown && (_jsxs("div", { className: cm.cn(cm.shrink0, cm.borderT), style: {
6121
+ })(), _jsx("div", { ref: messagesEndRef })] }), _jsx(BackgroundTasksStrip, { tasks: backgroundTasks }), autoFixCountdown && (_jsxs("div", { className: cm.cn(cm.shrink0, cm.borderT), style: {
6125
6122
  display: 'flex',
6126
6123
  alignItems: 'center',
6127
6124
  gap: 8,
@@ -6132,31 +6129,15 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6132
6129
  ? t('ide.chat.autoFixPaused', undefined, { defaultValue: 'Auto-fix paused' })
6133
6130
  : t('ide.chat.autoFixCountdown', { seconds: autoFixCountdown.secondsLeft }, {
6134
6131
  defaultValue: `Auto-fixing in ${autoFixCountdown.secondsLeft}s...`,
6135
- }) }), autoFixCountdown.paused ? (_jsx("button", { type: "button", onClick: () => setAutoFixCountdown((prev) => prev ? { ...prev, paused: false, secondsLeft: 3 } : prev), style: {
6136
- fontSize: 11,
6137
- padding: '2px 8px',
6138
- borderRadius: 4,
6139
- border: '1px solid rgba(128,128,128,0.3)',
6140
- background: 'transparent',
6141
- color: 'inherit',
6142
- cursor: 'pointer',
6143
- }, children: t('ide.chat.autoFixResume', undefined, { defaultValue: 'Resume' }) })) : (_jsx("button", { type: "button", onClick: () => setAutoFixCountdown((prev) => (prev ? { ...prev, paused: true } : prev)), style: {
6144
- fontSize: 11,
6145
- padding: '2px 8px',
6146
- borderRadius: 4,
6147
- border: '1px solid rgba(128,128,128,0.3)',
6148
- background: 'transparent',
6149
- color: 'inherit',
6150
- cursor: 'pointer',
6151
- }, children: t('ide.chat.autoFixPause', undefined, { defaultValue: 'Pause' }) })), _jsx("button", { type: "button", onClick: () => setAutoFixCountdown(null), style: {
6152
- fontSize: 11,
6153
- padding: '2px 8px',
6154
- borderRadius: 4,
6155
- border: '1px solid rgba(128,128,128,0.3)',
6156
- background: 'transparent',
6157
- color: 'inherit',
6158
- cursor: 'pointer',
6159
- }, children: t('ide.chat.autoFixCancel', undefined, { defaultValue: 'Cancel' }) })] })), retryCountdown && (_jsxs("div", { className: cm.cn(cm.shrink0, cm.borderT), "data-mol-id": "chat-retry-countdown", style: {
6132
+ }) }), autoFixCountdown.paused ? (_jsx("button", { type: "button", "data-mol-id": "chat-autofix-resume", onClick: () => setAutoFixCountdown((prev) => prev ? { ...prev, paused: false, secondsLeft: 3 } : prev),
6133
+ // This strip and the retry strip below it now share one button
6134
+ // treatment, so a user never sees four near-identical controls at
6135
+ // four slightly different sizes (they were 11px/4px-radius
6136
+ // hand-rolled frames with a hardcoded grey border). Semantics per
6137
+ // DESIGN.md's CTA table: Resume is the affirmative action
6138
+ // (primary), its sibling Pause is pause-like (warning), and the
6139
+ // Cancels are quiet dismissals (secondary).
6140
+ className: cm.cn(cm.button({ variant: 'solid', color: 'primary', size: 'xs' }), cm.touchTargetCompact), children: t('ide.chat.autoFixResume', undefined, { defaultValue: 'Resume' }) })) : (_jsx("button", { type: "button", "data-mol-id": "chat-autofix-pause", onClick: () => setAutoFixCountdown((prev) => (prev ? { ...prev, paused: true } : prev)), className: cm.cn(cm.button({ variant: 'solid', color: 'warning', size: 'xs' }), cm.touchTargetCompact), children: t('ide.chat.autoFixPause', undefined, { defaultValue: 'Pause' }) })), _jsx("button", { type: "button", "data-mol-id": "chat-autofix-cancel", onClick: () => setAutoFixCountdown(null), className: cm.cn(cm.button({ variant: 'solid', color: 'secondary', size: 'xs' }), cm.touchTargetCompact), children: t('ide.chat.autoFixCancel', undefined, { defaultValue: 'Cancel' }) })] })), retryCountdown && (_jsxs("div", { className: cm.cn(cm.shrink0, cm.borderT), "data-mol-id": "chat-retry-countdown", style: {
6160
6141
  display: 'flex',
6161
6142
  alignItems: 'center',
6162
6143
  gap: 8,
@@ -6165,15 +6146,11 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6165
6146
  background: 'rgba(234,179,8,0.06)',
6166
6147
  }, children: [_jsx(Icon, { name: "exclamation-triangle", size: 14, "aria-hidden": "true", style: { flexShrink: 0, color: '#d4a017' } }), _jsx("span", { style: { flex: 1, opacity: 0.85 }, children: t('ide.chat.retryCountdown', { seconds: retryCountdown.secondsRemaining, attempt: retryCountdown.attempt }, {
6167
6148
  defaultValue: `Server error — retrying in ${retryCountdown.secondsRemaining}s… (attempt ${retryCountdown.attempt})`,
6168
- }) }), _jsx("button", { type: "button", "data-mol-id": "chat-retry-cancel", onClick: cancelRetry, style: {
6169
- fontSize: 11,
6170
- padding: '2px 8px',
6171
- borderRadius: 4,
6172
- border: '1px solid rgba(128,128,128,0.3)',
6173
- background: 'transparent',
6174
- color: 'inherit',
6175
- cursor: 'pointer',
6176
- }, children: t('ide.chat.autoFixCancel', undefined, { defaultValue: 'Cancel' }) })] })), _jsxs("div", { className: cm.shrink0, style: { position: 'relative' }, children: [relevantSkill && (_jsx(RelevantSkillSuggestion, { skill: relevantSkill, onLoad: loadSkill, onOpen: (s) => onFileOpen?.(s.path, { focus: true }), onDismiss: dismissRelevantSkill })), attachmentError && (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textError), style: { padding: '4px 10px' }, children: attachmentError })), voiceError && (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textError), style: { padding: '4px 10px' }, children: voiceError })), voiceNotice && (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textMuted), style: { padding: '4px 10px' }, children: voiceNotice })), attachedFiles.length > 0 && (_jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: '4px', padding: '6px 10px 0' }, children: attachedFiles.map((f) => {
6149
+ }) }), _jsx("button", { type: "button", "data-mol-id": "chat-retry-cancel", onClick: cancelRetry,
6150
+ // The same button as the auto-fix strip's Cancel directly above it —
6151
+ // the two strips mirror each other, and DESIGN.md's rule is that one
6152
+ // action keeps one colour on every surface.
6153
+ className: cm.cn(cm.button({ variant: 'solid', color: 'secondary', size: 'xs' }), cm.touchTargetCompact), children: t('ide.chat.autoFixCancel', undefined, { defaultValue: 'Cancel' }) })] })), _jsxs("div", { className: cm.shrink0, style: { position: 'relative' }, children: [relevantSkill && (_jsx(RelevantSkillSuggestion, { skill: relevantSkill, onLoad: loadSkill, onOpen: (s) => onFileOpen?.(s.path, { focus: true }), onDismiss: dismissRelevantSkill })), attachmentError && (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textError), style: { padding: '4px 10px' }, children: attachmentError })), voiceError && (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textError), style: { padding: '4px 10px' }, children: voiceError })), voiceNotice && (_jsx("div", { className: cm.cn(cm.textSize('xs'), cm.textMuted), style: { padding: '4px 10px' }, children: voiceNotice })), attachedFiles.length > 0 && (_jsx("div", { style: { display: 'flex', flexWrap: 'wrap', gap: '4px', padding: '6px 10px 0' }, children: attachedFiles.map((f) => {
6177
6154
  const key = f.path ?? f.filename;
6178
6155
  return (_jsxs("span", { className: cm.cn(cm.surfaceSecondary, cm.textSize('xs')), style: {
6179
6156
  display: 'inline-flex',
@@ -6181,7 +6158,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6181
6158
  gap: '4px',
6182
6159
  borderRadius: '4px',
6183
6160
  padding: '2px 6px',
6184
- }, children: [f.previewUrl && (_jsx("img", { src: f.previewUrl, alt: f.filename, style: { width: 18, height: 18, objectFit: 'cover', borderRadius: 2 } })), _jsx("span", { style: { fontFamily: 'monospace', opacity: 0.85 }, children: f.path ? f.path.split('/').pop() : f.filename }), f.size > 0 && (_jsx("span", { className: cm.textMuted, style: { fontSize: 10 }, children: formatSize(f.size) })), _jsx("button", { type: "button", onClick: () => removeAttachment(key), style: {
6161
+ }, children: [f.previewUrl && (_jsx("img", { src: f.previewUrl, alt: f.filename, style: { width: 18, height: 18, objectFit: 'cover', borderRadius: 2 } })), _jsx("span", { style: { fontFamily: 'monospace', opacity: 0.85 }, children: f.path ? f.path.split('/').pop() : f.filename }), f.size > 0 && (_jsx("span", { className: cm.textMuted, style: { fontSize: 10 }, children: formatSize(f.size) })), _jsx("button", {
6162
+ /* mol-bespoke-button: attachment chip remove — icon-only x inside a 2px-padded chip, 32px coarse hit box */
6163
+ type: "button", onClick: () => removeAttachment(key), style: {
6185
6164
  background: 'none',
6186
6165
  border: 'none',
6187
6166
  cursor: 'pointer',
@@ -6507,7 +6486,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6507
6486
  textOverflow: 'ellipsis',
6508
6487
  }, children: [_jsx("option", { value: "name", children: t('ide.chat.models.colName', undefined, { defaultValue: 'Model' }) }), _jsx("option", { value: "context", children: t('ide.chat.models.colContext', undefined, { defaultValue: 'Context' }) }), _jsx("option", { value: "cost", children: t('ide.chat.models.colUsageRate', undefined, { defaultValue: 'Usage rate' }) }), _jsx("option", { value: "cutoff", children: t('ide.chat.models.colCutoff', undefined, { defaultValue: 'Cutoff' }) }), _jsx("option", { value: "free", children: t('ide.chat.models.colFree', undefined, { defaultValue: 'Free' }) }), _jsx("option", { value: "region", children: t('ide.chat.models.colRegion', undefined, { defaultValue: 'Region' }) })] }), _jsx(Tooltip, { content: t('ide.chat.modelSortDirection', undefined, {
6509
6488
  defaultValue: 'Toggle sort direction',
6510
- }), placement: "top", children: _jsx("button", { type: "button", "data-mol-id": "model-sort-direction", "aria-label": t('ide.chat.modelSortDirection', undefined, {
6489
+ }), placement: "top", children: _jsx("button", {
6490
+ /* mol-bespoke-button: icon-only sort-direction toggle — 24px square matched to the adjacent selects' height */
6491
+ type: "button", "data-mol-id": "model-sort-direction", "aria-label": t('ide.chat.modelSortDirection', undefined, {
6511
6492
  defaultValue: 'Toggle sort direction',
6512
6493
  }), onClick: () => setModelSort((s) => ({
6513
6494
  ...s,
@@ -6623,14 +6604,18 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6623
6604
  : isLight
6624
6605
  ? 'rgb(220,38,38)'
6625
6606
  : 'rgb(248,113,113)';
6626
- return (_jsxs(Fragment, { children: [dividerBefore && (_jsx("button", { type: "button", onClick: () => setShowDeprecated((s) => !s), className: cm.cn(cm.textSize('xs'), cm.textMuted, cm.w('full')), style: {
6607
+ return (_jsxs(Fragment, { children: [dividerBefore && (_jsx("button", {
6608
+ /* mol-bespoke-button: older-models collapse row — full-width disclosure row inside the model list */
6609
+ type: "button", onClick: () => setShowDeprecated((s) => !s), className: cm.cn(cm.textSize('xs'), cm.textMuted, cm.w('full')), style: {
6627
6610
  padding: '6px 12px',
6628
6611
  border: 'none',
6629
6612
  borderTop: '1px solid rgba(128,128,128,0.12)',
6630
6613
  background: 'rgba(128,128,128,0.04)',
6631
6614
  cursor: 'pointer',
6632
6615
  textAlign: 'left',
6633
- }, children: t('ide.chat.olderModelsCollapse', { count: deprecatedModels.length }, { defaultValue: 'Older models ⌃ ({{count}})' }) })), _jsxs("button", { type: "button", onClick: () => {
6616
+ }, children: t('ide.chat.olderModelsCollapse', { count: deprecatedModels.length }, { defaultValue: 'Older models ⌃ ({{count}})' }) })), _jsxs("button", {
6617
+ /* mol-bespoke-button: model row — full-width list item in the model picker */
6618
+ type: "button", onClick: () => {
6634
6619
  if (lockReason === 'paid') {
6635
6620
  setModelPicker(null);
6636
6621
  setInputValue('');
@@ -6882,14 +6867,18 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6882
6867
  }, children: [_jsx(RegionFlag, { code: rMeta?.flagCode ?? r, height: 12 }), _jsx("span", { children: rLabel }), _jsxs("span", { className: active ? undefined : cm.textMuted, style: { fontSize: '10px' }, children: ["(", t('ide.chat.models.usageRateValue', { rate: rRate }, { defaultValue: '×{{rate}}' }), ")"] })] }, r));
6883
6868
  }) }))] }));
6884
6869
  })()] }))] })] }, model.id));
6885
- }), !showDeprecated && deprecatedModels.length > 0 && (_jsx("button", { type: "button", onClick: () => setShowDeprecated(true), className: cm.cn(cm.textSize('xs'), cm.textMuted, cm.w('full')), style: {
6870
+ }), !showDeprecated && deprecatedModels.length > 0 && (_jsx("button", {
6871
+ /* mol-bespoke-button: older-models expand row — full-width disclosure row inside the model list */
6872
+ type: "button", onClick: () => setShowDeprecated(true), className: cm.cn(cm.textSize('xs'), cm.textMuted, cm.w('full')), style: {
6886
6873
  padding: '6px 12px',
6887
6874
  border: 'none',
6888
6875
  borderTop: '1px solid rgba(128,128,128,0.12)',
6889
6876
  background: 'rgba(128,128,128,0.04)',
6890
6877
  cursor: 'pointer',
6891
6878
  textAlign: 'left',
6892
- }, children: t('ide.chat.olderModelsExpand', { count: deprecatedModels.length }, { defaultValue: 'Older models ⌄ ({{count}})' }) }))] })), onManageCustomModels && (_jsx("button", { type: "button", "data-mol-id": "chat-model-manage-custom", onClick: () => {
6879
+ }, children: t('ide.chat.olderModelsExpand', { count: deprecatedModels.length }, { defaultValue: 'Older models ⌄ ({{count}})' }) }))] })), onManageCustomModels && (_jsx("button", {
6880
+ /* mol-bespoke-button: manage-custom-models footer — anchored full-width footer row of the model list, keyboard-indexed with the rows */
6881
+ type: "button", "data-mol-id": "chat-model-manage-custom", onClick: () => {
6893
6882
  const manageMode = modelPicker.mode === 'plan' || modelPicker.mode === 'execute'
6894
6883
  ? modelPicker.mode
6895
6884
  : liveModelMode;
@@ -6966,7 +6955,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
6966
6955
  overflow: 'hidden',
6967
6956
  whiteSpace: 'nowrap',
6968
6957
  textOverflow: 'ellipsis',
6969
- }, children: effortPickerModeOptions.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) })] }), _jsx("button", { type: "button", "data-mol-id": "chat-effort-picker-close", onClick: () => setEffortPicker(null), style: {
6958
+ }, children: effortPickerModeOptions.map((o) => (_jsx("option", { value: o.value, children: o.label }, o.value))) })] }), _jsx("button", {
6959
+ /* mol-bespoke-button: icon-only picker close — header x, no label */
6960
+ type: "button", "data-mol-id": "chat-effort-picker-close", onClick: () => setEffortPicker(null), style: {
6970
6961
  background: 'none',
6971
6962
  border: 'none',
6972
6963
  cursor: 'pointer',
@@ -7041,7 +7032,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7041
7032
  alignItems: 'center',
7042
7033
  }, children: [_jsx("span", { children: t('ide.chat.notificationSounds', undefined, {
7043
7034
  defaultValue: 'Notification sounds',
7044
- }) }), _jsx("button", { type: "button", onClick: () => setSoundsPicker(null), style: {
7035
+ }) }), _jsx("button", {
7036
+ /* mol-bespoke-button: icon-only picker close — header x, no label */
7037
+ type: "button", onClick: () => setSoundsPicker(null), style: {
7045
7038
  background: 'none',
7046
7039
  border: 'none',
7047
7040
  cursor: 'pointer',
@@ -7075,7 +7068,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7075
7068
  defaultValue: SOUND_MODE_LABELS[allModes[0]],
7076
7069
  })
7077
7070
  : t('ide.chat.soundMode.mixed', undefined, { defaultValue: 'mixed' });
7078
- return (_jsxs("button", { type: "button", onClick: () => void cycleSoundMode('all'), onMouseEnter: (e) => {
7071
+ return (_jsxs("button", {
7072
+ /* mol-bespoke-button: sounds "All" row — full-width list item in the /sounds popup */
7073
+ type: "button", onClick: () => void cycleSoundMode('all'), onMouseEnter: (e) => {
7079
7074
  ;
7080
7075
  e.currentTarget.style.background = 'rgba(128,128,128,0.15)';
7081
7076
  }, onMouseLeave: (e) => {
@@ -7185,7 +7180,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7185
7180
  ? t('ide.chat.scripts.heading', undefined, { defaultValue: 'Scripts' })
7186
7181
  : panelOverlay === 'tests'
7187
7182
  ? t('ide.tests.heading', undefined, { defaultValue: 'Tests' })
7188
- : t('ide.chat.settings.heading', undefined, { defaultValue: 'Settings' }) }), _jsx("button", { type: "button", "data-mol-id": "panel-overlay-close", "aria-label": t('ide.chat.closeOverlay', undefined, { defaultValue: 'Close' }), onClick: () => setPanelOverlay(null), style: {
7183
+ : t('ide.chat.settings.heading', undefined, { defaultValue: 'Settings' }) }), _jsx("button", {
7184
+ /* mol-bespoke-button: icon-only overlay close — header x, no label */
7185
+ type: "button", "data-mol-id": "panel-overlay-close", "aria-label": t('ide.chat.closeOverlay', undefined, { defaultValue: 'Close' }), onClick: () => setPanelOverlay(null), style: {
7189
7186
  background: 'none',
7190
7187
  border: 'none',
7191
7188
  cursor: 'pointer',
@@ -7306,37 +7303,23 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7306
7303
  resize: 'vertical',
7307
7304
  color: 'inherit',
7308
7305
  fontFamily: 'inherit',
7309
- } }), _jsxs("div", { style: { display: 'flex', gap: 6, justifyContent: 'flex-end' }, children: [_jsx("button", { type: "button", onClick: () => setEditingQueuedId(null), className: cm.textSize('xs'), style: {
7310
- padding: '4px 12px',
7311
- border: `1px solid ${isLight ? '#d1d9e0' : 'rgba(255,255,255,0.1)'}`,
7312
- borderRadius: '4px',
7313
- background: 'transparent',
7314
- color: 'inherit',
7315
- cursor: 'pointer',
7316
- ...(isCoarse ? { minHeight: 32 } : {}),
7317
- }, children: t('common.cancel', undefined, { defaultValue: 'Cancel' }) }), _jsx("button", { type: "button", onClick: () => {
7306
+ } }), _jsxs("div", { style: { display: 'flex', gap: 6, justifyContent: 'flex-end' }, children: [_jsx("button", { type: "button", "data-mol-id": "chat-queued-edit-cancel", onClick: () => setEditingQueuedId(null), className: cm.cn(cm.button({ variant: 'solid', color: 'secondary', size: 'xs' }), cm.touchTargetCompact), children: t('common.cancel', undefined, { defaultValue: 'Cancel' }) }), _jsx("button", { type: "button", "data-mol-id": "chat-queued-edit-save", onClick: () => {
7318
7307
  const trimmed = editingQueuedText.trim();
7319
7308
  if (trimmed)
7320
7309
  editQueuedMessage(qm.id, trimmed);
7321
7310
  else
7322
7311
  deleteQueuedMessage(qm.id);
7323
7312
  setEditingQueuedId(null);
7324
- }, className: cm.textSize('xs'), style: {
7325
- padding: '4px 12px',
7326
- border: `1px solid ${isLight ? '#d1d9e0' : 'rgba(255,255,255,0.1)'}`,
7327
- borderRadius: '4px',
7328
- background: 'rgba(128,128,128,0.1)',
7329
- color: 'inherit',
7330
- cursor: 'pointer',
7331
- ...(isCoarse ? { minHeight: 32 } : {}),
7332
- }, children: t('common.save', undefined, { defaultValue: 'Save' }) })] })] }, qm.id)) : (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }, children: [_jsx("span", { title: qm.content, className: cm.textSize('sm'), style: {
7313
+ }, className: cm.cn(cm.button({ variant: 'solid', color: 'primary', size: 'xs' }), cm.touchTargetCompact), children: t('common.save', undefined, { defaultValue: 'Save' }) })] })] }, qm.id)) : (_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 6, minWidth: 0 }, children: [_jsx("span", { title: qm.content, className: cm.textSize('sm'), style: {
7333
7314
  flex: 1,
7334
7315
  minWidth: 0,
7335
7316
  overflow: 'hidden',
7336
7317
  textOverflow: 'ellipsis',
7337
7318
  whiteSpace: 'nowrap',
7338
7319
  opacity: 0.8,
7339
- }, children: qm.content }), _jsx("button", { type: "button", title: t('ide.chat.editQueued', undefined, { defaultValue: 'Edit' }), onClick: () => {
7320
+ }, children: qm.content }), _jsx("button", {
7321
+ /* mol-bespoke-button: icon-only edit affordance — 22px (32px coarse) pencil on a dense queued-message row */
7322
+ type: "button", title: t('ide.chat.editQueued', undefined, { defaultValue: 'Edit' }), onClick: () => {
7340
7323
  setEditingQueuedId(qm.id);
7341
7324
  setEditingQueuedText(qm.content);
7342
7325
  }, style: {
@@ -7360,7 +7343,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7360
7343
  }, onMouseLeave: (e) => {
7361
7344
  e.currentTarget.style.opacity = '0.5';
7362
7345
  e.currentTarget.style.background = 'none';
7363
- }, children: _jsx(Icon, { name: "pencil", size: 13, "aria-hidden": "true" }) }), _jsx("button", { type: "button", title: t('ide.chat.deleteQueued', undefined, { defaultValue: 'Delete' }), onClick: () => deleteQueuedMessage(qm.id), style: {
7346
+ }, children: _jsx(Icon, { name: "pencil", size: 13, "aria-hidden": "true" }) }), _jsx("button", {
7347
+ /* mol-bespoke-button: icon-only delete affordance — 22px (32px coarse) trash on a dense queued-message row, theme error token */
7348
+ type: "button", title: t('ide.chat.deleteQueued', undefined, { defaultValue: 'Delete' }), onClick: () => deleteQueuedMessage(qm.id), style: {
7364
7349
  display: 'inline-flex',
7365
7350
  alignItems: 'center',
7366
7351
  justifyContent: 'center',
@@ -7370,18 +7355,23 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7370
7355
  border: 'none',
7371
7356
  borderRadius: 4,
7372
7357
  background: 'none',
7373
- color: isLight ? 'rgb(185,28,28)' : 'rgb(248,113,113)',
7358
+ // Theme ERROR token, not a per-theme literal — the token
7359
+ // already resolves per theme.
7360
+ color: 'var(--mol-color-error, #dc2626)',
7374
7361
  opacity: 0.6,
7375
7362
  cursor: 'pointer',
7376
7363
  padding: 0,
7377
7364
  transition: 'opacity 100ms, background 100ms',
7378
7365
  }, onMouseEnter: (e) => {
7379
7366
  e.currentTarget.style.opacity = '1';
7380
- e.currentTarget.style.background = 'rgba(220,38,38,0.12)';
7367
+ e.currentTarget.style.background =
7368
+ 'color-mix(in srgb, var(--mol-color-error, #dc2626) 12%, transparent)';
7381
7369
  }, onMouseLeave: (e) => {
7382
7370
  e.currentTarget.style.opacity = '0.6';
7383
7371
  e.currentTarget.style.background = 'none';
7384
- }, children: _jsx(Icon, { name: "trash", size: 13, "aria-hidden": "true" }) }), !isLoading && (_jsx("button", { type: "button", title: t('ide.chat.sendQueued', undefined, { defaultValue: 'Send' }), onClick: () => {
7372
+ }, children: _jsx(Icon, { name: "trash", size: 13, "aria-hidden": "true" }) }), !isLoading && (_jsx("button", {
7373
+ /* mol-bespoke-button: icon-only send affordance — 22px (32px coarse) arrow on a dense queued-message row, theme success token */
7374
+ type: "button", title: t('ide.chat.sendQueued', undefined, { defaultValue: 'Send' }), onClick: () => {
7385
7375
  const content = qm.content;
7386
7376
  deleteQueuedMessage(qm.id);
7387
7377
  sendMessage(content);
@@ -7395,14 +7385,16 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7395
7385
  border: 'none',
7396
7386
  borderRadius: 4,
7397
7387
  background: 'none',
7398
- color: isLight ? 'rgb(21,128,61)' : 'rgb(74,222,128)',
7388
+ // Theme SUCCESS token, not a per-theme literal.
7389
+ color: 'var(--mol-color-success, #16a34a)',
7399
7390
  opacity: 0.7,
7400
7391
  cursor: 'pointer',
7401
7392
  padding: 0,
7402
7393
  transition: 'opacity 100ms, background 100ms',
7403
7394
  }, onMouseEnter: (e) => {
7404
7395
  e.currentTarget.style.opacity = '1';
7405
- e.currentTarget.style.background = 'rgba(34,197,94,0.14)';
7396
+ e.currentTarget.style.background =
7397
+ 'color-mix(in srgb, var(--mol-color-success, #16a34a) 14%, transparent)';
7406
7398
  }, onMouseLeave: (e) => {
7407
7399
  e.currentTarget.style.opacity = '0.7';
7408
7400
  e.currentTarget.style.background = 'none';
@@ -7456,39 +7448,27 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7456
7448
  const commitBusy = commitState?.status === 'committing' ||
7457
7449
  commitState?.status === 'committed' ||
7458
7450
  autoCommitHeld;
7459
- return (_jsx("button", { type: "button", onClick: (e) => {
7451
+ return (_jsx("button", { type: "button", "data-mol-id": "chat-commit-button", onClick: (e) => {
7460
7452
  e.stopPropagation();
7461
7453
  if (commitBusy)
7462
7454
  return;
7463
7455
  handleCommit();
7464
- }, disabled: commitBusy, onMouseEnter: (e) => {
7465
- if (!commitBusy) {
7466
- e.currentTarget.style.background = 'rgba(64,112,224,0.3)';
7467
- e.currentTarget.style.borderColor = 'rgba(64,112,224,0.65)';
7468
- e.currentTarget.style.color = '#6090f0';
7469
- }
7470
- }, onMouseLeave: (e) => {
7471
- e.currentTarget.style.background = 'rgba(64,112,224,0.2)';
7472
- e.currentTarget.style.borderColor = 'rgba(64,112,224,0.4)';
7473
- e.currentTarget.style.color = '#4070e0';
7474
- }, style: {
7475
- fontSize: 12,
7476
- padding: '4px 10px',
7477
- // Touch floor for this inline bar action (36px, matching
7478
- // the notice-card buttons).
7479
- ...(isCoarse ? { minHeight: 36 } : {}),
7480
- borderRadius: 6,
7481
- border: '1px solid rgba(64,112,224,0.4)',
7482
- background: 'rgba(64,112,224,0.2)',
7483
- color: '#4070e0',
7484
- cursor: commitBusy ? 'not-allowed' : 'pointer',
7485
- opacity: commitBusy ? 0.5 : 1,
7486
- transition: 'background 100ms, border-color 100ms, color 100ms',
7487
- }, children: commitState?.status === 'committing'
7456
+ }, disabled: commitBusy,
7457
+ // The SAME design-system button as the tests bar's action
7458
+ // one strip above (and as the green AutoCommitBadge that
7459
+ // replaces this one when auto-commit is on) — only the
7460
+ // semantic colour differs. The CVA owns hover/active/focus
7461
+ // and the disabled look, so there is nothing to hand-roll:
7462
+ // this used to be an inline 12px/6px-radius button with
7463
+ // hardcoded rgba(64,112,224,*) and hand-written hover, and
7464
+ // it visibly mismatched the 13px/3px tests-bar button.
7465
+ className: cm.cn(cm.button({ variant: 'solid', color: 'primary', size: 'xs' }), cm.touchTargetCompact), children: commitState?.status === 'committing'
7488
7466
  ? t('ide.chat.committing')
7489
7467
  : t('ide.chat.commit') }));
7490
7468
  })())] }), commitBarExpanded && (_jsx("div", { style: { marginTop: 4, paddingLeft: 16, maxHeight: 200, overflowY: 'auto' }, children: pendingFiles.map((f) => (_jsxs("button", { type: "button", onClick: () => onFileDiff?.(f.path), onMouseEnter: (e) => {
7491
- e.currentTarget.style.color = '#6090f0';
7469
+ // Theme PRIMARY token, not a literal blue — the row sits in
7470
+ // the same bar as the commit button, which is now primary.
7471
+ e.currentTarget.style.color = 'var(--mol-color-primary, #4070e0)';
7492
7472
  }, onMouseLeave: (e) => {
7493
7473
  e.currentTarget.style.color = '';
7494
7474
  }, style: {
@@ -7510,7 +7490,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7510
7490
  width: '100%',
7511
7491
  overflow: 'hidden',
7512
7492
  whiteSpace: 'nowrap',
7513
- }, className: cm.textMuted, children: [_jsx("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis' }, children: f.path }), (!!f.additions || !!f.deletions) && (_jsxs("span", { style: { marginLeft: 'auto', flexShrink: 0, fontSize: 10, opacity: 0.8 }, children: [!!f.additions && (_jsxs("span", { style: { color: '#3fb950' }, children: ["+", f.additions] })), !!f.additions && !!f.deletions && ' ', !!f.deletions && (_jsxs("span", { style: { color: '#f85149' }, children: ["-", f.deletions] }))] })), onFileRevert && (_jsx("span", { role: "button", tabIndex: 0, title: t('ide.chat.revertFile', undefined, {
7493
+ }, className: cm.textMuted, children: [_jsx("span", { style: { overflow: 'hidden', textOverflow: 'ellipsis' }, children: f.path }), (!!f.additions || !!f.deletions) && (_jsxs("span", { style: { marginLeft: 'auto', flexShrink: 0, fontSize: 10, opacity: 0.8 }, children: [!!f.additions && (_jsxs("span", { style: { color: '#3fb950' }, children: ["+", f.additions] })), !!f.additions && !!f.deletions && ' ', !!f.deletions && (_jsxs("span", { style: { color: '#f85149' }, children: ["-", f.deletions] }))] })), onFileRevert && (_jsx("span", {
7494
+ /* mol-bespoke-button: icon-only per-file revert affordance — 18px (32px coarse) hit box on a dense file row */
7495
+ role: "button", tabIndex: 0, title: t('ide.chat.revertFile', undefined, {
7514
7496
  defaultValue: 'Revert to last commit',
7515
7497
  }), onClick: (e) => {
7516
7498
  e.stopPropagation();
@@ -7605,7 +7587,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7605
7587
  alignItems: 'center',
7606
7588
  marginTop: '6px',
7607
7589
  gap: '4px',
7608
- }, children: [canEdit !== false && (_jsx("button", { type: "button", onClick: () => {
7590
+ }, children: [canEdit !== false && (_jsx("button", {
7591
+ /* mol-bespoke-button: icon-only composer toggle — shares the composer row's 24px / 40x32-coarse icon box model */
7592
+ type: "button", onClick: () => {
7609
7593
  const newMode = mode === 'plan' ? 'execute' : 'plan';
7610
7594
  setMode(newMode);
7611
7595
  http
@@ -7650,7 +7634,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7650
7634
  }, onMouseLeave: (e) => {
7651
7635
  if (mode !== 'plan')
7652
7636
  e.currentTarget.style.opacity = '0.4';
7653
- }, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z" }) }) })), fastModeAvailable && canEdit !== false && (_jsx("button", { type: "button", "data-mol-id": "chat-fast-mode-toggle", disabled: !canEdit, onClick: () => {
7637
+ }, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z" }) }) })), fastModeAvailable && canEdit !== false && (_jsx("button", {
7638
+ /* mol-bespoke-button: icon-only composer toggle — shares the composer row's 24px / 40x32-coarse icon box model */
7639
+ type: "button", "data-mol-id": "chat-fast-mode-toggle", disabled: !canEdit, onClick: () => {
7654
7640
  const next = !fastMode;
7655
7641
  setFastMode(next);
7656
7642
  http
@@ -7693,7 +7679,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7693
7679
  }, onMouseLeave: (e) => {
7694
7680
  if (!fastMode)
7695
7681
  e.currentTarget.style.opacity = '0.4';
7696
- }, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M9.504.43a.75.75 0 0 1 .584.859l-.828 4.211h4.49a.75.75 0 0 1 .573 1.234l-7.25 8.5a.75.75 0 0 1-1.32-.658l.828-4.211H2.09a.75.75 0 0 1-.573-1.234l7.25-8.5a.75.75 0 0 1 .737-.201Z" }) }) })), _jsx("button", { type: "button", "data-mol-id": "chat-mic-button", onClick: toggleVoice, title: t('ide.chat.voice', undefined, {
7682
+ }, children: _jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "currentColor", children: _jsx("path", { d: "M9.504.43a.75.75 0 0 1 .584.859l-.828 4.211h4.49a.75.75 0 0 1 .573 1.234l-7.25 8.5a.75.75 0 0 1-1.32-.658l.828-4.211H2.09a.75.75 0 0 1-.573-1.234l7.25-8.5a.75.75 0 0 1 .737-.201Z" }) }) })), _jsx("button", {
7683
+ /* mol-bespoke-button: icon-only composer toggle — shares the composer row's 24px / 40x32-coarse icon box model */
7684
+ type: "button", "data-mol-id": "chat-mic-button", onClick: toggleVoice, title: t('ide.chat.voice', undefined, {
7697
7685
  defaultValue: isListening ? 'Stop dictation' : 'Dictate',
7698
7686
  }), style: {
7699
7687
  display: 'inline-flex',
@@ -7715,7 +7703,9 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7715
7703
  }, onMouseLeave: (e) => {
7716
7704
  if (!isListening)
7717
7705
  e.currentTarget.style.opacity = '0.4';
7718
- }, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", width: "16", height: "16", style: { display: 'block' }, children: [_jsx("rect", { x: "6", y: "1", width: "4", height: "8", rx: "2", fill: isListening ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "1.25" }), _jsx("path", { d: "M4 7v1a4 4 0 008 0V7", fill: "none", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" }), _jsx("line", { x1: "8", y1: "12", x2: "8", y2: "15", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" }), _jsx("line", { x1: "6", y1: "15", x2: "10", y2: "15", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" })] }) }), canEdit !== false && (_jsx("button", { type: "button", onClick: () => fileInputRef.current?.click(), title: t('ide.chat.attachFile', undefined, { defaultValue: 'Attach file' }), style: {
7706
+ }, children: _jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 16 16", width: "16", height: "16", style: { display: 'block' }, children: [_jsx("rect", { x: "6", y: "1", width: "4", height: "8", rx: "2", fill: isListening ? 'currentColor' : 'none', stroke: "currentColor", strokeWidth: "1.25" }), _jsx("path", { d: "M4 7v1a4 4 0 008 0V7", fill: "none", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" }), _jsx("line", { x1: "8", y1: "12", x2: "8", y2: "15", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" }), _jsx("line", { x1: "6", y1: "15", x2: "10", y2: "15", stroke: "currentColor", strokeWidth: "1.25", strokeLinecap: "round" })] }) }), canEdit !== false && (_jsx("button", {
7707
+ /* mol-bespoke-button: icon-only composer affordance — shares the composer row's 24px / 40x32-coarse icon box model */
7708
+ type: "button", onClick: () => fileInputRef.current?.click(), title: t('ide.chat.attachFile', undefined, { defaultValue: 'Attach file' }), style: {
7719
7709
  display: 'inline-flex',
7720
7710
  alignItems: 'center',
7721
7711
  justifyContent: 'center',
@@ -7892,46 +7882,27 @@ function ChatInner({ projectId, endpoint, initialMessage, onInitialMessageSent,
7892
7882
  display: 'flex',
7893
7883
  gap: '4px',
7894
7884
  alignItems: 'center',
7895
- }, children: [canEdit !== false && (isLoading || isRemoteStreaming) && (_jsx("button", { type: "button", onClick: handleAbort, title: t('ide.chat.stop', undefined, { defaultValue: 'Stop' }), onMouseEnter: (e) => {
7896
- e.currentTarget.style.background = 'rgba(248,81,73,0.3)';
7897
- e.currentTarget.style.borderColor = 'rgba(248,81,73,0.65)';
7898
- }, onMouseLeave: (e) => {
7899
- e.currentTarget.style.background = 'rgba(248,81,73,0.2)';
7900
- e.currentTarget.style.borderColor = 'rgba(248,81,73,0.4)';
7901
- }, style: {
7902
- padding: '5px 10px',
7903
- borderRadius: 6,
7904
- border: '1px solid rgba(248,81,73,0.4)',
7905
- background: 'rgba(248,81,73,0.2)',
7906
- color: '#f85149',
7907
- cursor: 'pointer',
7908
- transition: 'background 100ms, border-color 100ms',
7909
- display: 'flex',
7910
- alignItems: 'center',
7911
- justifyContent: 'center',
7912
- // Touch hit-area floor for the composer's action buttons.
7885
+ }, children: [canEdit !== false && (isLoading || isRemoteStreaming) && (_jsx("button", { type: "button", "data-mol-id": "chat-stop-button", onClick: handleAbort, title: t('ide.chat.stop', undefined, { defaultValue: 'Stop' }),
7886
+ // The composer's two action buttons (Stop, Send) are design-system
7887
+ // buttons in the ERROR and PRIMARY semantics — same radius, height
7888
+ // and states as every other action button in the panel. They were a
7889
+ // matched pair of hand-rolled 6px-radius frames with hardcoded
7890
+ // rgba(248,81,73,*) / rgba(96,160,240,*) and hand-written hover.
7891
+ className: cm.button({ variant: 'solid', color: 'error', size: 'xs' }), style: {
7892
+ // The composer's documented touch box: wide for hit spacing but
7893
+ // deliberately flat (40×32) so the row doesn't balloon. This is the
7894
+ // one thing the ClassMap can't express here, and the reason this is
7895
+ // NOT cm.touchTargetCompact — a 36px floor would out-grow the
7896
+ // neighbouring icon buttons.
7913
7897
  ...(isCoarse ? { minWidth: 40, minHeight: 32 } : {}),
7914
- }, children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", style: { display: 'block' }, children: _jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "1.5", fill: "currentColor" }) }) })), _jsx("button", { type: "button", onClick: () => void handleSubmit(), title: t('ide.chat.send', undefined, { defaultValue: 'Send' }), disabled: !hasInput && attachedFiles.length === 0, onMouseEnter: (e) => {
7915
- if (!e.currentTarget.disabled) {
7916
- e.currentTarget.style.background = 'rgba(96,160,240,0.3)';
7917
- e.currentTarget.style.borderColor = 'rgba(96,160,240,0.7)';
7918
- }
7919
- }, onMouseLeave: (e) => {
7920
- e.currentTarget.style.background = 'rgba(96,160,240,0.2)';
7921
- e.currentTarget.style.borderColor = 'rgba(96,160,240,0.5)';
7922
- }, style: {
7923
- padding: '5px 10px',
7924
- borderRadius: 6,
7925
- border: '1px solid rgba(96,160,240,0.5)',
7926
- background: 'rgba(96,160,240,0.2)',
7927
- color: '#6aa3f0',
7928
- cursor: !hasInput && attachedFiles.length === 0 ? 'not-allowed' : 'pointer',
7929
- opacity: !hasInput && attachedFiles.length === 0 ? 0.5 : 1,
7930
- transition: 'background 100ms, border-color 100ms, color 100ms',
7931
- display: 'flex',
7932
- alignItems: 'center',
7933
- justifyContent: 'center',
7934
- // Touch hit-area floor for the composer's action buttons.
7898
+ }, children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", style: { display: 'block' }, children: _jsx("rect", { x: "2", y: "2", width: "8", height: "8", rx: "1.5", fill: "currentColor" }) }) })), _jsx("button", { type: "button", "data-mol-id": "chat-send-button", onClick: () => void handleSubmit(), title: t('ide.chat.send', undefined, { defaultValue: 'Send' }), disabled: !hasInput && attachedFiles.length === 0,
7899
+ // Stop's twin in the PRIMARY semantic. The real `disabled`
7900
+ // attribute above carries the muted/inert look via the CVA
7901
+ // (`disabled:opacity-50 disabled:pointer-events-none`), so the
7902
+ // hand-rolled cursor/opacity pair is gone with the rest.
7903
+ className: cm.button({ variant: 'solid', color: 'primary', size: 'xs' }), style: {
7904
+ // See the Stop button: the composer's documented flat 40×32 touch
7905
+ // box, which the ClassMap can't express.
7935
7906
  ...(isCoarse ? { minWidth: 40, minHeight: 32 } : {}),
7936
7907
  }, children: _jsx("svg", { width: "12", height: "12", viewBox: "0 0 12 12", style: { display: 'block' }, children: _jsx("path", { d: "M 2.5,6.5 L 6,3 L 9.5,6.5 M 6,3.5 L 6,10", fill: "none", stroke: "currentColor", strokeWidth: "1.75", strokeLinecap: "round", strokeLinejoin: "round" }) }) })] })] })] })] }), reportModal && (_jsx(ReportModal, { projectId: projectId, conversationId: conversationId, initialTitle: reportModal.title, productName: productName, appVersion: version || APP_VERSION, onClose: () => setReportModal(null), onSubmitted: (result) => {
7937
7908
  setReportModal(null);
@@ -8091,7 +8062,9 @@ export function ChatPanel({ projectId, endpoint, initialMessage, onInitialMessag
8091
8062
  height: isCoarse ? undefined : '33px',
8092
8063
  minHeight: '33px',
8093
8064
  zIndex: 10,
8094
- }, children: [_jsxs("button", { type: "button", onClick: handleToggleDropdown, className: cm.cn(cm.textSize('xs'), cm.textMuted), onMouseEnter: (e) => {
8065
+ }, children: [_jsxs("button", {
8066
+ /* mol-bespoke-button: conversation picker — the header title row, a full-width disclosure for the history dropdown */
8067
+ type: "button", onClick: handleToggleDropdown, className: cm.cn(cm.textSize('xs'), cm.textMuted), onMouseEnter: (e) => {
8095
8068
  const s = e.currentTarget.querySelector('span');
8096
8069
  if (s)
8097
8070
  s.style.opacity = '1';