@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,59 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { z } from "zod";
3
+ import { clearAllLogs, clearLogsByIds, getFilteredLogs } from "../../proxy/store";
4
+
5
+ const DeleteBodySchema = z
6
+ .object({
7
+ ids: z.array(z.number().int().positive()).optional(),
8
+ })
9
+ .optional();
10
+
11
+ export const Route = createFileRoute("/api/logs")({
12
+ server: {
13
+ handlers: {
14
+ GET: ({ request }: { request: Request }) => {
15
+ const url = new URL(request.url);
16
+ const sessionId = url.searchParams.get("sessionId") ?? undefined;
17
+ const model = url.searchParams.get("model") ?? undefined;
18
+ const offset = Number(url.searchParams.get("offset") ?? 0);
19
+ const limit = Number(url.searchParams.get("limit") ?? 50);
20
+
21
+ const allLogs = getFilteredLogs(sessionId, model);
22
+ const paginatedLogs = allLogs.slice(offset, offset + limit);
23
+
24
+ return Response.json({
25
+ logs: paginatedLogs,
26
+ total: allLogs.length,
27
+ offset,
28
+ limit,
29
+ });
30
+ },
31
+ DELETE: async ({ request }: { request: Request }) => {
32
+ let body: z.infer<typeof DeleteBodySchema> = undefined;
33
+ try {
34
+ const raw = await request.text();
35
+ if (raw !== "") {
36
+ const parsed: unknown = JSON.parse(raw);
37
+ const result = DeleteBodySchema.safeParse(parsed);
38
+ if (!result.success) {
39
+ return Response.json(
40
+ { error: "Invalid request body", details: result.error.format() },
41
+ { status: 400 },
42
+ );
43
+ }
44
+ body = result.data;
45
+ }
46
+ } catch {
47
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
48
+ }
49
+
50
+ if (body?.ids !== undefined && body.ids.length > 0) {
51
+ const result = clearLogsByIds(body.ids);
52
+ return Response.json({ success: true, cleared: result.cleared });
53
+ }
54
+ const result = clearAllLogs();
55
+ return Response.json({ success: true, cleared: result.cleared });
56
+ },
57
+ },
58
+ },
59
+ });
@@ -0,0 +1,25 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { handleMcpRequest } from "../../mcp/server";
3
+
4
+ /**
5
+ * MCP HTTP Streamable transport endpoint. Mounted at `POST /api/mcp` on the
6
+ * existing TanStack Start HTTP server — see
7
+ * `openspec/changes/add-mcp-server/design.md` D1.
8
+ *
9
+ * All method/header routing is handled inside the SDK's
10
+ * `WebStandardStreamableHTTPServerTransport` (it dispatches GET for SSE
11
+ * stream, POST for client→server requests, DELETE for session close), so
12
+ * the route simply forwards the request.
13
+ */
14
+ export const Route = createFileRoute("/api/mcp")({
15
+ server: {
16
+ handlers: {
17
+ // The SDK may issue either POST, GET, or DELETE. TanStack Start only
18
+ // requires us to declare the methods we accept; routing by method is
19
+ // handled inside the transport.
20
+ POST: ({ request }: { request: Request }) => handleMcpRequest(request),
21
+ GET: ({ request }: { request: Request }) => handleMcpRequest(request),
22
+ DELETE: ({ request }: { request: Request }) => handleMcpRequest(request),
23
+ },
24
+ },
25
+ });
@@ -0,0 +1,10 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { getModels } from "../../proxy/store";
3
+
4
+ export const Route = createFileRoute("/api/models")({
5
+ server: {
6
+ handlers: {
7
+ GET: () => Response.json(getModels()),
8
+ },
9
+ },
10
+ });
@@ -0,0 +1,293 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { getProvider, getModelUsageName } from "../../proxy/providers";
3
+ import { appendLogEntry } from "../../proxy/logger";
4
+ import { addTestLogEntry } from "../../proxy/store";
5
+ import {
6
+ ProviderTestResultsSchema,
7
+ type ProviderTestResult as TestResult,
8
+ type ProviderTestState,
9
+ } from "../../lib/providerTestContract";
10
+
11
+ function hasSuccessField(result: ProviderTestState): result is TestResult {
12
+ return Object.prototype.hasOwnProperty.call(result, "success");
13
+ }
14
+
15
+ function createTestLogEntry(
16
+ providerName: string,
17
+ path: string,
18
+ body: string,
19
+ upstreamUrl: string,
20
+ result: TestResult,
21
+ isTest: boolean,
22
+ ): Record<string, unknown> {
23
+ return {
24
+ timestamp: new Date().toISOString(),
25
+ id: `test-${Date.now()}`,
26
+ method: "POST",
27
+ path,
28
+ model: isTest ? result.model : undefined,
29
+ sessionId: null,
30
+ rawRequestBody: body,
31
+ responseStatus: result.success ? 200 : 500,
32
+ responseText: result.rawResponse ?? JSON.stringify(result),
33
+ inputTokens: result.inputTokens ?? null,
34
+ outputTokens: result.outputTokens ?? null,
35
+ elapsedMs: result.latencyMs ?? 0,
36
+ streaming: result.streaming ?? false,
37
+ userAgent: "provider-test",
38
+ origin: null,
39
+ upstreamUrl,
40
+ error: result.success ? null : (result.error?.message ?? String(result.error)),
41
+ isTest: true,
42
+ providerName,
43
+ headers: result.requestHeaders ?? {},
44
+ };
45
+ }
46
+
47
+ async function logModelResults(
48
+ displayName: string,
49
+ providerName: string,
50
+ anthropicUrl: string | undefined,
51
+ openaiUrl: string | undefined,
52
+ modelResults: {
53
+ anthropic: { nonStreaming: ProviderTestState; streaming: ProviderTestState };
54
+ openai: { nonStreaming: ProviderTestState; streaming: ProviderTestState };
55
+ },
56
+ ): Promise<void> {
57
+ const usageModel = getModelUsageName(displayName, providerName);
58
+
59
+ if (anthropicUrl !== undefined) {
60
+ const nsResult = modelResults.anthropic.nonStreaming;
61
+ const sResult = modelResults.anthropic.streaming;
62
+ if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
63
+ const nonStreamingResult = nsResult;
64
+ const streamingResult = sResult;
65
+
66
+ const requestBody = JSON.stringify({
67
+ model: usageModel,
68
+ messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
69
+ max_tokens: 1024,
70
+ });
71
+ const upstreamUrl = `${anthropicUrl}/v1/messages`;
72
+
73
+ await addTestLogEntry({
74
+ timestamp: new Date().toISOString(),
75
+ method: "POST",
76
+ path: "/v1/messages",
77
+ model: nonStreamingResult.model ?? displayName,
78
+ sessionId: null,
79
+ rawRequestBody: requestBody,
80
+ responseStatus: nonStreamingResult.success ? 200 : 500,
81
+ responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
82
+ inputTokens: nonStreamingResult.inputTokens ?? null,
83
+ outputTokens: nonStreamingResult.outputTokens ?? null,
84
+ cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
85
+ cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
86
+ elapsedMs: nonStreamingResult.latencyMs ?? 0,
87
+ streaming: false,
88
+ userAgent: "provider-test",
89
+ origin: null,
90
+ apiFormat: "anthropic",
91
+ isTest: true,
92
+ providerName,
93
+ headers: nonStreamingResult.requestHeaders ?? {},
94
+ });
95
+
96
+ appendLogEntry(
97
+ createTestLogEntry(
98
+ providerName,
99
+ "/v1/messages",
100
+ requestBody,
101
+ upstreamUrl,
102
+ nonStreamingResult,
103
+ true,
104
+ ),
105
+ );
106
+
107
+ const streamingRequestBody = JSON.stringify({
108
+ model: usageModel,
109
+ messages: [{ role: "user", content: "say hello" }],
110
+ max_tokens: 256,
111
+ stream: true,
112
+ });
113
+
114
+ await addTestLogEntry({
115
+ timestamp: new Date().toISOString(),
116
+ method: "POST",
117
+ path: "/v1/messages",
118
+ model: streamingResult.model ?? displayName,
119
+ sessionId: null,
120
+ rawRequestBody: streamingRequestBody,
121
+ responseStatus: streamingResult.success ? 200 : 500,
122
+ responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
123
+ inputTokens: streamingResult.inputTokens ?? null,
124
+ outputTokens: streamingResult.outputTokens ?? null,
125
+ cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
126
+ cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
127
+ elapsedMs: streamingResult.latencyMs ?? 0,
128
+ streaming: true,
129
+ streamingChunks: streamingResult.streamingChunks,
130
+ userAgent: "provider-test",
131
+ origin: null,
132
+ apiFormat: "anthropic",
133
+ isTest: true,
134
+ providerName,
135
+ headers: streamingResult.requestHeaders ?? {},
136
+ });
137
+
138
+ appendLogEntry(
139
+ createTestLogEntry(
140
+ providerName,
141
+ "/v1/messages",
142
+ streamingRequestBody,
143
+ upstreamUrl,
144
+ streamingResult,
145
+ true,
146
+ ),
147
+ );
148
+ }
149
+ }
150
+
151
+ if (openaiUrl !== undefined) {
152
+ const nsResult = modelResults.openai.nonStreaming;
153
+ const sResult = modelResults.openai.streaming;
154
+ if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
155
+ const nonStreamingResult = nsResult;
156
+ const streamingResult = sResult;
157
+
158
+ const requestBody = JSON.stringify({
159
+ model: usageModel,
160
+ messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
161
+ max_tokens: 1024,
162
+ });
163
+ const upstreamUrl = `${openaiUrl}/v1/chat/completions`;
164
+
165
+ await addTestLogEntry({
166
+ timestamp: new Date().toISOString(),
167
+ method: "POST",
168
+ path: "/v1/chat/completions",
169
+ model: nonStreamingResult.model ?? displayName,
170
+ sessionId: null,
171
+ rawRequestBody: requestBody,
172
+ responseStatus: nonStreamingResult.success ? 200 : 500,
173
+ responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
174
+ inputTokens: nonStreamingResult.inputTokens ?? null,
175
+ outputTokens: nonStreamingResult.outputTokens ?? null,
176
+ cacheCreationInputTokens: null,
177
+ cacheReadInputTokens: null,
178
+ elapsedMs: nonStreamingResult.latencyMs ?? 0,
179
+ streaming: false,
180
+ userAgent: "provider-test",
181
+ origin: null,
182
+ apiFormat: "openai",
183
+ isTest: true,
184
+ providerName,
185
+ headers: nonStreamingResult.requestHeaders ?? {},
186
+ });
187
+
188
+ appendLogEntry(
189
+ createTestLogEntry(
190
+ providerName,
191
+ "/v1/chat/completions",
192
+ requestBody,
193
+ upstreamUrl,
194
+ nonStreamingResult,
195
+ true,
196
+ ),
197
+ );
198
+
199
+ const streamingRequestBody = JSON.stringify({
200
+ model: usageModel,
201
+ messages: [{ role: "user", content: "say hello" }],
202
+ max_tokens: 256,
203
+ stream: true,
204
+ });
205
+
206
+ await addTestLogEntry({
207
+ timestamp: new Date().toISOString(),
208
+ method: "POST",
209
+ path: "/v1/chat/completions",
210
+ model: streamingResult.model ?? displayName,
211
+ sessionId: null,
212
+ rawRequestBody: streamingRequestBody,
213
+ responseStatus: streamingResult.success ? 200 : 500,
214
+ responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
215
+ inputTokens: streamingResult.inputTokens ?? null,
216
+ outputTokens: streamingResult.outputTokens ?? null,
217
+ cacheCreationInputTokens: null,
218
+ cacheReadInputTokens: null,
219
+ elapsedMs: streamingResult.latencyMs ?? 0,
220
+ streaming: true,
221
+ streamingChunks: streamingResult.streamingChunks,
222
+ userAgent: "provider-test",
223
+ origin: null,
224
+ apiFormat: "openai",
225
+ isTest: true,
226
+ providerName,
227
+ headers: streamingResult.requestHeaders ?? {},
228
+ });
229
+
230
+ appendLogEntry(
231
+ createTestLogEntry(
232
+ providerName,
233
+ "/v1/chat/completions",
234
+ streamingRequestBody,
235
+ upstreamUrl,
236
+ streamingResult,
237
+ true,
238
+ ),
239
+ );
240
+ }
241
+ }
242
+ }
243
+
244
+ export const Route = createFileRoute("/api/providers/$providerId/test/log")({
245
+ server: {
246
+ handlers: {
247
+ POST: async ({ params, request }: { params: { providerId: string }; request: Request }) => {
248
+ const provider = getProvider(params.providerId);
249
+ if (!provider) {
250
+ return Response.json({ error: "Provider not found" }, { status: 404 });
251
+ }
252
+
253
+ let body: unknown;
254
+ try {
255
+ body = await request.json();
256
+ } catch {
257
+ return Response.json({ error: "Invalid JSON body" }, { status: 400 });
258
+ }
259
+
260
+ const parsed = ProviderTestResultsSchema.safeParse(body);
261
+ if (!parsed.success) {
262
+ return Response.json(
263
+ { error: `Invalid test results: ${parsed.error.message}` },
264
+ { status: 400 },
265
+ );
266
+ }
267
+
268
+ const results = parsed.data;
269
+ const anthropicUrl =
270
+ provider.anthropicBaseUrl !== undefined && provider.anthropicBaseUrl.length > 0
271
+ ? provider.anthropicBaseUrl
272
+ : undefined;
273
+ const openaiUrl =
274
+ provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl.length > 0
275
+ ? provider.openaiBaseUrl
276
+ : undefined;
277
+
278
+ const entries: Promise<void>[] = [];
279
+ if (results.models !== undefined) {
280
+ for (const [modelName, modelResult] of Object.entries(results.models)) {
281
+ entries.push(
282
+ logModelResults(modelName, provider.name, anthropicUrl, openaiUrl, modelResult),
283
+ );
284
+ }
285
+ }
286
+
287
+ await Promise.all(entries);
288
+
289
+ return Response.json({ logged: entries.length });
290
+ },
291
+ },
292
+ },
293
+ });
@@ -0,0 +1,50 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { z } from "zod";
3
+ import { getProviders, updateProvider, deleteProvider } from "../../proxy/providers";
4
+
5
+ const ProviderUpdateSchema = z.object({
6
+ name: z.string().min(1, "Name is required").optional(),
7
+ apiKey: z.string().min(1, "API key is required").optional(),
8
+ format: z.enum(["anthropic", "openai"]).optional(),
9
+ baseUrl: z.string().min(1, "Base URL is required").optional(),
10
+ model: z.string().optional(),
11
+ models: z.array(z.string()).optional(),
12
+ authHeader: z.enum(["bearer", "x-api-key"]).optional(),
13
+ anthropicBaseUrl: z.string().optional(),
14
+ openaiBaseUrl: z.string().optional(),
15
+ apiDocsUrl: z.string().optional(),
16
+ source: z.enum(["company", "personal"]).optional(),
17
+ });
18
+
19
+ export const Route = createFileRoute("/api/providers/$providerId")({
20
+ server: {
21
+ handlers: {
22
+ GET: ({ params }: { params: { providerId: string } }) => {
23
+ const providers = getProviders();
24
+ const provider = providers.find((p) => p.id === params.providerId);
25
+ if (!provider) {
26
+ return Response.json({ error: "Provider not found" }, { status: 404 });
27
+ }
28
+ return Response.json(provider);
29
+ },
30
+ PUT: async ({ params, request }: { params: { providerId: string }; request: Request }) => {
31
+ const parsed = ProviderUpdateSchema.safeParse(await request.json());
32
+ if (!parsed.success) {
33
+ return Response.json({ error: parsed.error.message }, { status: 400 });
34
+ }
35
+ const updated = updateProvider(params.providerId, parsed.data);
36
+ if (!updated) {
37
+ return Response.json({ error: "Provider not found" }, { status: 404 });
38
+ }
39
+ return Response.json(updated);
40
+ },
41
+ DELETE: ({ params }: { params: { providerId: string } }) => {
42
+ const deleted = deleteProvider(params.providerId);
43
+ if (!deleted) {
44
+ return Response.json({ error: "Provider not found" }, { status: 404 });
45
+ }
46
+ return Response.json({ success: true });
47
+ },
48
+ },
49
+ },
50
+ });
@@ -0,0 +1,26 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { exportProviders, exportProvidersWithKeys } from "../../proxy/providers";
3
+
4
+ export const Route = createFileRoute("/api/providers/export")({
5
+ server: {
6
+ handlers: {
7
+ GET: ({ request }: { request: Request }) => {
8
+ const url = new URL(request.url);
9
+ const includeKeys = url.searchParams.get("includeKeys") === "true";
10
+
11
+ const json = includeKeys ? exportProvidersWithKeys() : exportProviders();
12
+
13
+ const filename = includeKeys
14
+ ? `agent-inspector-providers-${Date.now()}.json`
15
+ : `agent-inspector-providers-safe-${Date.now()}.json`;
16
+
17
+ return new Response(json, {
18
+ headers: {
19
+ "Content-Type": "application/json",
20
+ "Content-Disposition": `attachment; filename="${filename}"`,
21
+ },
22
+ });
23
+ },
24
+ },
25
+ },
26
+ });
@@ -0,0 +1,47 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { z } from "zod";
3
+ import { importProviders } from "../../proxy/providers";
4
+
5
+ const ImportRequestSchema = z.union([z.string(), z.object({ providers: z.unknown() })]);
6
+
7
+ export const Route = createFileRoute("/api/providers/import")({
8
+ server: {
9
+ handlers: {
10
+ POST: async ({ request }: { request: Request }) => {
11
+ try {
12
+ const rawBody = await request.text();
13
+ let jsonContent: string;
14
+ try {
15
+ const parsedBody: unknown = JSON.parse(rawBody);
16
+ jsonContent = typeof parsedBody === "string" ? parsedBody : JSON.stringify(parsedBody);
17
+ } catch {
18
+ jsonContent = rawBody;
19
+ }
20
+
21
+ if (!jsonContent || jsonContent.trim() === "") {
22
+ return Response.json({ error: "No JSON content provided" }, { status: 400 });
23
+ }
24
+
25
+ const result = importProviders(jsonContent);
26
+
27
+ return Response.json({
28
+ success: result.imported > 0,
29
+ imported: result.imported,
30
+ errors: result.errors,
31
+ message:
32
+ result.imported > 0
33
+ ? `Successfully imported ${result.imported} provider(s)`
34
+ : result.errors.length > 0
35
+ ? `Import completed with ${result.errors.length} error(s)`
36
+ : "No providers imported",
37
+ });
38
+ } catch (err) {
39
+ return Response.json(
40
+ { error: `Failed to import: ${err instanceof Error ? err.message : String(err)}` },
41
+ { status: 400 },
42
+ );
43
+ }
44
+ },
45
+ },
46
+ },
47
+ });
@@ -0,0 +1,23 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { scanExternalProviders } from "../../proxy/providerImporters";
3
+
4
+ export const Route = createFileRoute("/api/providers/scan")({
5
+ server: {
6
+ handlers: {
7
+ GET: () => {
8
+ try {
9
+ const result = scanExternalProviders();
10
+ return Response.json({
11
+ providers: result.providers,
12
+ warnings: result.warnings,
13
+ });
14
+ } catch (err) {
15
+ return Response.json(
16
+ { error: `Scan failed: ${err instanceof Error ? err.message : String(err)}` },
17
+ { status: 500 },
18
+ );
19
+ }
20
+ },
21
+ },
22
+ },
23
+ });
@@ -0,0 +1,45 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { z } from "zod";
3
+ import { getProviders, addProvider } from "../../proxy/providers";
4
+
5
+ const ProviderInputSchema = z.object({
6
+ name: z.string().min(1, "Name is required"),
7
+ apiKey: z.string().min(1, "API key is required"),
8
+ format: z.enum(["anthropic", "openai"]).optional(),
9
+ anthropicBaseUrl: z.string().optional(),
10
+ openaiBaseUrl: z.string().optional(),
11
+ models: z.array(z.string()).min(1, "At least one model is required"),
12
+ model: z.string().optional(),
13
+ authHeader: z.enum(["bearer", "x-api-key"]).optional().default("bearer"),
14
+ apiDocsUrl: z.string().optional(),
15
+ source: z.enum(["company", "personal"]).optional(),
16
+ });
17
+
18
+ export const Route = createFileRoute("/api/providers")({
19
+ server: {
20
+ handlers: {
21
+ GET: () => {
22
+ return Response.json(getProviders());
23
+ },
24
+ POST: async ({ request }: { request: Request }) => {
25
+ const parsed = ProviderInputSchema.safeParse(await request.json());
26
+ if (!parsed.success) {
27
+ return Response.json({ error: parsed.error.message }, { status: 400 });
28
+ }
29
+ const newProvider = addProvider(
30
+ parsed.data.name,
31
+ parsed.data.apiKey,
32
+ parsed.data.format,
33
+ undefined, // baseUrl (legacy) — use format-specific URLs instead
34
+ parsed.data.models,
35
+ parsed.data.authHeader,
36
+ parsed.data.apiDocsUrl,
37
+ parsed.data.anthropicBaseUrl,
38
+ parsed.data.openaiBaseUrl,
39
+ parsed.data.source,
40
+ );
41
+ return Response.json(newProvider, { status: 201 });
42
+ },
43
+ },
44
+ },
45
+ });
@@ -0,0 +1,17 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { getSessionSnapshots, getSessions } from "../../proxy/store";
3
+
4
+ export const Route = createFileRoute("/api/sessions")({
5
+ server: {
6
+ handlers: {
7
+ GET: ({ request }: { request: Request }) => {
8
+ const url = new URL(request.url);
9
+ const details = url.searchParams.get("details");
10
+ if (details === "true" || details === "1") {
11
+ return Response.json(getSessionSnapshots());
12
+ }
13
+ return Response.json(getSessions());
14
+ },
15
+ },
16
+ },
17
+ });
@@ -0,0 +1,6 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { ProxyViewerContainer } from "../components/ProxyViewerContainer";
3
+
4
+ export const Route = createFileRoute("/")({
5
+ component: ProxyViewerContainer,
6
+ });
@@ -0,0 +1,15 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { handleProxy } from "../../proxy/handler";
3
+
4
+ export const Route = createFileRoute("/proxy/$")({
5
+ server: {
6
+ handlers: {
7
+ GET: ({ request }: { request: Request }) => handleProxy(request),
8
+ POST: ({ request }: { request: Request }) => handleProxy(request),
9
+ PUT: ({ request }: { request: Request }) => handleProxy(request),
10
+ DELETE: ({ request }: { request: Request }) => handleProxy(request),
11
+ PATCH: ({ request }: { request: Request }) => handleProxy(request),
12
+ OPTIONS: ({ request }: { request: Request }) => handleProxy(request),
13
+ },
14
+ },
15
+ });
@@ -0,0 +1,23 @@
1
+ import { createFileRoute } from "@tanstack/react-router";
2
+ import { ProxyViewerContainer } from "../../components/ProxyViewerContainer";
3
+ import { decodeSessionIdFromPath, encodeSessionIdForPath } from "../../lib/sessionUrl";
4
+
5
+ /**
6
+ * Per-session deep link: opens a page that is pre-scoped to a single
7
+ * session id. The path segment is base64url-encoded so JSON session blobs
8
+ * and Unicode project paths survive dev-server URL normalization.
9
+ */
10
+ export const Route = createFileRoute("/session/$sessionId")({
11
+ component: SessionViewerRoute,
12
+ parseParams: (params) => ({
13
+ sessionId: decodeSessionIdFromPath(params.sessionId),
14
+ }),
15
+ stringifyParams: (params) => ({
16
+ sessionId: encodeSessionIdForPath(params.sessionId),
17
+ }),
18
+ });
19
+
20
+ function SessionViewerRoute(): React.JSX.Element {
21
+ const { sessionId } = Route.useParams();
22
+ return <ProxyViewerContainer key={sessionId} initialSessionId={sessionId} />;
23
+ }