@tonyclaw/agent-inspector 2.0.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 (400) hide show
  1. package/.output/cli.js +1611 -0
  2. package/.output/nitro.json +17 -0
  3. package/.output/public/assets/CompareDrawer-CU5ZrWcL.js +1 -0
  4. package/.output/public/assets/ProxyViewerContainer-pEBqVp1d.js +101 -0
  5. package/.output/public/assets/ReplayDialog-F58yNg5j.js +1 -0
  6. package/.output/public/assets/RequestAnatomy-C9lT0qE_.js +1 -0
  7. package/.output/public/assets/ResponseView-DHJq6bnz.js +1 -0
  8. package/.output/public/assets/StreamingChunkSequence-BTgfpFUT.js +1 -0
  9. package/.output/public/assets/_sessionId-DsNRbnNm.js +1 -0
  10. package/.output/public/assets/alibaba-TTwafVwX.svg +1 -0
  11. package/.output/public/assets/index-CpWG2hFn.css +1 -0
  12. package/.output/public/assets/index-DmBV8Gve.js +1 -0
  13. package/.output/public/assets/json-viewer-CZVYLR8j.js +14 -0
  14. package/.output/public/assets/main-DHs7FBK3.js +18 -0
  15. package/.output/public/assets/minimax-BPMzvuL-.jpeg +0 -0
  16. package/.output/public/assets/qwen-CONDcHqt.png +0 -0
  17. package/.output/public/assets/zhipuai-BPNAnxo-.svg +219 -0
  18. package/.output/server/_chunks/ssr-renderer.mjs +22 -0
  19. package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +1 -0
  20. package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +210 -0
  21. package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +2 -0
  22. package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +2 -0
  23. package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +2 -0
  24. package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +11 -0
  25. package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +69 -0
  26. package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +1 -0
  27. package/.output/server/_libs/@radix-ui/react-use-escape-keydown+[...].mjs +17 -0
  28. package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +1 -0
  29. package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +6 -0
  30. package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +34 -0
  31. package/.output/server/_libs/ajv-formats.mjs +330 -0
  32. package/.output/server/_libs/ajv.mjs +11444 -0
  33. package/.output/server/_libs/aria-hidden.mjs +122 -0
  34. package/.output/server/_libs/atomically.mjs +152 -0
  35. package/.output/server/_libs/bail.mjs +8 -0
  36. package/.output/server/_libs/cfworker__json-schema.mjs +1 -0
  37. package/.output/server/_libs/character-entities.mjs +2130 -0
  38. package/.output/server/_libs/class-variance-authority.mjs +44 -0
  39. package/.output/server/_libs/clsx.mjs +16 -0
  40. package/.output/server/_libs/comma-separated-tokens.mjs +10 -0
  41. package/.output/server/_libs/conf.mjs +635 -0
  42. package/.output/server/_libs/cookie-es.mjs +58 -0
  43. package/.output/server/_libs/core-util-is.mjs +75 -0
  44. package/.output/server/_libs/croner.mjs +1 -0
  45. package/.output/server/_libs/crossws.mjs +1 -0
  46. package/.output/server/_libs/debounce-fn.mjs +69 -0
  47. package/.output/server/_libs/decode-named-character-reference+[...].mjs +8 -0
  48. package/.output/server/_libs/dequal.mjs +27 -0
  49. package/.output/server/_libs/detect-node-es.mjs +1 -0
  50. package/.output/server/_libs/devlop.mjs +8 -0
  51. package/.output/server/_libs/diff.mjs +320 -0
  52. package/.output/server/_libs/dot-prop.mjs +265 -0
  53. package/.output/server/_libs/env-paths.mjs +57 -0
  54. package/.output/server/_libs/estree-util-is-identifier-name.mjs +11 -0
  55. package/.output/server/_libs/extend.mjs +97 -0
  56. package/.output/server/_libs/fast-deep-equal.mjs +38 -0
  57. package/.output/server/_libs/fast-uri.mjs +812 -0
  58. package/.output/server/_libs/floating-ui__core.mjs +725 -0
  59. package/.output/server/_libs/floating-ui__dom.mjs +622 -0
  60. package/.output/server/_libs/floating-ui__react-dom.mjs +292 -0
  61. package/.output/server/_libs/floating-ui__utils.mjs +320 -0
  62. package/.output/server/_libs/get-nonce.mjs +9 -0
  63. package/.output/server/_libs/h3-v2.mjs +276 -0
  64. package/.output/server/_libs/h3.mjs +408 -0
  65. package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
  66. package/.output/server/_libs/hast-util-whitespace.mjs +10 -0
  67. package/.output/server/_libs/hookable.mjs +1 -0
  68. package/.output/server/_libs/html-url-attributes.mjs +26 -0
  69. package/.output/server/_libs/immediate.mjs +74 -0
  70. package/.output/server/_libs/inherits.mjs +50 -0
  71. package/.output/server/_libs/inline-style-parser.mjs +142 -0
  72. package/.output/server/_libs/is-plain-obj.mjs +10 -0
  73. package/.output/server/_libs/isarray.mjs +14 -0
  74. package/.output/server/_libs/isbot.mjs +20 -0
  75. package/.output/server/_libs/json-schema-traverse.mjs +180 -0
  76. package/.output/server/_libs/jszip.mjs +3051 -0
  77. package/.output/server/_libs/lie.mjs +273 -0
  78. package/.output/server/_libs/lucide-react.mjs +492 -0
  79. package/.output/server/_libs/mdast-util-from-markdown.mjs +717 -0
  80. package/.output/server/_libs/mdast-util-to-hast.mjs +710 -0
  81. package/.output/server/_libs/mdast-util-to-string.mjs +38 -0
  82. package/.output/server/_libs/micromark-core-commonmark.mjs +2259 -0
  83. package/.output/server/_libs/micromark-factory-destination.mjs +94 -0
  84. package/.output/server/_libs/micromark-factory-label.mjs +63 -0
  85. package/.output/server/_libs/micromark-factory-space.mjs +24 -0
  86. package/.output/server/_libs/micromark-factory-title.mjs +65 -0
  87. package/.output/server/_libs/micromark-factory-whitespace.mjs +22 -0
  88. package/.output/server/_libs/micromark-util-character.mjs +44 -0
  89. package/.output/server/_libs/micromark-util-chunked.mjs +36 -0
  90. package/.output/server/_libs/micromark-util-classify-character+[...].mjs +12 -0
  91. package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
  92. package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
  93. package/.output/server/_libs/micromark-util-decode-string.mjs +21 -0
  94. package/.output/server/_libs/micromark-util-encode.mjs +1 -0
  95. package/.output/server/_libs/micromark-util-html-tag-name.mjs +69 -0
  96. package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
  97. package/.output/server/_libs/micromark-util-resolve-all.mjs +15 -0
  98. package/.output/server/_libs/micromark-util-sanitize-uri.mjs +41 -0
  99. package/.output/server/_libs/micromark-util-subtokenize.mjs +346 -0
  100. package/.output/server/_libs/micromark.mjs +906 -0
  101. package/.output/server/_libs/mimic-function.mjs +47 -0
  102. package/.output/server/_libs/modelcontextprotocol__server.mjs +9738 -0
  103. package/.output/server/_libs/ocache.mjs +1 -0
  104. package/.output/server/_libs/ohash.mjs +1 -0
  105. package/.output/server/_libs/pako.mjs +4223 -0
  106. package/.output/server/_libs/process-nextick-args.mjs +48 -0
  107. package/.output/server/_libs/property-information.mjs +1209 -0
  108. package/.output/server/_libs/radix-ui.mjs +1 -0
  109. package/.output/server/_libs/radix-ui__number.mjs +6 -0
  110. package/.output/server/_libs/radix-ui__primitive.mjs +11 -0
  111. package/.output/server/_libs/radix-ui__react-accordion.mjs +1 -0
  112. package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +1 -0
  113. package/.output/server/_libs/radix-ui__react-arrow.mjs +23 -0
  114. package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +1 -0
  115. package/.output/server/_libs/radix-ui__react-avatar.mjs +1 -0
  116. package/.output/server/_libs/radix-ui__react-checkbox.mjs +1 -0
  117. package/.output/server/_libs/radix-ui__react-collapsible.mjs +144 -0
  118. package/.output/server/_libs/radix-ui__react-collection.mjs +69 -0
  119. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +39 -0
  120. package/.output/server/_libs/radix-ui__react-context-menu.mjs +1 -0
  121. package/.output/server/_libs/radix-ui__react-context.mjs +78 -0
  122. package/.output/server/_libs/radix-ui__react-dialog.mjs +325 -0
  123. package/.output/server/_libs/radix-ui__react-direction.mjs +9 -0
  124. package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +1 -0
  125. package/.output/server/_libs/radix-ui__react-focus-guards.mjs +29 -0
  126. package/.output/server/_libs/radix-ui__react-focus-scope.mjs +206 -0
  127. package/.output/server/_libs/radix-ui__react-form.mjs +1 -0
  128. package/.output/server/_libs/radix-ui__react-hover-card.mjs +1 -0
  129. package/.output/server/_libs/radix-ui__react-id.mjs +14 -0
  130. package/.output/server/_libs/radix-ui__react-label.mjs +1 -0
  131. package/.output/server/_libs/radix-ui__react-menu.mjs +1 -0
  132. package/.output/server/_libs/radix-ui__react-menubar.mjs +1 -0
  133. package/.output/server/_libs/radix-ui__react-popover.mjs +1 -0
  134. package/.output/server/_libs/radix-ui__react-popper.mjs +286 -0
  135. package/.output/server/_libs/radix-ui__react-portal.mjs +16 -0
  136. package/.output/server/_libs/radix-ui__react-presence.mjs +128 -0
  137. package/.output/server/_libs/radix-ui__react-primitive.mjs +42 -0
  138. package/.output/server/_libs/radix-ui__react-progress.mjs +1 -0
  139. package/.output/server/_libs/radix-ui__react-radio-group.mjs +1 -0
  140. package/.output/server/_libs/radix-ui__react-roving-focus.mjs +224 -0
  141. package/.output/server/_libs/radix-ui__react-scroll-area.mjs +721 -0
  142. package/.output/server/_libs/radix-ui__react-select.mjs +1163 -0
  143. package/.output/server/_libs/radix-ui__react-separator.mjs +28 -0
  144. package/.output/server/_libs/radix-ui__react-slider.mjs +1 -0
  145. package/.output/server/_libs/radix-ui__react-slot.mjs +99 -0
  146. package/.output/server/_libs/radix-ui__react-switch.mjs +1 -0
  147. package/.output/server/_libs/radix-ui__react-tabs.mjs +189 -0
  148. package/.output/server/_libs/radix-ui__react-toast.mjs +2 -0
  149. package/.output/server/_libs/radix-ui__react-toggle-group.mjs +1 -0
  150. package/.output/server/_libs/radix-ui__react-toggle.mjs +1 -0
  151. package/.output/server/_libs/radix-ui__react-toolbar.mjs +1 -0
  152. package/.output/server/_libs/radix-ui__react-tooltip.mjs +495 -0
  153. package/.output/server/_libs/radix-ui__react-use-previous.mjs +14 -0
  154. package/.output/server/_libs/radix-ui__react-use-size.mjs +39 -0
  155. package/.output/server/_libs/react-dom.mjs +10781 -0
  156. package/.output/server/_libs/react-markdown.mjs +147 -0
  157. package/.output/server/_libs/react-remove-scroll-bar.mjs +82 -0
  158. package/.output/server/_libs/react-remove-scroll.mjs +328 -0
  159. package/.output/server/_libs/react-style-singleton.mjs +69 -0
  160. package/.output/server/_libs/react.mjs +515 -0
  161. package/.output/server/_libs/readable-stream.mjs +1518 -0
  162. package/.output/server/_libs/remark-parse.mjs +19 -0
  163. package/.output/server/_libs/remark-rehype.mjs +21 -0
  164. package/.output/server/_libs/rou3.mjs +14 -0
  165. package/.output/server/_libs/safe-buffer.mjs +64 -0
  166. package/.output/server/_libs/semver.mjs +1938 -0
  167. package/.output/server/_libs/seroval-plugins.mjs +58 -0
  168. package/.output/server/_libs/seroval.mjs +1765 -0
  169. package/.output/server/_libs/setimmediate.mjs +152 -0
  170. package/.output/server/_libs/space-separated-tokens.mjs +6 -0
  171. package/.output/server/_libs/srvx.mjs +1029 -0
  172. package/.output/server/_libs/stubborn-fs.mjs +91 -0
  173. package/.output/server/_libs/stubborn-utils.mjs +66 -0
  174. package/.output/server/_libs/style-to-js.mjs +72 -0
  175. package/.output/server/_libs/style-to-object.mjs +38 -0
  176. package/.output/server/_libs/swr.mjs +939 -0
  177. package/.output/server/_libs/tailwind-merge.mjs +3010 -0
  178. package/.output/server/_libs/tanstack__history.mjs +217 -0
  179. package/.output/server/_libs/tanstack__react-router.mjs +1480 -0
  180. package/.output/server/_libs/tanstack__react-store.mjs +1 -0
  181. package/.output/server/_libs/tanstack__react-virtual.mjs +44 -0
  182. package/.output/server/_libs/tanstack__router-core.mjs +4827 -0
  183. package/.output/server/_libs/tanstack__store.mjs +1 -0
  184. package/.output/server/_libs/tanstack__virtual-core.mjs +1225 -0
  185. package/.output/server/_libs/tiny-invariant.mjs +12 -0
  186. package/.output/server/_libs/tiny-warning.mjs +5 -0
  187. package/.output/server/_libs/trim-lines.mjs +41 -0
  188. package/.output/server/_libs/trough.mjs +85 -0
  189. package/.output/server/_libs/tslib.mjs +1 -0
  190. package/.output/server/_libs/ufo.mjs +54 -0
  191. package/.output/server/_libs/uint8array-extras.mjs +69 -0
  192. package/.output/server/_libs/ungap__structured-clone.mjs +212 -0
  193. package/.output/server/_libs/unified.mjs +661 -0
  194. package/.output/server/_libs/unist-util-is.mjs +100 -0
  195. package/.output/server/_libs/unist-util-position.mjs +27 -0
  196. package/.output/server/_libs/unist-util-stringify-position.mjs +27 -0
  197. package/.output/server/_libs/unist-util-visit-parents.mjs +82 -0
  198. package/.output/server/_libs/unist-util-visit.mjs +24 -0
  199. package/.output/server/_libs/unstorage.mjs +1 -0
  200. package/.output/server/_libs/use-callback-ref.mjs +66 -0
  201. package/.output/server/_libs/use-sidecar.mjs +106 -0
  202. package/.output/server/_libs/use-sync-external-store.mjs +64 -0
  203. package/.output/server/_libs/util-deprecate.mjs +12 -0
  204. package/.output/server/_libs/vfile-message.mjs +138 -0
  205. package/.output/server/_libs/vfile.mjs +467 -0
  206. package/.output/server/_libs/when-exit.mjs +53 -0
  207. package/.output/server/_libs/zod.mjs +4524 -0
  208. package/.output/server/_sessionId-wMLPvC5g.mjs +123 -0
  209. package/.output/server/_ssr/CompareDrawer-BU4V0uVf.mjs +1041 -0
  210. package/.output/server/_ssr/ProxyViewerContainer-BnRwFEnn.mjs +5972 -0
  211. package/.output/server/_ssr/ReplayDialog-C7dn9pd_.mjs +322 -0
  212. package/.output/server/_ssr/RequestAnatomy-C1rWpe9-.mjs +353 -0
  213. package/.output/server/_ssr/ResponseView-hGpPaYsf.mjs +602 -0
  214. package/.output/server/_ssr/StreamingChunkSequence-BRWI1r_G.mjs +302 -0
  215. package/.output/server/_ssr/index-BKURLVPz.mjs +118 -0
  216. package/.output/server/_ssr/index.mjs +1184 -0
  217. package/.output/server/_ssr/json-viewer-BBd2DtQP.mjs +515 -0
  218. package/.output/server/_ssr/router-BcZ0D6AB.mjs +6317 -0
  219. package/.output/server/_ssr/start-HYkvq4Ni.mjs +4 -0
  220. package/.output/server/_tanstack-start-manifest_v-1y8ZVxRI.mjs +4 -0
  221. package/.output/server/index.mjs +436 -0
  222. package/.output/server/node_modules/tslib/modules/index.js +70 -0
  223. package/.output/server/node_modules/tslib/modules/package.json +3 -0
  224. package/.output/server/node_modules/tslib/package.json +47 -0
  225. package/.output/server/node_modules/tslib/tslib.js +484 -0
  226. package/.output/server/package.json +9 -0
  227. package/LICENSE +21 -0
  228. package/README.md +52 -0
  229. package/package.json +110 -0
  230. package/src/assets/favicon.svg +31 -0
  231. package/src/assets/logos/alibaba.svg +1 -0
  232. package/src/assets/logos/anthropic.svg +1 -0
  233. package/src/assets/logos/claude-code.svg +4 -0
  234. package/src/assets/logos/deepseek.svg +1 -0
  235. package/src/assets/logos/mcp.png +0 -0
  236. package/src/assets/logos/minimax.jpeg +0 -0
  237. package/src/assets/logos/openai.svg +1 -0
  238. package/src/assets/logos/opencode.svg +4 -0
  239. package/src/assets/logos/qwen.png +0 -0
  240. package/src/assets/logos/zhipuai.svg +219 -0
  241. package/src/cli/detect-tools.ts +147 -0
  242. package/src/cli/doctor.ts +521 -0
  243. package/src/cli/onboard.ts +224 -0
  244. package/src/cli/templates/command-onboard.ts +17 -0
  245. package/src/cli/templates/skill-onboard.ts +547 -0
  246. package/src/cli.ts +345 -0
  247. package/src/components/OnboardingBanner.tsx +67 -0
  248. package/src/components/ProxyViewer.tsx +545 -0
  249. package/src/components/ProxyViewerContainer.tsx +363 -0
  250. package/src/components/providers/ImportWizardDialog.tsx +349 -0
  251. package/src/components/providers/ProviderCard.tsx +474 -0
  252. package/src/components/providers/ProviderForm.tsx +494 -0
  253. package/src/components/providers/ProviderLogo.tsx +117 -0
  254. package/src/components/providers/ProvidersPanel.tsx +619 -0
  255. package/src/components/providers/SettingsDialog.tsx +202 -0
  256. package/src/components/proxy-viewer/CompareDrawer.tsx +893 -0
  257. package/src/components/proxy-viewer/ConversationGroup.tsx +107 -0
  258. package/src/components/proxy-viewer/ConversationHeader.tsx +300 -0
  259. package/src/components/proxy-viewer/LogEntry.tsx +543 -0
  260. package/src/components/proxy-viewer/LogEntryHeader.tsx +501 -0
  261. package/src/components/proxy-viewer/ReplayDialog.tsx +218 -0
  262. package/src/components/proxy-viewer/ResponseView.tsx +171 -0
  263. package/src/components/proxy-viewer/StreamingChunkSequence.tsx +188 -0
  264. package/src/components/proxy-viewer/ThreadConnector.tsx +136 -0
  265. package/src/components/proxy-viewer/TurnGroup.tsx +337 -0
  266. package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +98 -0
  267. package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +196 -0
  268. package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +53 -0
  269. package/src/components/proxy-viewer/anatomy/types.ts +39 -0
  270. package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +114 -0
  271. package/src/components/proxy-viewer/cacheTrend.ts +50 -0
  272. package/src/components/proxy-viewer/diff/DiffView.tsx +321 -0
  273. package/src/components/proxy-viewer/diff/computeDiff.ts +178 -0
  274. package/src/components/proxy-viewer/diff/index.ts +3 -0
  275. package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +157 -0
  276. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +66 -0
  277. package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +21 -0
  278. package/src/components/proxy-viewer/formats/index.tsx +33 -0
  279. package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +170 -0
  280. package/src/components/proxy-viewer/index.ts +9 -0
  281. package/src/components/proxy-viewer/lazy.ts +37 -0
  282. package/src/components/proxy-viewer/log-formats/anthropic.ts +194 -0
  283. package/src/components/proxy-viewer/log-formats/index.ts +23 -0
  284. package/src/components/proxy-viewer/log-formats/openai.ts +167 -0
  285. package/src/components/proxy-viewer/log-formats/types.ts +40 -0
  286. package/src/components/proxy-viewer/log-formats/unknown.ts +18 -0
  287. package/src/components/proxy-viewer/logEntryVisibility.ts +39 -0
  288. package/src/components/proxy-viewer/requestDiff.ts +277 -0
  289. package/src/components/proxy-viewer/useCopyFeedback.ts +36 -0
  290. package/src/components/proxy-viewer/useKeyboardNavigation.ts +190 -0
  291. package/src/components/proxy-viewer/viewerState.ts +66 -0
  292. package/src/components/ui/badge.tsx +47 -0
  293. package/src/components/ui/button.tsx +47 -0
  294. package/src/components/ui/collapsible.tsx +21 -0
  295. package/src/components/ui/confirm-dialog.tsx +51 -0
  296. package/src/components/ui/crab-logo.tsx +95 -0
  297. package/src/components/ui/crab-variants.tsx +467 -0
  298. package/src/components/ui/dialog.tsx +129 -0
  299. package/src/components/ui/json-expansion-button.tsx +56 -0
  300. package/src/components/ui/json-viewer-bulk.ts +97 -0
  301. package/src/components/ui/json-viewer.tsx +494 -0
  302. package/src/components/ui/mcp-logo.tsx +20 -0
  303. package/src/components/ui/scroll-area.tsx +54 -0
  304. package/src/components/ui/select.tsx +178 -0
  305. package/src/components/ui/separator.tsx +28 -0
  306. package/src/components/ui/tabs.tsx +88 -0
  307. package/src/components/ui/tooltip.tsx +51 -0
  308. package/src/index.css +11 -0
  309. package/src/knowledge/candidateStore.ts +63 -0
  310. package/src/knowledge/distiller.ts +98 -0
  311. package/src/knowledge/openclawClient.ts +118 -0
  312. package/src/knowledge/redactor.ts +80 -0
  313. package/src/knowledge/types.ts +84 -0
  314. package/src/lib/apiClient.ts +49 -0
  315. package/src/lib/export-logs.ts +51 -0
  316. package/src/lib/mask.ts +4 -0
  317. package/src/lib/objectUtils.ts +22 -0
  318. package/src/lib/providerContract.ts +26 -0
  319. package/src/lib/providerTestContract.ts +107 -0
  320. package/src/lib/runtimeConfig.ts +25 -0
  321. package/src/lib/serverPort.ts +41 -0
  322. package/src/lib/sessionUrl.ts +44 -0
  323. package/src/lib/stopReason.ts +58 -0
  324. package/src/lib/useOnboarding.ts +80 -0
  325. package/src/lib/useProviders.ts +30 -0
  326. package/src/lib/useStripConfig.ts +108 -0
  327. package/src/lib/utils.ts +21 -0
  328. package/src/mcp/loopback.ts +76 -0
  329. package/src/mcp/previewExtractor.ts +166 -0
  330. package/src/mcp/server.ts +396 -0
  331. package/src/mcp/toolHandlers.ts +341 -0
  332. package/src/proxy/chunkStorage.ts +112 -0
  333. package/src/proxy/claudeCodeStrip.ts +99 -0
  334. package/src/proxy/config.ts +172 -0
  335. package/src/proxy/constants.ts +47 -0
  336. package/src/proxy/dataDir.ts +86 -0
  337. package/src/proxy/formats/anthropic/anthropicProvider.ts +75 -0
  338. package/src/proxy/formats/anthropic/handler.ts +71 -0
  339. package/src/proxy/formats/anthropic/index.ts +14 -0
  340. package/src/proxy/formats/anthropic/register.ts +4 -0
  341. package/src/proxy/formats/anthropic/schemas.ts +237 -0
  342. package/src/proxy/formats/anthropic/stream.ts +205 -0
  343. package/src/proxy/formats/handler.ts +46 -0
  344. package/src/proxy/formats/index.ts +12 -0
  345. package/src/proxy/formats/jsonSchema.ts +36 -0
  346. package/src/proxy/formats/openai/alibabaProvider.ts +38 -0
  347. package/src/proxy/formats/openai/handler.ts +96 -0
  348. package/src/proxy/formats/openai/index.ts +25 -0
  349. package/src/proxy/formats/openai/provider.ts +50 -0
  350. package/src/proxy/formats/openai/register.ts +4 -0
  351. package/src/proxy/formats/openai/schemas.ts +187 -0
  352. package/src/proxy/formats/openai/stream.ts +206 -0
  353. package/src/proxy/formats/protocol.ts +50 -0
  354. package/src/proxy/formats/providerRegistry.ts +51 -0
  355. package/src/proxy/formats/providers/index.ts +3 -0
  356. package/src/proxy/formats/registry.ts +66 -0
  357. package/src/proxy/handler.ts +334 -0
  358. package/src/proxy/logFinalizer.ts +305 -0
  359. package/src/proxy/logFinalizer.worker.ts +24 -0
  360. package/src/proxy/logIndex.ts +268 -0
  361. package/src/proxy/logger.ts +179 -0
  362. package/src/proxy/openaiOrphanToolStrip.ts +142 -0
  363. package/src/proxy/providerImporters.ts +491 -0
  364. package/src/proxy/providers.ts +613 -0
  365. package/src/proxy/schemas.ts +209 -0
  366. package/src/proxy/sessionProcess.ts +140 -0
  367. package/src/proxy/sessionRuntime.ts +85 -0
  368. package/src/proxy/sessionSupervisor.ts +283 -0
  369. package/src/proxy/sessionWorkerEntry.ts +26 -0
  370. package/src/proxy/socketTracker.ts +255 -0
  371. package/src/proxy/store.ts +412 -0
  372. package/src/proxy/upstream.ts +90 -0
  373. package/src/router.tsx +16 -0
  374. package/src/routes/__root.tsx +45 -0
  375. package/src/routes/api/config.paths.ts +14 -0
  376. package/src/routes/api/config.ts +53 -0
  377. package/src/routes/api/health.ts +15 -0
  378. package/src/routes/api/knowledge.candidates.$candidateId.promote.ts +32 -0
  379. package/src/routes/api/knowledge.candidates.ts +10 -0
  380. package/src/routes/api/knowledge.project-context.ts +18 -0
  381. package/src/routes/api/knowledge.search.ts +31 -0
  382. package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +16 -0
  383. package/src/routes/api/logs.$id.chunks.ts +36 -0
  384. package/src/routes/api/logs.$id.replay.ts +191 -0
  385. package/src/routes/api/logs.$id.ts +22 -0
  386. package/src/routes/api/logs.stream.ts +74 -0
  387. package/src/routes/api/logs.ts +59 -0
  388. package/src/routes/api/mcp.ts +25 -0
  389. package/src/routes/api/models.ts +10 -0
  390. package/src/routes/api/providers.$providerId.test.log.ts +293 -0
  391. package/src/routes/api/providers.$providerId.ts +50 -0
  392. package/src/routes/api/providers.export.ts +26 -0
  393. package/src/routes/api/providers.import.ts +47 -0
  394. package/src/routes/api/providers.scan.ts +23 -0
  395. package/src/routes/api/providers.ts +45 -0
  396. package/src/routes/api/sessions.ts +17 -0
  397. package/src/routes/index.tsx +6 -0
  398. package/src/routes/proxy/$.ts +15 -0
  399. package/src/routes/session/$sessionId.tsx +23 -0
  400. package/styles/globals.css +188 -0
@@ -0,0 +1,97 @@
1
+ import { useCallback, useMemo, useState, useTransition } from "react";
2
+
3
+ type JsonPrimitive = string | number | boolean | null;
4
+ export type JsonValue =
5
+ | JsonPrimitive
6
+ | ReadonlyArray<JsonValue>
7
+ | Readonly<{ [key: string]: JsonValue }>;
8
+
9
+ export type JsonExpansionPolicy = {
10
+ depth: number;
11
+ };
12
+
13
+ export function getJsonExpansionPolicy(_value: JsonValue): JsonExpansionPolicy {
14
+ return { depth: Number.POSITIVE_INFINITY };
15
+ }
16
+
17
+ export type JsonBulkExpansion = {
18
+ parsedData: JsonValue | null;
19
+ policy: JsonExpansionPolicy | null;
20
+ isExpanded: boolean;
21
+ toggle: () => void;
22
+ isPending: boolean;
23
+ bulkDepth: number;
24
+ bulkRevision: number;
25
+ };
26
+
27
+ type ParsedJsonText =
28
+ | {
29
+ kind: "json";
30
+ data: JsonValue;
31
+ }
32
+ | {
33
+ kind: "text";
34
+ };
35
+
36
+ export function parseJsonText(text: string): ParsedJsonText {
37
+ try {
38
+ const parsed: unknown = JSON.parse(text);
39
+ return { kind: "json", data: safeJsonValue(parsed) };
40
+ } catch {
41
+ return { kind: "text" };
42
+ }
43
+ }
44
+
45
+ export function useJsonBulkExpansion(text: string | null): JsonBulkExpansion {
46
+ const parsed = useMemo(() => (text === null ? null : parseJsonText(text)), [text]);
47
+ const parsedData = parsed?.kind === "json" ? parsed.data : null;
48
+ const policy = useMemo(
49
+ () => (parsedData === null ? null : getJsonExpansionPolicy(parsedData)),
50
+ [parsedData],
51
+ );
52
+ const [isExpanded, setIsExpanded] = useState(false);
53
+ const [bulkDepth, setBulkDepth] = useState(0);
54
+ const [bulkRevision, setBulkRevision] = useState(0);
55
+ const [isPending, startTransition] = useTransition();
56
+
57
+ const toggle = useCallback(() => {
58
+ const nextExpanded = !isExpanded;
59
+ const targetDepth = nextExpanded && policy !== null ? policy.depth : 0;
60
+ startTransition(() => {
61
+ setIsExpanded(nextExpanded);
62
+ setBulkDepth(targetDepth);
63
+ setBulkRevision((current) => current + 1);
64
+ });
65
+ }, [isExpanded, policy]);
66
+
67
+ return { parsedData, policy, isExpanded, toggle, isPending, bulkDepth, bulkRevision };
68
+ }
69
+
70
+ export function safeJsonValue(value: unknown): JsonValue {
71
+ if (value === null || value === undefined) return null;
72
+ switch (typeof value) {
73
+ case "string":
74
+ return value;
75
+ case "number":
76
+ return value;
77
+ case "boolean":
78
+ return value;
79
+ case "object": {
80
+ if (Array.isArray(value)) {
81
+ return value.map((item: unknown) => safeJsonValue(item));
82
+ }
83
+ const result: Record<string, JsonValue> = {};
84
+ for (const key of Object.keys(value)) {
85
+ const descriptor = Object.getOwnPropertyDescriptor(value, key);
86
+ result[key] = safeJsonValue(descriptor?.value);
87
+ }
88
+ return result;
89
+ }
90
+ case "bigint":
91
+ case "symbol":
92
+ case "function":
93
+ case "undefined":
94
+ return String(value);
95
+ }
96
+ return null;
97
+ }
@@ -0,0 +1,494 @@
1
+ import { Check, ChevronDown, ChevronRight, ChevronsDown, Copy } from "lucide-react";
2
+ import { type JSX, memo, useEffect, useMemo, useState } from "react";
3
+ import ReactMarkdown from "react-markdown";
4
+ import { cn } from "../../lib/utils";
5
+ import { Button } from "./button";
6
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./tooltip";
7
+ import type { JsonValue } from "./json-viewer-bulk";
8
+ import { parseJsonText, safeJsonValue } from "./json-viewer-bulk";
9
+
10
+ type DataType = "string" | "number" | "boolean" | "null" | "array" | "object";
11
+
12
+ function classifyValue(value: JsonValue): DataType {
13
+ if (value === null) return "null";
14
+ if (Array.isArray(value)) return "array";
15
+ switch (typeof value) {
16
+ case "string":
17
+ return "string";
18
+ case "number":
19
+ return "number";
20
+ case "boolean":
21
+ return "boolean";
22
+ case "object":
23
+ return "object";
24
+ case "bigint":
25
+ case "symbol":
26
+ case "undefined":
27
+ case "function":
28
+ return "object";
29
+ }
30
+ }
31
+
32
+ function isExpandable(value: JsonValue): boolean {
33
+ return value !== null && (Array.isArray(value) || typeof value === "object");
34
+ }
35
+
36
+ function getEntries(value: JsonValue): ReadonlyArray<readonly [string, JsonValue]> {
37
+ if (Array.isArray(value)) {
38
+ return value.map((item, index): readonly [string, JsonValue] => [String(index), item]);
39
+ }
40
+ if (typeof value === "object" && value !== null) {
41
+ return Object.entries(value);
42
+ }
43
+ return [];
44
+ }
45
+
46
+ const STRING_TRUNCATE_LIMIT = 120;
47
+
48
+ function StringValue({ text }: { text: string }): JSX.Element {
49
+ const [expanded, setExpanded] = useState(false);
50
+ const isLong = text.length > STRING_TRUNCATE_LIMIT;
51
+
52
+ if (!isLong) {
53
+ return (
54
+ <span className="text-emerald-400 break-all">
55
+ &quot;
56
+ <span className="prose prose-sm dark:prose-invert inline max-w-none [&_p]:inline [&_p]:my-0 [&_code]:text-emerald-300 [&_a]:text-emerald-300">
57
+ <ReactMarkdown>{text}</ReactMarkdown>
58
+ </span>
59
+ &quot;
60
+ </span>
61
+ );
62
+ }
63
+
64
+ return (
65
+ <span className="text-emerald-400 break-all">
66
+ &quot;
67
+ {expanded ? (
68
+ <span
69
+ className="cursor-pointer prose prose-sm dark:prose-invert inline max-w-none [&_p]:inline [&_p]:my-0 [&_code]:text-emerald-300 [&_a]:text-emerald-300"
70
+ onClick={(e) => {
71
+ e.stopPropagation();
72
+ setExpanded(false);
73
+ }}
74
+ onKeyDown={(e) => {
75
+ if (e.key === "Enter" || e.key === " ") {
76
+ e.stopPropagation();
77
+ setExpanded(false);
78
+ }
79
+ }}
80
+ role="button"
81
+ tabIndex={0}
82
+ >
83
+ <ReactMarkdown>{text}</ReactMarkdown>
84
+ </span>
85
+ ) : (
86
+ <Tooltip delayDuration={300}>
87
+ <TooltipTrigger
88
+ onClick={(e) => {
89
+ e.stopPropagation();
90
+ setExpanded(true);
91
+ }}
92
+ className="text-left cursor-pointer"
93
+ >
94
+ <span>{text.slice(0, STRING_TRUNCATE_LIMIT)}</span>
95
+ <span className="text-emerald-400/50">…</span>
96
+ </TooltipTrigger>
97
+ <TooltipContent
98
+ side="bottom"
99
+ className="max-w-md text-xs p-2 break-words whitespace-pre-wrap"
100
+ >
101
+ {text.slice(0, 500)}
102
+ {text.length > 500 ? "…" : ""}
103
+ </TooltipContent>
104
+ </Tooltip>
105
+ )}
106
+ &quot;
107
+ </span>
108
+ );
109
+ }
110
+
111
+ function PrimitiveValue({ value }: { value: JsonValue }): JSX.Element {
112
+ if (value === null) {
113
+ return <span className="text-rose-400 italic">null</span>;
114
+ }
115
+
116
+ switch (typeof value) {
117
+ case "string":
118
+ return <StringValue text={value} />;
119
+ case "number":
120
+ return <span className="text-amber-400">{value}</span>;
121
+ case "boolean":
122
+ return <span className="text-blue-400">{value ? "true" : "false"}</span>;
123
+ case "object":
124
+ case "bigint":
125
+ case "symbol":
126
+ case "undefined":
127
+ case "function":
128
+ return <span className="text-muted-foreground">{JSON.stringify(value)}</span>;
129
+ }
130
+ }
131
+
132
+ function CopyValueButton({ value }: { value: JsonValue }): JSX.Element {
133
+ const [copied, setCopied] = useState(false);
134
+
135
+ function handleCopy(e: React.MouseEvent): void {
136
+ e.stopPropagation();
137
+ void window.navigator.clipboard.writeText(JSON.stringify(value, null, 2)).then(() => {
138
+ setCopied(true);
139
+ setTimeout(() => {
140
+ setCopied(false);
141
+ }, 2000);
142
+ });
143
+ }
144
+
145
+ return (
146
+ <button
147
+ type="button"
148
+ onClick={handleCopy}
149
+ className="inline-flex items-center gap-1 text-[10px] text-muted-foreground hover:text-foreground transition-colors"
150
+ title="Copy JSON"
151
+ >
152
+ {copied ? <Check className="size-3 text-green-500" /> : <Copy className="size-3" />}
153
+ </button>
154
+ );
155
+ }
156
+
157
+ function CopyButton({ value }: { value: JsonValue }): JSX.Element {
158
+ const [copied, setCopied] = useState(false);
159
+
160
+ function handleCopy(e: React.MouseEvent): void {
161
+ e.stopPropagation();
162
+ void window.navigator.clipboard.writeText(JSON.stringify(value, null, 2)).then(() => {
163
+ setCopied(true);
164
+ setTimeout(() => {
165
+ setCopied(false);
166
+ }, 2000);
167
+ });
168
+ }
169
+
170
+ return (
171
+ <button
172
+ type="button"
173
+ onClick={handleCopy}
174
+ className="opacity-0 group-hover/row:opacity-100 hover:bg-muted p-0.5 rounded transition-opacity shrink-0"
175
+ title="Copy to clipboard"
176
+ >
177
+ {copied ? (
178
+ <Check className="size-3 text-green-500" />
179
+ ) : (
180
+ <Copy className="size-3 text-muted-foreground" />
181
+ )}
182
+ </button>
183
+ );
184
+ }
185
+
186
+ type JsonNodeProps = {
187
+ name: string;
188
+ value: JsonValue;
189
+ level: number;
190
+ defaultExpandDepth: number;
191
+ isArrayItem: boolean;
192
+ /** Full JSON-pointer-style path to this node (e.g. "/messages/3"). */
193
+ path: string;
194
+ /** When set, ancestors of this path auto-expand for one render. */
195
+ expandTargetPath: string | null;
196
+ /** Set of paths that should expose `data-anatomy-path` on their row. */
197
+ anatomyPaths: Set<string> | null;
198
+ };
199
+
200
+ function ExpandCollapseButton({
201
+ onClick,
202
+ }: {
203
+ onClick: (e: React.MouseEvent) => void;
204
+ }): JSX.Element {
205
+ return (
206
+ <button
207
+ type="button"
208
+ onClick={onClick}
209
+ className="opacity-0 group-hover/row:opacity-100 hover:bg-muted p-0.5 rounded transition-opacity shrink-0"
210
+ title="Expand all descendants"
211
+ >
212
+ <ChevronsDown className="size-3.5 text-muted-foreground" />
213
+ </button>
214
+ );
215
+ }
216
+
217
+ const JsonNode = memo(function JsonNode({
218
+ name,
219
+ value,
220
+ level,
221
+ defaultExpandDepth,
222
+ isArrayItem,
223
+ path,
224
+ expandTargetPath,
225
+ anatomyPaths,
226
+ }: JsonNodeProps): JSX.Element {
227
+ // A node is an ancestor of the target if the target starts with this
228
+ // node's path followed by a path separator. The root path is "" and
229
+ // is an ancestor of every non-empty path.
230
+ const isAncestorOfTarget = useMemo(() => {
231
+ if (expandTargetPath === null) return false;
232
+ if (path === "") return expandTargetPath.length > 0;
233
+ return expandTargetPath === path || expandTargetPath.startsWith(`${path}/`);
234
+ }, [expandTargetPath, path]);
235
+
236
+ const initialExpanded = level < defaultExpandDepth || (isAncestorOfTarget && isExpandable(value));
237
+
238
+ const [expanded, setExpanded] = useState(initialExpanded);
239
+ // Re-evaluate on every render so a freshly-changed expandTargetPath
240
+ // immediately auto-expands a previously-collapsed ancestor.
241
+ useEffect(() => {
242
+ if (isAncestorOfTarget && isExpandable(value) && !expanded) {
243
+ setExpanded(true);
244
+ }
245
+ // We deliberately only react to expandTargetPath changes here.
246
+ }, [expandTargetPath]);
247
+
248
+ const [childResetKey, setChildResetKey] = useState(0);
249
+ const [childDepthOverride, setChildDepthOverride] = useState<number | null>(null);
250
+ const expandable = isExpandable(value);
251
+ const fullyExpanded = childDepthOverride === Number.POSITIVE_INFINITY;
252
+ const entries = useMemo(() => getEntries(value), [value]);
253
+ const hasExpandableChild = useMemo(
254
+ () => entries.some(([, child]) => isExpandable(child)),
255
+ [entries],
256
+ );
257
+
258
+ const dataType = classifyValue(value);
259
+ const openBracket = dataType === "array" ? "[" : "{";
260
+ const closeBracket = dataType === "array" ? "]" : "}";
261
+
262
+ const hasAnatomyPath = anatomyPaths !== null && anatomyPaths.has(path);
263
+
264
+ function expandAllDeep(): void {
265
+ setExpanded(true);
266
+ setChildDepthOverride(Number.POSITIVE_INFINITY);
267
+ setChildResetKey((k) => k + 1);
268
+ }
269
+
270
+ function collapseToDefault(): void {
271
+ setExpanded(false);
272
+ setChildDepthOverride(0);
273
+ setChildResetKey((k) => k + 1);
274
+ }
275
+
276
+ function handleRowToggle(): void {
277
+ if (fullyExpanded) {
278
+ collapseToDefault();
279
+ } else {
280
+ setExpanded(!expanded);
281
+ }
282
+ }
283
+
284
+ function handleExpandAll(e: React.MouseEvent): void {
285
+ e.stopPropagation();
286
+ expandAllDeep();
287
+ }
288
+
289
+ const effectiveChildDepth = childDepthOverride ?? defaultExpandDepth;
290
+
291
+ return (
292
+ <div className={cn(level > 0 && "border-l border-border/50 ml-2")}>
293
+ <div
294
+ className={cn(
295
+ "flex items-start gap-1 py-0.5 px-1 -ml-1 rounded-sm group/row",
296
+ expandable && "cursor-pointer hover:bg-muted/50",
297
+ )}
298
+ data-anatomy-path={hasAnatomyPath ? path : undefined}
299
+ onClick={expandable ? handleRowToggle : undefined}
300
+ onKeyDown={
301
+ expandable
302
+ ? (e) => {
303
+ if (e.key === "Enter" || e.key === " ") {
304
+ e.preventDefault();
305
+ handleRowToggle();
306
+ }
307
+ }
308
+ : undefined
309
+ }
310
+ onDoubleClick={expandable && hasExpandableChild ? () => expandAllDeep() : undefined}
311
+ role={expandable ? "button" : undefined}
312
+ tabIndex={expandable ? 0 : undefined}
313
+ >
314
+ {expandable ? (
315
+ <span className="w-4 h-5 flex items-center justify-center shrink-0">
316
+ {expanded ? (
317
+ <ChevronDown className="size-3 text-muted-foreground" />
318
+ ) : (
319
+ <ChevronRight className="size-3 text-muted-foreground" />
320
+ )}
321
+ </span>
322
+ ) : (
323
+ <span className="w-4 shrink-0" />
324
+ )}
325
+
326
+ <span className={cn("shrink-0", isArrayItem ? "text-muted-foreground" : "text-cyan-400")}>
327
+ {isArrayItem ? name : `"${name}"`}
328
+ </span>
329
+
330
+ <span className="text-muted-foreground shrink-0">{expandable ? "" : ":"}</span>
331
+
332
+ {expandable ? (
333
+ <span className="text-muted-foreground">
334
+ {openBracket}
335
+ <span className="text-muted-foreground/60 text-xs">
336
+ {" "}
337
+ {entries.length} {entries.length === 1 ? "item" : "items"} {closeBracket}
338
+ </span>
339
+ </span>
340
+ ) : (
341
+ <span className="min-w-0">
342
+ <PrimitiveValue value={value} />
343
+ </span>
344
+ )}
345
+
346
+ {expandable && hasExpandableChild && !fullyExpanded && (
347
+ <ExpandCollapseButton onClick={handleExpandAll} />
348
+ )}
349
+ <CopyButton value={value} />
350
+ </div>
351
+
352
+ {expandable && expanded && (
353
+ <div className="pl-4" key={childResetKey}>
354
+ {entries.map(([key, childValue]) => (
355
+ <JsonNode
356
+ key={key}
357
+ name={key}
358
+ value={childValue}
359
+ level={level + 1}
360
+ defaultExpandDepth={effectiveChildDepth}
361
+ isArrayItem={dataType === "array"}
362
+ path={path === "" ? `/${key}` : `${path}/${key}`}
363
+ expandTargetPath={expandTargetPath}
364
+ anatomyPaths={anatomyPaths}
365
+ />
366
+ ))}
367
+ <div className="text-muted-foreground py-0.5 px-1">{closeBracket}</div>
368
+ </div>
369
+ )}
370
+ </div>
371
+ );
372
+ });
373
+
374
+ export type JsonViewerProps = {
375
+ data: JsonValue;
376
+ defaultExpandDepth?: number;
377
+ className?: string;
378
+ showCopy?: boolean;
379
+ bulkDepth?: number;
380
+ bulkRevision?: number;
381
+ /**
382
+ * Set of JSON-pointer-style paths whose row should expose a
383
+ * `data-anatomy-path` attribute. Used by the Anatomy view to
384
+ * locate rows for click-to-jump. When `null` or `undefined`,
385
+ * no `data-anatomy-path` attribute is emitted (zero cost).
386
+ */
387
+ anatomyPaths?: Set<string> | null;
388
+ /**
389
+ * When set, every ancestor of this path in the tree auto-expands
390
+ * for one render so the target row becomes visible. The hook
391
+ * flips this back to `null` after the scroll lands.
392
+ */
393
+ expandToPath?: string | null;
394
+ };
395
+
396
+ export function JsonViewer({
397
+ data,
398
+ defaultExpandDepth = 0,
399
+ className,
400
+ showCopy = false,
401
+ bulkDepth: controlledBulkDepth,
402
+ bulkRevision: controlledBulkRevision,
403
+ anatomyPaths = null,
404
+ expandToPath = null,
405
+ }: JsonViewerProps): JSX.Element {
406
+ const expandable = isExpandable(data);
407
+ const entries = useMemo(() => getEntries(data), [data]);
408
+
409
+ const bulkDepth = controlledBulkDepth ?? defaultExpandDepth;
410
+ const bulkRevision = controlledBulkRevision ?? 0;
411
+
412
+ if (!expandable) {
413
+ return (
414
+ <TooltipProvider>
415
+ <div className={cn("font-mono text-xs leading-relaxed", className)}>
416
+ <div className="flex items-center gap-1">
417
+ <PrimitiveValue value={data} />
418
+ {showCopy && <CopyValueButton value={data} />}
419
+ </div>
420
+ </div>
421
+ </TooltipProvider>
422
+ );
423
+ }
424
+
425
+ const dataType = classifyValue(data);
426
+ const isArray = dataType === "array";
427
+
428
+ return (
429
+ <TooltipProvider>
430
+ <div className={cn("font-mono text-xs leading-relaxed", className)}>
431
+ {showCopy && (
432
+ <div className="mb-2 flex items-center justify-end gap-2">
433
+ <CopyValueButton value={data} />
434
+ </div>
435
+ )}
436
+ <div key={bulkRevision}>
437
+ {entries.map(([key, childValue]) => (
438
+ <JsonNode
439
+ key={key}
440
+ name={key}
441
+ value={childValue}
442
+ level={0}
443
+ defaultExpandDepth={bulkDepth}
444
+ isArrayItem={isArray}
445
+ path={`/${key}`}
446
+ expandTargetPath={expandToPath}
447
+ anatomyPaths={anatomyPaths}
448
+ />
449
+ ))}
450
+ </div>
451
+ </div>
452
+ </TooltipProvider>
453
+ );
454
+ }
455
+
456
+ export type JsonViewerFromStringProps = {
457
+ text: string;
458
+ defaultExpandDepth?: number;
459
+ className?: string;
460
+ /**
461
+ * Forwarded to the inner `JsonViewer` so that a parent bulk-expansion
462
+ * controller (e.g. the header's Expand-all button) can expand/collapse
463
+ * all nodes. `JsonViewer` falls back to `defaultExpandDepth` when both
464
+ * are unset.
465
+ */
466
+ bulkDepth?: number;
467
+ bulkRevision?: number;
468
+ };
469
+
470
+ export const JsonViewerFromString = memo(function JsonViewerFromString({
471
+ text,
472
+ defaultExpandDepth = 0,
473
+ className,
474
+ bulkDepth,
475
+ bulkRevision,
476
+ }: JsonViewerFromStringProps): JSX.Element {
477
+ const parsed = useMemo(() => parseJsonText(text), [text]);
478
+
479
+ if (parsed.kind === "json") {
480
+ return (
481
+ <JsonViewer
482
+ data={parsed.data}
483
+ defaultExpandDepth={defaultExpandDepth}
484
+ className={className}
485
+ bulkDepth={bulkDepth}
486
+ bulkRevision={bulkRevision}
487
+ />
488
+ );
489
+ }
490
+
491
+ return (
492
+ <pre className={cn("font-mono text-xs whitespace-pre-wrap break-words", className)}>{text}</pre>
493
+ );
494
+ });
@@ -0,0 +1,20 @@
1
+ import type { JSX } from "react";
2
+ import { cn } from "../../lib/utils";
3
+ import McpLogoPng from "../../assets/logos/mcp.png";
4
+
5
+ /**
6
+ * Official Model Context Protocol logo (from Wikimedia Commons). The PNG
7
+ * is a black-on-white raster of the official mark — flipped to a white
8
+ * silhouette on the dark header via `invert` so it reads against the
9
+ * app background.
10
+ */
11
+ export function McpLogo({ className }: { className?: string }): JSX.Element {
12
+ return (
13
+ <img
14
+ src={McpLogoPng}
15
+ alt="Model Context Protocol"
16
+ aria-hidden="true"
17
+ className={cn("inline-block size-8 object-contain invert", className)}
18
+ />
19
+ );
20
+ }
@@ -0,0 +1,54 @@
1
+ import { ScrollArea as ScrollAreaPrimitive } from "radix-ui";
2
+ import * as React from "react";
3
+
4
+ import { cn } from "../../lib/utils";
5
+
6
+ function ScrollArea({
7
+ className,
8
+ children,
9
+ ...props
10
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.Root>): React.JSX.Element {
11
+ return (
12
+ <ScrollAreaPrimitive.Root
13
+ data-slot="scroll-area"
14
+ className={cn("relative", className)}
15
+ {...props}
16
+ >
17
+ <ScrollAreaPrimitive.Viewport
18
+ data-slot="scroll-area-viewport"
19
+ className="focus-visible:ring-ring/50 size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:outline-1"
20
+ >
21
+ {children}
22
+ </ScrollAreaPrimitive.Viewport>
23
+ <ScrollBar />
24
+ <ScrollAreaPrimitive.Corner />
25
+ </ScrollAreaPrimitive.Root>
26
+ );
27
+ }
28
+
29
+ function ScrollBar({
30
+ className,
31
+ orientation = "vertical",
32
+ ...props
33
+ }: React.ComponentProps<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>): React.JSX.Element {
34
+ return (
35
+ <ScrollAreaPrimitive.ScrollAreaScrollbar
36
+ data-slot="scroll-area-scrollbar"
37
+ orientation={orientation}
38
+ className={cn(
39
+ "flex touch-none p-px transition-colors select-none",
40
+ orientation === "vertical" && "h-full w-2.5 border-l border-l-transparent",
41
+ orientation === "horizontal" && "h-2.5 flex-col border-t border-t-transparent",
42
+ className,
43
+ )}
44
+ {...props}
45
+ >
46
+ <ScrollAreaPrimitive.ScrollAreaThumb
47
+ data-slot="scroll-area-thumb"
48
+ className="bg-border relative flex-1 rounded-full"
49
+ />
50
+ </ScrollAreaPrimitive.ScrollAreaScrollbar>
51
+ );
52
+ }
53
+
54
+ export { ScrollArea, ScrollBar };