@mcp-b/react-components 0.45.0 → 0.46.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 (125) hide show
  1. package/dist/{AgentChat-Bibfj7u1.d.ts → AgentChat-BLmQghkt.d.ts} +2 -2
  2. package/dist/{CodeBlock-8K1p1BDU.js → CodeBlock-BpooTofO.js} +1 -1
  3. package/dist/{FileTree-QTP57Qz4.js → FileTree-CAXWXH63.js} +1 -1
  4. package/dist/{McpConnectorForm-MRm1r59e.d.ts → McpConnectorForm-BETdVBRk.d.ts} +1 -1
  5. package/dist/{McpPluginCatalog-mbGw8FTu.d.ts → McpPluginCatalog-C6ip9IvL.d.ts} +2 -2
  6. package/dist/{PromptInput-BRX7FhjH.d.ts → PromptInput-DtJHyp0S.d.ts} +27 -22
  7. package/dist/{SetupChecklist-CZeToAbu.js → SetupChecklist-DyPZWzK2.js} +2 -2
  8. package/dist/{ThinkChat-CWMcl79Q.js → ThinkChat-qztQ6Clo.js} +4 -1
  9. package/dist/{ThinkChatActivity-CgvmTXXB.d.ts → ThinkChatActivity-B3lGVS-6.d.ts} +1 -1
  10. package/dist/{WorkspaceFileView-DJ8Oxz57.js → WorkspaceFileView-BvDbKM2c.js} +2 -2
  11. package/dist/components/agents-sdk/AgentActivity.js +1 -1
  12. package/dist/components/agents-sdk/AgentChat.d.ts +1 -1
  13. package/dist/components/agents-sdk/AgentChat.js +29 -30
  14. package/dist/components/agents-sdk/BrowserLiveScreen.js +1 -1
  15. package/dist/components/agents-sdk/BrowserLiveView.js +1 -1
  16. package/dist/components/agents-sdk/BrowserReplay.js +1 -1
  17. package/dist/components/agents-sdk/BrowserRunPanel.js +1 -1
  18. package/dist/components/agents-sdk/ManagerOffice.d.ts +2 -1
  19. package/dist/components/agents-sdk/ManagerOffice.js +28 -10
  20. package/dist/components/agents-sdk/McpConnectionRequest.d.ts +1 -1
  21. package/dist/components/agents-sdk/McpConnectionRequest.js +10 -4
  22. package/dist/components/agents-sdk/McpConnectorForm.d.ts +1 -1
  23. package/dist/components/agents-sdk/McpPluginCatalog.d.ts +1 -1
  24. package/dist/components/agents-sdk/McpPluginCatalog.js +9 -5
  25. package/dist/components/agents-sdk/McpServerPicker.d.ts +2 -2
  26. package/dist/components/agents-sdk/McpServerPicker.js +2 -2
  27. package/dist/components/agents-sdk/ModelSelector.js +2 -2
  28. package/dist/components/agents-sdk/PromptInputCommands.d.ts +5 -2
  29. package/dist/components/agents-sdk/PromptInputCommands.js +81 -3
  30. package/dist/components/agents-sdk/SubagentRunIndicator.js +1 -1
  31. package/dist/components/agents-sdk/ThinkChat.d.ts +3 -3
  32. package/dist/components/agents-sdk/ThinkChat.js +1 -1
  33. package/dist/components/agents-sdk/ThinkChatActivity.d.ts +1 -1
  34. package/dist/components/agents-sdk/ThinkChatToolPanels.js +1 -1
  35. package/dist/components/agents-sdk/ThinkExecutionDetail.js +1 -1
  36. package/dist/components/agents-sdk/ThinkExecutionStatus.js +1 -1
  37. package/dist/components/agents-sdk/ThinkExecutionWorkbench.js +1 -1
  38. package/dist/components/agents-sdk/ThinkFullApp.d.ts +1 -1
  39. package/dist/components/agents-sdk/ThinkFullApp.js +2 -2
  40. package/dist/components/agents-sdk/ThinkRoutineBrowser.js +1 -1
  41. package/dist/components/agents-sdk/ThinkRoutineForm.js +1 -1
  42. package/dist/components/agents-sdk/ThinkRoutineLibrary.js +1 -1
  43. package/dist/components/agents-sdk/ThinkSidepanel.js +22 -9
  44. package/dist/components/agents-sdk/ThinkThreadPicker.js +1 -1
  45. package/dist/components/agents-sdk/WorkspaceBrowser.js +1 -1
  46. package/dist/components/agents-sdk/WorkspaceExplorer.js +1 -1
  47. package/dist/components/agents-sdk/WorkspaceFileView.js +1 -1
  48. package/dist/components/agents-sdk/WorkspaceHeader.js +1 -1
  49. package/dist/components/agents-sdk/WorkspaceMountManager.js +1 -1
  50. package/dist/components/ai-sdk/Activity.js +1 -1
  51. package/dist/components/ai-sdk/AgentChatStartScreen.js +1 -1
  52. package/dist/components/ai-sdk/Approval.js +1 -1
  53. package/dist/components/ai-sdk/Artifact.js +1 -1
  54. package/dist/components/ai-sdk/ChainOfThought.d.ts +1 -1
  55. package/dist/components/ai-sdk/ChainOfThought.js +1 -1
  56. package/dist/components/ai-sdk/Checkpoint.js +1 -1
  57. package/dist/components/ai-sdk/CodeBlock.js +1 -1
  58. package/dist/components/ai-sdk/ComposerLink.d.ts +27 -0
  59. package/dist/components/ai-sdk/ComposerLink.js +111 -0
  60. package/dist/components/ai-sdk/ConnectedAppCards.js +1 -1
  61. package/dist/components/ai-sdk/Conversation.js +1 -1
  62. package/dist/components/ai-sdk/Goal.js +1 -1
  63. package/dist/components/ai-sdk/MediaPreviewCard.js +1 -1
  64. package/dist/components/ai-sdk/Message.js +18 -2
  65. package/dist/components/ai-sdk/MessageScroller.js +1 -1
  66. package/dist/components/ai-sdk/MessageScrollerVirtual.js +1 -1
  67. package/dist/components/ai-sdk/Plan.js +1 -1
  68. package/dist/components/ai-sdk/PromptInput.d.ts +2 -2
  69. package/dist/components/ai-sdk/PromptInput.js +65 -59
  70. package/dist/components/ai-sdk/PromptInputComposerEditor.d.ts +31 -0
  71. package/dist/components/ai-sdk/PromptInputComposerEditor.js +198 -0
  72. package/dist/components/ai-sdk/Queue.js +1 -1
  73. package/dist/components/ai-sdk/Reasoning.js +1 -1
  74. package/dist/components/ai-sdk/Sources.js +1 -1
  75. package/dist/components/ai-sdk/Task.js +1 -1
  76. package/dist/components/extension/ChatGptSignInScreen.js +2 -2
  77. package/dist/components/extension/CodexModelSelector.js +1 -1
  78. package/dist/components/extension/ConversationTabPicker.js +1 -1
  79. package/dist/components/foundations/AppIcon.js +1 -1
  80. package/dist/components/foundations/Checkbox.js +1 -1
  81. package/dist/components/foundations/ContextMenu.js +1 -1
  82. package/dist/components/foundations/Menubar.js +1 -1
  83. package/dist/components/foundations/SearchField.js +1 -1
  84. package/dist/components/foundations/Select.js +1 -1
  85. package/dist/components/foundations/Stepper.js +1 -1
  86. package/dist/components/foundations/Toast.js +1 -1
  87. package/dist/components/foundations/icons.d.ts +1 -1
  88. package/dist/components/foundations/icons.js +1 -1
  89. package/dist/components/general-purpose/Commit.js +2 -2
  90. package/dist/components/general-purpose/EnvironmentVariables.js +2 -2
  91. package/dist/components/general-purpose/FileTree.js +1 -1
  92. package/dist/components/general-purpose/PricingPlanCard.js +1 -1
  93. package/dist/components/general-purpose/ResponsiveSidebarShell.js +1 -1
  94. package/dist/components/general-purpose/SetupChecklist.js +1 -1
  95. package/dist/components/general-purpose/Terminal.js +2 -2
  96. package/dist/components/general-purpose/TestResults.js +1 -1
  97. package/dist/components/general-purpose/ThemeModeControl.js +1 -1
  98. package/dist/components/general-purpose/WebPreview.js +1 -1
  99. package/dist/components/nanites/AgentConnection.js +2 -2
  100. package/dist/components/nanites/AgentToolDetail.js +2 -2
  101. package/dist/{copy-button-BpA7wQva.js → copy-button-D7ySsRRo.js} +1 -1
  102. package/dist/{icons-DbrksZyY.js → icons-BNEY4gO5.js} +44 -4
  103. package/dist/{icons-6ZnyZJiR.d.ts → icons-D0Pd2P9v.d.ts} +9 -4
  104. package/dist/{mcp-server-SD_S-IpB.js → mcp-server-7NR24ASj.js} +31 -4
  105. package/dist/{mcp-server-catalog-CCj2ItkV.d.ts → mcp-server-catalog-Cbu483Zb.d.ts} +9 -9
  106. package/dist/{provider-logos-zjZycgV6.js → provider-logos-DWYY8wNz.js} +31 -6
  107. package/dist/styles/action-guide.css +4 -0
  108. package/dist/styles/agent-attention.css +5 -1
  109. package/dist/styles/agent-chat.css +21 -18
  110. package/dist/styles/app-icon.css +21 -0
  111. package/dist/styles/brand-marks.css +22 -0
  112. package/dist/styles/composer-link.css +99 -0
  113. package/dist/styles/connected-app-card.css +9 -0
  114. package/dist/styles/github-motion-mark.css +8 -1
  115. package/dist/styles/index.css +2 -0
  116. package/dist/styles/manager-office.css +10 -3
  117. package/dist/styles/mcp-plugin-catalog.css +4 -0
  118. package/dist/styles/mcp-server-picker.css +2 -0
  119. package/dist/styles/prompt-input.css +14 -53
  120. package/dist/styles/think-sidepanel.css +9 -0
  121. package/dist/utils/composer-link.d.ts +59 -0
  122. package/dist/utils/composer-link.js +203 -0
  123. package/dist/utils/mcp-server-catalog.d.ts +1 -1
  124. package/dist/utils/mcp-server-catalog.js +9 -9
  125. package/package.json +2 -2
@@ -0,0 +1,99 @@
1
+ .composer-link {
2
+ --composer-link-fill: var(
3
+ --composer-link-color,
4
+ light-dark(var(--sigvelo-color-primary-600), var(--sigvelo-color-primary-400))
5
+ );
6
+
7
+ display: inline;
8
+ max-inline-size: 100%;
9
+ /* Official mark hexes (Linear 5E6AD2, Gmail EA4335) miss 4.5:1 on the user
10
+ bubble. Mix toward --sigvelo-color-text so light darkens and dark lightens
11
+ while the hue stays the brand. */
12
+ color: color-mix(in oklab, var(--composer-link-fill) 80%, var(--sigvelo-color-text));
13
+ text-decoration: none;
14
+ font: inherit;
15
+ font-weight: var(--sigvelo-font-weight-semibold);
16
+ line-height: inherit;
17
+ white-space: nowrap;
18
+ cursor: default;
19
+ }
20
+
21
+ .composer-link:hover {
22
+ color: color-mix(in oklab, var(--composer-link-fill) 70%, var(--sigvelo-color-text));
23
+ text-decoration: none;
24
+ }
25
+
26
+ .composer-link:focus-visible {
27
+ outline: var(--sigvelo-focus-ring);
28
+ outline-offset: 2px;
29
+ border-radius: var(--sigvelo-radius-sm);
30
+ }
31
+
32
+ .composer-link__icon {
33
+ display: inline-block;
34
+ /* Larger than cap-height, under the 1.5 line-height so Linear tiles and
35
+ Lucide glyphs share one box. */
36
+ inline-size: 1.2em;
37
+ block-size: 1.2em;
38
+ margin-inline-end: var(--sigvelo-spacing-1);
39
+ vertical-align: -0.25em;
40
+ overflow: visible;
41
+ color: inherit;
42
+ }
43
+
44
+ .composer-link__icon :is(svg, img, .app-icon),
45
+ .composer-link__icon.app-icon {
46
+ display: block;
47
+ inline-size: 100%;
48
+ block-size: 100%;
49
+ }
50
+
51
+ .composer-link__icon :is(img, .app-icon__image) {
52
+ object-fit: cover;
53
+ }
54
+
55
+ /* Nested AppIcon tiles add radius, shadow, and inset — flatten so the mark
56
+ fills the icon box. */
57
+ .composer-link:not(.prompt-input__tab-item) .app-icon {
58
+ --sigvelo-recipe-app-icon-size: 100%;
59
+ padding: 0;
60
+ border-radius: 0;
61
+ overflow: visible;
62
+ filter: none;
63
+ }
64
+
65
+ .composer-link__label {
66
+ min-inline-size: 0;
67
+ font-weight: inherit;
68
+ }
69
+
70
+ .prompt-input__textarea .composer-link {
71
+ pointer-events: none;
72
+ }
73
+
74
+ .prompt-input__tab-item.composer-link,
75
+ .prompt-input__tab-item.composer-link:hover {
76
+ display: flex;
77
+ color: inherit;
78
+ text-decoration: none;
79
+ font-weight: inherit;
80
+ margin-inline: 0;
81
+ }
82
+
83
+ .prompt-input__tab-item .composer-link__icon {
84
+ display: inline-flex;
85
+ margin-inline-end: 0;
86
+ vertical-align: unset;
87
+ }
88
+
89
+ @media (forced-colors: active) {
90
+ .composer-link {
91
+ color: LinkText;
92
+ forced-color-adjust: none;
93
+ }
94
+
95
+ .composer-link:hover,
96
+ .composer-link:focus-visible {
97
+ color: LinkText;
98
+ }
99
+ }
@@ -15,6 +15,15 @@
15
15
  align-items: center;
16
16
  }
17
17
 
18
+ .connected-app-card__icon > :is(svg, img) {
19
+ inline-size: var(--sigvelo-control-icon-size-md);
20
+ block-size: var(--sigvelo-control-icon-size-md);
21
+ }
22
+
23
+ .connected-app-card__icon :is(img, .app-icon__image) {
24
+ color: unset;
25
+ }
26
+
18
27
  .connected-app-card__status {
19
28
  display: inline-flex;
20
29
  align-items: center;
@@ -5,12 +5,13 @@
5
5
  place-items: center;
6
6
  inline-size: 1.625em;
7
7
  block-size: 1.625em;
8
- color: currentColor;
8
+ color: inherit;
9
9
  line-height: 0;
10
10
  }
11
11
 
12
12
  .github-motion-mark svg {
13
13
  grid-area: 1 / 1;
14
+ fill: currentColor;
14
15
  transform-origin: 50% 50%;
15
16
  animation: github-motion-mark-breathe 2.6s ease-in-out infinite;
16
17
  }
@@ -89,3 +90,9 @@
89
90
  animation: none;
90
91
  }
91
92
  }
93
+
94
+ @media (forced-colors: active) {
95
+ .github-motion-mark {
96
+ color: CanvasText;
97
+ }
98
+ }
@@ -40,6 +40,7 @@
40
40
  @import "./fieldset.css" layer(components);
41
41
  @import "./form.css" layer(components);
42
42
  @import "./github-motion-mark.css" layer(components);
43
+ @import "./brand-marks.css" layer(components);
43
44
  @import "./input.css" layer(components);
44
45
  @import "./kbd.css" layer(components);
45
46
  @import "./label.css" layer(components);
@@ -107,6 +108,7 @@
107
108
  @import "./chatgpt-sign-in-screen.css" layer(components);
108
109
  @import "./plan.css" layer(components);
109
110
  @import "./prompt-input.css" layer(components);
111
+ @import "./composer-link.css" layer(components);
110
112
  @import "./queue.css" layer(components);
111
113
  @import "./reasoning.css" layer(components);
112
114
  @import "./resizable-side-panel.css" layer(components);
@@ -910,6 +910,9 @@
910
910
  .manager-office__connection-icons .app-icon {
911
911
  filter: none;
912
912
  }
913
+ .manager-office__connection-icons .app-icon :is(img, .app-icon__image) {
914
+ color: unset;
915
+ }
913
916
  .manager-office__dashboard-card-actions {
914
917
  display: flex;
915
918
  align-items: center;
@@ -1548,9 +1551,13 @@
1548
1551
  block-size: 100%;
1549
1552
  }
1550
1553
 
1551
- .manager-office__channel-mark > svg {
1552
- inline-size: 65%;
1553
- block-size: 65%;
1554
+ .manager-office__channel-mark > :is(svg, img, .app-icon__image) {
1555
+ inline-size: var(--sigvelo-control-icon-size-md);
1556
+ block-size: var(--sigvelo-control-icon-size-md);
1557
+ }
1558
+
1559
+ .manager-office__channel-mark :is(img, .app-icon__image) {
1560
+ color: unset;
1554
1561
  }
1555
1562
 
1556
1563
  .manager-office__channel-direction {
@@ -225,6 +225,10 @@
225
225
  gap: var(--sigvelo-spacing-3-5);
226
226
  }
227
227
 
228
+ .mcp-plugin-details__identity :is(img, .app-icon__image) {
229
+ color: unset;
230
+ }
231
+
228
232
  .mcp-plugin-details__identity > .separator {
229
233
  block-size: var(--sigvelo-spacing-8);
230
234
  background-color: color-mix(in oklab, currentcolor, transparent 30%);
@@ -55,6 +55,8 @@
55
55
  justify-content: center;
56
56
  inline-size: var(--sigvelo-control-icon-size-lg);
57
57
  block-size: var(--sigvelo-control-icon-size-lg);
58
+ /* Lucide and monochrome protocol marks tint from this. Hardcoded brand
59
+ fills ignore it; Discord sets its own color on the mark. */
58
60
  color: var(--sigvelo-color-text-muted);
59
61
  }
60
62
 
@@ -212,14 +212,22 @@
212
212
  font-family: inherit;
213
213
  font-size: var(--sigvelo-density-compact-control-font-size);
214
214
  line-height: var(--sigvelo-leading-normal);
215
+ white-space: pre-wrap;
216
+ overflow-wrap: anywhere;
215
217
  resize: none;
216
218
  overflow-block: hidden;
217
219
  }
218
220
 
219
- .prompt-input__textarea::placeholder {
221
+ .prompt-input__textarea::placeholder,
222
+ .prompt-input__textarea[data-empty]::before {
220
223
  color: var(--sigvelo-control-placeholder-color);
221
224
  }
222
225
 
226
+ .prompt-input__textarea[data-empty]::before {
227
+ content: attr(data-placeholder);
228
+ pointer-events: none;
229
+ }
230
+
223
231
  .prompt-input__textarea:focus,
224
232
  .prompt-input__textarea:focus-visible {
225
233
  border: none;
@@ -553,11 +561,15 @@
553
561
  flex: 0 0 auto;
554
562
  }
555
563
 
556
- .prompt-input__command-icon > svg {
564
+ .prompt-input__command-icon > :is(svg, img, .app-icon) {
557
565
  inline-size: var(--sigvelo-density-compact-control-icon-size);
558
566
  block-size: var(--sigvelo-density-compact-control-icon-size);
559
567
  }
560
568
 
569
+ .prompt-input__command-icon :is(img, .app-icon__image) {
570
+ color: unset;
571
+ }
572
+
561
573
  .prompt-input__command-copy {
562
574
  display: grid;
563
575
  grid-template-columns: auto var(--sigvelo-layout-track-fill) auto;
@@ -584,51 +596,6 @@
584
596
  overflow-wrap: anywhere;
585
597
  }
586
598
 
587
- .prompt-input__references {
588
- display: flex;
589
- flex-wrap: wrap;
590
- gap: var(--sigvelo-spacing-1);
591
- }
592
-
593
- .prompt-input__reference {
594
- position: relative;
595
- gap: var(--sigvelo-spacing-1);
596
- padding-inline: var(--sigvelo-spacing-1);
597
- color: var(--sigvelo-color-primary-text);
598
- font-weight: inherit;
599
- font-size: var(--sigvelo-density-compact-control-font-size);
600
- }
601
-
602
- .prompt-input__reference-icon,
603
- .prompt-input__reference-remove {
604
- display: inline-flex;
605
- flex: 0 0 auto;
606
- }
607
-
608
- .prompt-input__reference-label {
609
- max-inline-size: 18rem;
610
- }
611
-
612
- .prompt-input__reference-remove {
613
- position: absolute;
614
- inset-inline-end: calc(-1 * var(--sigvelo-spacing-3));
615
- color: var(--sigvelo-color-text-muted);
616
- opacity: 0;
617
- pointer-events: none;
618
- }
619
-
620
- .prompt-input__reference:hover .prompt-input__reference-remove,
621
- .prompt-input__reference:focus-visible .prompt-input__reference-remove {
622
- opacity: 1;
623
- }
624
-
625
- /* Local wrap. Not --sigvelo-layout-break-compact. */
626
- @container prompt-input (inline-size < 28rem) {
627
- .prompt-input__reference-label {
628
- max-inline-size: 12rem;
629
- }
630
- }
631
-
632
599
  .prompt-input__command-description,
633
600
  .prompt-input__context-description {
634
601
  color: var(--sigvelo-color-text-muted);
@@ -674,7 +641,6 @@
674
641
  .prompt-input__button,
675
642
  .prompt-input__attachment-remove,
676
643
  .prompt-input__recording-button,
677
- .prompt-input__reference,
678
644
  .prompt-input__submit {
679
645
  --sigvelo-recipe-button-height: var(--sigvelo-control-height-xl);
680
646
  }
@@ -690,11 +656,6 @@
690
656
  min-block-size: var(--sigvelo-control-height-xl);
691
657
  }
692
658
 
693
- .prompt-input__reference-remove {
694
- position: static;
695
- opacity: 1;
696
- }
697
-
698
659
  .prompt-input__attachment[data-image] .prompt-input__attachment-remove {
699
660
  position: static;
700
661
  }
@@ -60,6 +60,15 @@
60
60
  color: var(--sigvelo-color-text-muted);
61
61
  }
62
62
 
63
+ .think-sidepanel .app-icon-stack .app-icon :is(img, .app-icon__image) {
64
+ color: unset;
65
+ }
66
+
67
+ .think-sidepanel .button .app-icon-stack .app-icon :is(svg, img) {
68
+ inline-size: 100%;
69
+ block-size: 100%;
70
+ }
71
+
63
72
  @media (forced-colors: active) {
64
73
  .think-sidepanel,
65
74
  .think-sidepanel__gate {
@@ -0,0 +1,59 @@
1
+ //#region src/utils/composer-link.d.ts
2
+ declare const COMPOSER_LINK_ORIGIN = "https://composer.invalid";
3
+ declare const COMPOSER_LINK_KINDS: readonly ["command", "mcp", "skill", "tab", "file"];
4
+ type ComposerLinkKind = (typeof COMPOSER_LINK_KINDS)[number];
5
+ declare const COMPOSER_CHROME_ICONS: readonly ["box"];
6
+ type ComposerChromeIcon = (typeof COMPOSER_CHROME_ICONS)[number];
7
+ interface ComposerLinkParts {
8
+ kind: ComposerLinkKind;
9
+ value: string;
10
+ label?: string;
11
+ iconSrc?: string;
12
+ chromeIcon?: ComposerChromeIcon;
13
+ }
14
+ interface ParsedComposerLink extends ComposerLinkParts {
15
+ href: string;
16
+ label: string;
17
+ }
18
+ type ComposerDraftSegment = {
19
+ type: "text";
20
+ value: string;
21
+ } | {
22
+ type: "link";
23
+ href: string;
24
+ label: string;
25
+ parts: ParsedComposerLink;
26
+ };
27
+ declare function isComposerLinkKind(value: string): value is ComposerLinkKind;
28
+ declare function isComposerChromeIcon(value: string): value is ComposerChromeIcon;
29
+ declare function composerLinkHref(parts: ComposerLinkParts): string;
30
+ declare function parseComposerHref(href: string | undefined): ParsedComposerLink | undefined;
31
+ declare function escapeComposerLinkLabel(label: string): string;
32
+ /** Brand hex from a Simple Icons URL, skipped when it would vanish as text. */
33
+ declare function brandHexFromIconSrc(src: string | undefined): string | undefined;
34
+ /** Most chromatic opaque pixel, skipped when the mark is charcoal, white, or gray. */
35
+ declare function chromaticHexFromPixels(data: Uint8ClampedArray): string | undefined;
36
+ declare function sampleImageAccent(image: HTMLImageElement): string | undefined;
37
+ declare function serializeComposerLink(parts: ComposerLinkParts & {
38
+ label: string;
39
+ }): string;
40
+ declare function splitComposerDraft(text: string): ComposerDraftSegment[];
41
+ declare function parseComposerLinks(text: string): ParsedComposerLink[];
42
+ declare function composerTriggerMatch(text: string): {
43
+ trigger: "/" | "@";
44
+ query: string;
45
+ triggerIndex: number;
46
+ } | undefined;
47
+ declare function inferComposerLinkKind(command: {
48
+ id?: string;
49
+ }, trigger: "/" | "@"): ComposerLinkKind;
50
+ declare function replaceComposerTrigger(draft: string, command: {
51
+ id?: string;
52
+ value: string;
53
+ label: string;
54
+ href?: string;
55
+ iconSrc?: string;
56
+ }, trigger: "/" | "@"): string;
57
+ declare function composerDraftToPrompt(text: string): string;
58
+ //#endregion
59
+ export { COMPOSER_CHROME_ICONS, COMPOSER_LINK_KINDS, COMPOSER_LINK_ORIGIN, ComposerChromeIcon, ComposerDraftSegment, ComposerLinkKind, ComposerLinkParts, ParsedComposerLink, brandHexFromIconSrc, chromaticHexFromPixels, composerDraftToPrompt, composerLinkHref, composerTriggerMatch, escapeComposerLinkLabel, inferComposerLinkKind, isComposerChromeIcon, isComposerLinkKind, parseComposerHref, parseComposerLinks, replaceComposerTrigger, sampleImageAccent, serializeComposerLink, splitComposerDraft };
@@ -0,0 +1,203 @@
1
+ //#region src/utils/composer-link.ts
2
+ const COMPOSER_LINK_ORIGIN = "https://composer.invalid";
3
+ const COMPOSER_LINK_KINDS = [
4
+ "command",
5
+ "mcp",
6
+ "skill",
7
+ "tab",
8
+ "file"
9
+ ];
10
+ const COMPOSER_CHROME_ICONS = ["box"];
11
+ const COMPOSER_LINK_KIND_SET = new Set(COMPOSER_LINK_KINDS);
12
+ const COMPOSER_MARKDOWN_LINK = /\[([^\]]+)\]\((https:\/\/composer\.invalid\/(?:command|mcp|skill|tab|file)\/[^)\s]+)\)/g;
13
+ const TRAILING_TRIGGER = /(?:^|\s)([/@])([^\n]*)$/u;
14
+ function isComposerLinkKind(value) {
15
+ return COMPOSER_LINK_KIND_SET.has(value);
16
+ }
17
+ const COMPOSER_CHROME_ICON_SET = new Set(COMPOSER_CHROME_ICONS);
18
+ function isComposerChromeIcon(value) {
19
+ return COMPOSER_CHROME_ICON_SET.has(value);
20
+ }
21
+ function defaultChromeIcon(kind) {
22
+ return kind === "command" || kind === "skill" ? "box" : void 0;
23
+ }
24
+ function parseIconParam(value) {
25
+ if (!value) return {};
26
+ if (isComposerChromeIcon(value)) return { chromeIcon: value };
27
+ return { iconSrc: value };
28
+ }
29
+ function composerLinkHref(parts) {
30
+ const url = new URL(`${COMPOSER_LINK_ORIGIN}/${parts.kind}/${encodeURIComponent(parts.value)}`);
31
+ if (parts.label) url.searchParams.set("label", parts.label);
32
+ const icon = parts.iconSrc ?? parts.chromeIcon ?? defaultChromeIcon(parts.kind);
33
+ if (icon) url.searchParams.set("icon", icon);
34
+ return url.href;
35
+ }
36
+ function parseComposerHref(href) {
37
+ if (!href) return void 0;
38
+ let url;
39
+ try {
40
+ url = new URL(href);
41
+ } catch {
42
+ return;
43
+ }
44
+ if (url.origin !== "https://composer.invalid") return void 0;
45
+ const segments = url.pathname.split("/").filter(Boolean);
46
+ const kind = segments[0];
47
+ const encodedValue = segments.slice(1).join("/");
48
+ if (!kind || !isComposerLinkKind(kind) || !encodedValue) return void 0;
49
+ const value = decodeURIComponent(encodedValue);
50
+ const label = url.searchParams.get("label")?.trim() || void 0;
51
+ const iconParam = parseIconParam(url.searchParams.get("icon")?.trim() || void 0);
52
+ return {
53
+ kind,
54
+ value,
55
+ href: url.href,
56
+ label: label ?? value,
57
+ ...iconParam,
58
+ ...!iconParam.iconSrc && !iconParam.chromeIcon && defaultChromeIcon(kind) ? { chromeIcon: defaultChromeIcon(kind) } : {}
59
+ };
60
+ }
61
+ function escapeComposerLinkLabel(label) {
62
+ return label.replaceAll("[", "").replaceAll("]", "").trim() || label.trim();
63
+ }
64
+ const SIMPLE_ICONS_HEX = /\/([0-9a-fA-F]{6})(?:[/?#]|$)/;
65
+ function srgbChannel(value) {
66
+ const channel = value / 255;
67
+ return channel <= .03928 ? channel / 12.92 : ((channel + .055) / 1.055) ** 2.4;
68
+ }
69
+ function isUsableTextColor(red, green, blue) {
70
+ const luminance = .2126 * srgbChannel(red) + .7152 * srgbChannel(green) + .0722 * srgbChannel(blue);
71
+ return luminance >= .12 && luminance <= .82;
72
+ }
73
+ /** Brand hex from a Simple Icons URL, skipped when it would vanish as text. */
74
+ function brandHexFromIconSrc(src) {
75
+ if (!src) return void 0;
76
+ const hex = SIMPLE_ICONS_HEX.exec(src)?.[1];
77
+ if (!hex) return void 0;
78
+ return isUsableTextColor(Number.parseInt(hex.slice(0, 2), 16), Number.parseInt(hex.slice(2, 4), 16), Number.parseInt(hex.slice(4, 6), 16)) ? `#${hex}` : void 0;
79
+ }
80
+ /** Most chromatic opaque pixel, skipped when the mark is charcoal, white, or gray. */
81
+ function chromaticHexFromPixels(data) {
82
+ let bestChroma = 0;
83
+ let best;
84
+ for (let index = 0; index + 3 < data.length; index += 4) {
85
+ if ((data[index + 3] ?? 0) < 128) continue;
86
+ const red = data[index] ?? 0;
87
+ const green = data[index + 1] ?? 0;
88
+ const blue = data[index + 2] ?? 0;
89
+ const chroma = Math.max(red, green, blue) / 255 - Math.min(red, green, blue) / 255;
90
+ if (chroma < .18 || !isUsableTextColor(red, green, blue)) continue;
91
+ if (chroma > bestChroma) {
92
+ bestChroma = chroma;
93
+ best = `#${[
94
+ red,
95
+ green,
96
+ blue
97
+ ].map((channel) => channel.toString(16).padStart(2, "0")).join("")}`;
98
+ }
99
+ }
100
+ return best;
101
+ }
102
+ function sampleImageAccent(image) {
103
+ if (!image.naturalWidth) return void 0;
104
+ const canvas = document.createElement("canvas");
105
+ canvas.width = 32;
106
+ canvas.height = 32;
107
+ const context = canvas.getContext("2d", { willReadFrequently: true });
108
+ if (!context) return void 0;
109
+ try {
110
+ context.drawImage(image, 0, 0, 32, 32);
111
+ return chromaticHexFromPixels(context.getImageData(0, 0, 32, 32).data);
112
+ } catch {
113
+ return;
114
+ }
115
+ }
116
+ function serializeComposerLink(parts) {
117
+ const label = escapeComposerLinkLabel(parts.label);
118
+ return `[${label}](${composerLinkHref({
119
+ ...parts,
120
+ label
121
+ })})`;
122
+ }
123
+ function splitComposerDraft(text) {
124
+ const segments = [];
125
+ let lastIndex = 0;
126
+ for (const match of text.matchAll(COMPOSER_MARKDOWN_LINK)) {
127
+ const index = match.index ?? 0;
128
+ if (index > lastIndex) segments.push({
129
+ type: "text",
130
+ value: text.slice(lastIndex, index)
131
+ });
132
+ const parsed = parseComposerHref(match[2] ?? "");
133
+ const label = match[1] ?? parsed?.label ?? "";
134
+ if (!parsed) segments.push({
135
+ type: "text",
136
+ value: match[0] ?? ""
137
+ });
138
+ else segments.push({
139
+ type: "link",
140
+ href: parsed.href,
141
+ label,
142
+ parts: {
143
+ ...parsed,
144
+ label
145
+ }
146
+ });
147
+ lastIndex = index + (match[0]?.length ?? 0);
148
+ }
149
+ if (lastIndex < text.length) segments.push({
150
+ type: "text",
151
+ value: text.slice(lastIndex)
152
+ });
153
+ return segments;
154
+ }
155
+ function parseComposerLinks(text) {
156
+ return splitComposerDraft(text).flatMap((segment) => segment.type === "link" ? [segment.parts] : []);
157
+ }
158
+ function composerTriggerMatch(text) {
159
+ const match = TRAILING_TRIGGER.exec(text);
160
+ if (!match) return void 0;
161
+ const trigger = match[1];
162
+ if (trigger !== "/" && trigger !== "@") return void 0;
163
+ const matchIndex = match.index ?? 0;
164
+ const triggerIndex = text[matchIndex] === "/" || text[matchIndex] === "@" ? matchIndex : matchIndex + 1;
165
+ return {
166
+ trigger,
167
+ query: match[2] ?? "",
168
+ triggerIndex
169
+ };
170
+ }
171
+ function inferComposerLinkKind(command, trigger) {
172
+ const id = command.id ?? "";
173
+ if (id.startsWith("mcp:")) return "mcp";
174
+ if (id.startsWith("tab:")) return "tab";
175
+ if (id.startsWith("skill:")) return "skill";
176
+ if (id.startsWith("file:")) return "file";
177
+ return trigger === "@" ? "mcp" : "command";
178
+ }
179
+ function replaceComposerTrigger(draft, command, trigger) {
180
+ const href = command.href ?? composerLinkHref({
181
+ kind: inferComposerLinkKind(command, trigger),
182
+ value: command.value,
183
+ label: command.label,
184
+ iconSrc: command.iconSrc
185
+ });
186
+ const markdown = `[${escapeComposerLinkLabel(command.label)}](${href})`;
187
+ const match = composerTriggerMatch(draft);
188
+ if (!match) {
189
+ const trimmed = draft.trimEnd();
190
+ return trimmed ? `${trimmed} ${markdown} ` : `${markdown} `;
191
+ }
192
+ return `${draft.slice(0, match.triggerIndex)}${markdown} `;
193
+ }
194
+ function composerDraftToPrompt(text) {
195
+ return splitComposerDraft(text).map((segment) => {
196
+ if (segment.type === "text") return segment.value;
197
+ if (segment.parts.kind === "mcp" || segment.parts.kind === "tab") return `@${segment.parts.value}`;
198
+ if (segment.parts.kind === "file") return segment.parts.value;
199
+ return `/${segment.parts.value}`;
200
+ }).join("").replace(/[^\S\n]+/g, " ").trim();
201
+ }
202
+ //#endregion
203
+ export { COMPOSER_CHROME_ICONS, COMPOSER_LINK_KINDS, COMPOSER_LINK_ORIGIN, brandHexFromIconSrc, chromaticHexFromPixels, composerDraftToPrompt, composerLinkHref, composerTriggerMatch, escapeComposerLinkLabel, inferComposerLinkKind, isComposerChromeIcon, isComposerLinkKind, parseComposerHref, parseComposerLinks, replaceComposerTrigger, sampleImageAccent, serializeComposerLink, splitComposerDraft };
@@ -1,2 +1,2 @@
1
- import { a as MCP_SERVER_SETUP_AUTH, c as McpServerManualSetup, d as McpServerSetupAuthFieldName, f as McpServerSetupLink, h as getMcpServerRuntimeState, i as MANUAL_MCP_SERVER_CARDS, l as McpServerSetupAuth, m as getMcpServerIconSrc, n as DCR_MCP_SERVER_CARDS, o as McpServerCard, p as getMcpServerEntry, r as DEFAULT_MCP_SERVER_CARDS, s as McpServerCardIcon, t as CUSTOM_MCP_SERVER_CARD, u as McpServerSetupAuthField } from "../mcp-server-catalog-CCj2ItkV.js";
1
+ import { a as MCP_SERVER_SETUP_AUTH, c as McpServerManualSetup, d as McpServerSetupAuthFieldName, f as McpServerSetupLink, h as getMcpServerRuntimeState, i as MANUAL_MCP_SERVER_CARDS, l as McpServerSetupAuth, m as getMcpServerIconSrc, n as DCR_MCP_SERVER_CARDS, o as McpServerCard, p as getMcpServerEntry, r as DEFAULT_MCP_SERVER_CARDS, s as McpServerCardIcon, t as CUSTOM_MCP_SERVER_CARD, u as McpServerSetupAuthField } from "../mcp-server-catalog-Cbu483Zb.js";
2
2
  export { CUSTOM_MCP_SERVER_CARD, DCR_MCP_SERVER_CARDS, DEFAULT_MCP_SERVER_CARDS, MANUAL_MCP_SERVER_CARDS, MCP_SERVER_SETUP_AUTH, McpServerCard, McpServerCardIcon, McpServerManualSetup, McpServerSetupAuth, McpServerSetupAuthField, McpServerSetupAuthFieldName, McpServerSetupLink, getMcpServerEntry, getMcpServerIconSrc, getMcpServerRuntimeState };
@@ -274,7 +274,7 @@ const DCR_MCP_SERVER_CARDS = [
274
274
  url: "https://mcp.miro.com/mcp",
275
275
  description: "Work with boards and diagrams",
276
276
  category: DCR_CATEGORY,
277
- icon: "https://cdn.simpleicons.org/miro/FFD02F"
277
+ icon: "https://cdn.simpleicons.org/miro/050038"
278
278
  },
279
279
  {
280
280
  id: "monday",
@@ -298,7 +298,7 @@ const DCR_MCP_SERVER_CARDS = [
298
298
  url: "https://mcp.notion.com/mcp",
299
299
  description: "Work across docs, wikis, and project notes",
300
300
  category: DCR_CATEGORY,
301
- icon: "https://cdn.simpleicons.org/notion/A1A1AA"
301
+ icon: "https://cdn.simpleicons.org/notion/000000"
302
302
  },
303
303
  {
304
304
  id: "paypal",
@@ -306,7 +306,7 @@ const DCR_MCP_SERVER_CARDS = [
306
306
  url: "https://mcp.paypal.com/mcp",
307
307
  description: "Use PayPal merchant tools",
308
308
  category: DCR_CATEGORY,
309
- icon: "https://cdn.simpleicons.org/paypal/003087"
309
+ icon: "https://cdn.simpleicons.org/paypal/002991"
310
310
  },
311
311
  {
312
312
  id: "postman",
@@ -322,7 +322,7 @@ const DCR_MCP_SERVER_CARDS = [
322
322
  url: "https://mcp.railway.com",
323
323
  description: "Manage Railway projects and services",
324
324
  category: DCR_CATEGORY,
325
- icon: "https://cdn.simpleicons.org/railway/8957E5"
325
+ icon: "https://cdn.simpleicons.org/railway/0B0D0E"
326
326
  },
327
327
  {
328
328
  id: "ramp",
@@ -338,7 +338,7 @@ const DCR_MCP_SERVER_CARDS = [
338
338
  url: "https://mcp.sentry.dev/mcp",
339
339
  description: "Debug errors and inspect projects",
340
340
  category: DCR_CATEGORY,
341
- icon: "https://cdn.simpleicons.org/sentry/8957E5"
341
+ icon: "https://cdn.simpleicons.org/sentry/362D59"
342
342
  },
343
343
  {
344
344
  id: "square",
@@ -362,7 +362,7 @@ const DCR_MCP_SERVER_CARDS = [
362
362
  url: "https://mcp.supabase.com/mcp",
363
363
  description: "Manage Supabase projects",
364
364
  category: DCR_CATEGORY,
365
- icon: "https://cdn.simpleicons.org/supabase/3ECF8E"
365
+ icon: "https://cdn.simpleicons.org/supabase/3FCF8E"
366
366
  },
367
367
  {
368
368
  id: "vercel",
@@ -370,7 +370,7 @@ const DCR_MCP_SERVER_CARDS = [
370
370
  url: "https://mcp.vercel.com",
371
371
  description: "Manage projects and deployments",
372
372
  category: DCR_CATEGORY,
373
- icon: "https://cdn.simpleicons.org/vercel/A1A1AA"
373
+ icon: "https://cdn.simpleicons.org/vercel/000000"
374
374
  },
375
375
  {
376
376
  id: "webflow",
@@ -386,7 +386,7 @@ const DCR_MCP_SERVER_CARDS = [
386
386
  url: "https://mcp.wix.com/mcp",
387
387
  description: "Work with Wix sites and apps",
388
388
  category: DCR_CATEGORY,
389
- icon: "https://cdn.simpleicons.org/wix/A1A1AA"
389
+ icon: "https://cdn.simpleicons.org/wix/0C6EFC"
390
390
  },
391
391
  {
392
392
  id: "zapier",
@@ -491,7 +491,7 @@ const MANUAL_MCP_SERVER_CARDS = [
491
491
  url: "https://chatmcp.googleapis.com/mcp/v1",
492
492
  description: "Read spaces, memberships, and messages",
493
493
  category: MANUAL_CATEGORY,
494
- icon: "https://cdn.simpleicons.org/googlechat/00AC47",
494
+ icon: "https://cdn.simpleicons.org/googlechat/34A853",
495
495
  manualSetup: {
496
496
  auth: MCP_SERVER_SETUP_AUTH.manualOAuthClientSecret,
497
497
  description: "Enable Chat and Chat MCP APIs, configure a Chat app, and create a web OAuth client.",