@tonyclaw/agent-inspector 3.0.44 → 3.0.46

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 (347) hide show
  1. package/.output/{nitro.json → backend/nitro.json} +3 -3
  2. package/.output/backend-public/assets/index-D4LX-sw-.js +11 -0
  3. package/.output/cli.js +22707 -17099
  4. package/.output/server/_libs/extend.mjs +4 -8
  5. package/.output/server/_libs/jszip.mjs +9 -35
  6. package/.output/server/_libs/modelcontextprotocol__core.mjs +25 -25
  7. package/.output/server/_libs/modelcontextprotocol__server.mjs +2 -2
  8. package/.output/server/_libs/react-dom.mjs +2 -3
  9. package/.output/server/_libs/react.mjs +1 -27
  10. package/.output/server/_libs/tanstack__react-router.mjs +1 -329
  11. package/.output/server/_libs/tanstack__router-core.mjs +42 -100
  12. package/.output/server/_libs/use-sync-external-store.mjs +1 -64
  13. package/.output/server/_libs/ws.mjs +1 -1
  14. package/.output/server/_libs/zod.mjs +6 -6
  15. package/.output/server/_ssr/index.mjs +5 -4
  16. package/.output/server/_ssr/publicBasePathContext-IH2ilOfu.mjs +176 -0
  17. package/.output/server/_ssr/{router-DWcUFPR3.mjs → router-D18yUq36.mjs} +7877 -5597
  18. package/.output/server/_ssr/start-COQu_AgD.mjs +57 -0
  19. package/.output/server/_tanstack-start-manifest_v-DnbdNeun.mjs +4 -0
  20. package/.output/server/index.mjs +5 -145
  21. package/.output/{public/assets/CompareDrawer-DQHjxFO6.js → ui/assets/CompareDrawer-DAUuIJ6G.js} +1 -1
  22. package/.output/{public/assets/InspectorPet-D1A4505B.js → ui/assets/InspectorPet-BRBVjOWI.js} +1 -1
  23. package/.output/ui/assets/ProxyViewerContainer-D7Sq0ctc.js +59 -0
  24. package/.output/{public/assets/ReplayDialog-C5vmbecv.js → ui/assets/ReplayDialog-nDLsjOhs.js} +1 -1
  25. package/.output/{public/assets/RequestAnatomy-CPGNB8lk.js → ui/assets/RequestAnatomy-zd4BDgL0.js} +1 -1
  26. package/.output/ui/assets/ResponseView-AdIXGcSn.js +2 -0
  27. package/.output/ui/assets/StreamingChunkSequence-CesTz8He.js +1 -0
  28. package/.output/{public/assets/_sessionId-CDhRgzf6.js → ui/assets/_sessionId-BAfzrhSU.js} +1 -1
  29. package/.output/{public/assets/_sessionId-mw3aA8Bp.js → ui/assets/_sessionId-QnBomgPD.js} +1 -1
  30. package/.output/ui/assets/favicon-DYEkHSNl.svg +21 -0
  31. package/.output/{public/assets/index-B2eoeT-Z.js → ui/assets/index-BcsdxBAd.js} +1 -1
  32. package/.output/ui/assets/index-BvXp42al.css +1 -0
  33. package/.output/{public/assets/index-CX7_rf7o.js → ui/assets/index-D0rtCN9V.js} +1 -1
  34. package/.output/ui/assets/index-DHpwr08Z.js +73 -0
  35. package/.output/{public/assets/index-BfRhTvOd.js → ui/assets/index-dNuk2dsU.js} +1 -1
  36. package/.output/ui/assets/json-viewer-BvFHglMb.js +1 -0
  37. package/.output/{public/assets/jszip.min-C9rCFoU3.js → ui/assets/jszip.min-B5Z7gNZB.js} +1 -1
  38. package/.output/ui/index.html +229 -0
  39. package/.output/ui/runtime-config.js +2 -0
  40. package/.output/workers/logFinalizer.worker.js +983 -414
  41. package/.output/workers/sessionWorkerEntry.js +983 -414
  42. package/README.md +363 -35
  43. package/docs/instance-control.openapi.yaml +361 -0
  44. package/package.json +28 -5
  45. package/scripts/generate-theme-scales.mjs +3 -3
  46. package/src/{router.tsx → backend/router.tsx} +3 -15
  47. package/src/backend/routes/$.ts +26 -0
  48. package/src/backend/routes/__root.ts +4 -0
  49. package/src/backend/routes/api/-instances.ts +109 -0
  50. package/src/{routes → backend/routes}/api/alerts.summary.ts +3 -3
  51. package/src/{routes → backend/routes}/api/alerts.ts +4 -4
  52. package/src/{routes → backend/routes}/api/config.paths.ts +1 -1
  53. package/src/{routes → backend/routes}/api/config.ts +11 -2
  54. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.help.ts +1 -1
  55. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.install.ts +1 -1
  56. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.runner-presets.ts +1 -1
  57. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.upgrade.ts +1 -1
  58. package/src/{routes → backend/routes}/api/ecosystem.packages.ts +5 -1
  59. package/src/{routes → backend/routes}/api/ecosystem.recipes.$recipeId.run.ts +1 -1
  60. package/src/{routes → backend/routes}/api/ecosystem.tasks.$taskId.ts +1 -1
  61. package/src/{routes → backend/routes}/api/ecosystem.tasks.ts +1 -1
  62. package/src/{routes → backend/routes}/api/groups.$groupId.evidence.ts +2 -2
  63. package/src/{routes → backend/routes}/api/groups.$groupId.sessions.ts +2 -2
  64. package/src/{routes → backend/routes}/api/groups.$groupId.ts +2 -2
  65. package/src/{routes → backend/routes}/api/groups.ts +2 -2
  66. package/src/{routes → backend/routes}/api/health.ts +3 -3
  67. package/src/backend/routes/api/instances.$name.connection.ts +12 -0
  68. package/src/backend/routes/api/instances.$name.restart.ts +23 -0
  69. package/src/backend/routes/api/instances.$name.start.ts +18 -0
  70. package/src/backend/routes/api/instances.$name.stop.ts +23 -0
  71. package/src/backend/routes/api/instances.$name.ts +12 -0
  72. package/src/backend/routes/api/instances.ts +16 -0
  73. package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.promote.ts +2 -2
  74. package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.ts +2 -2
  75. package/src/{routes → backend/routes}/api/knowledge.candidates.ts +1 -1
  76. package/src/{routes → backend/routes}/api/knowledge.project-context.ts +2 -2
  77. package/src/{routes → backend/routes}/api/knowledge.search.ts +2 -2
  78. package/src/{routes → backend/routes}/api/knowledge.sessions.$sessionId.candidates.ts +3 -3
  79. package/src/{routes → backend/routes}/api/logs.$id.body.ts +6 -6
  80. package/src/{routes → backend/routes}/api/logs.$id.chunks.ts +5 -4
  81. package/src/{routes → backend/routes}/api/logs.$id.replay.ts +12 -11
  82. package/src/{routes → backend/routes}/api/logs.$id.ts +4 -3
  83. package/src/{routes → backend/routes}/api/logs.import.ts +3 -3
  84. package/src/{routes → backend/routes}/api/logs.stream.ts +11 -7
  85. package/src/{routes → backend/routes}/api/logs.ts +17 -9
  86. package/src/{routes → backend/routes}/api/mcp.ts +1 -1
  87. package/src/{routes → backend/routes}/api/models.ts +1 -1
  88. package/src/{routes → backend/routes}/api/pi-agent.ts +2 -2
  89. package/src/{routes → backend/routes}/api/providers.$providerId.model-metadata.ts +5 -5
  90. package/src/{routes → backend/routes}/api/providers.$providerId.test.log.ts +7 -7
  91. package/src/{routes → backend/routes}/api/providers.$providerId.ts +4 -4
  92. package/src/{routes → backend/routes}/api/providers.export.ts +1 -1
  93. package/src/{routes → backend/routes}/api/providers.import.ts +3 -3
  94. package/src/{routes → backend/routes}/api/providers.scan.ts +2 -2
  95. package/src/{routes → backend/routes}/api/providers.ts +9 -4
  96. package/src/{routes → backend/routes}/api/runs.$runId.evidence.ts +2 -2
  97. package/src/{routes → backend/routes}/api/runs.$runId.ts +2 -2
  98. package/src/{routes → backend/routes}/api/runs.ts +4 -4
  99. package/src/backend/routes/api/runtime.ts +46 -0
  100. package/src/{routes → backend/routes}/api/sessions.ts +3 -3
  101. package/src/{routes → backend/routes}/proxy/$.ts +1 -1
  102. package/src/{routes → backend/routes}/readyz.ts +1 -1
  103. package/src/backend/start.ts +10 -0
  104. package/src/cli/alias.ts +431 -0
  105. package/src/cli/doctor.ts +32 -9
  106. package/src/cli/instance.ts +1050 -0
  107. package/src/cli/instanceArgs.ts +285 -0
  108. package/src/cli/instanceControl.ts +181 -0
  109. package/src/cli/instanceModel.ts +267 -0
  110. package/src/cli/instanceRegistry.ts +731 -0
  111. package/src/cli/networkHints.ts +27 -14
  112. package/src/cli/onboard.ts +190 -35
  113. package/src/cli/onboardTarget.ts +228 -0
  114. package/src/cli/templates/codex-skill-onboard.ts +109 -31
  115. package/src/cli/templates/skill-onboard.ts +140 -70
  116. package/src/cli.ts +338 -77
  117. package/src/components/ProxyViewer.tsx +20 -10
  118. package/src/components/ProxyViewerContainer.tsx +12 -11
  119. package/src/components/pi-agent/PiAgentPanel.tsx +2 -2
  120. package/src/components/providers/ProviderCard.tsx +1 -1
  121. package/src/components/providers/ProviderTestResultsView.tsx +1 -1
  122. package/src/components/providers/SettingsDialog.tsx +160 -140
  123. package/src/components/proxy-viewer/ApplicationBar.tsx +2 -1
  124. package/src/components/proxy-viewer/LogEntry.tsx +1 -1
  125. package/src/components/proxy-viewer/log-formats/index.ts +1 -1
  126. package/src/contracts/index.ts +5 -0
  127. package/src/contracts/log.ts +33 -3
  128. package/src/knowledge/types.ts +3 -2
  129. package/src/lib/alertContract.ts +2 -2
  130. package/src/lib/apiClient.ts +30 -7
  131. package/src/lib/apiFormat.ts +29 -0
  132. package/src/lib/basePath.ts +31 -7
  133. package/src/lib/browserRuntimeContract.ts +124 -0
  134. package/src/lib/browserRuntimeResolver.ts +244 -0
  135. package/src/{proxy → lib}/claudeCodeStrip.ts +6 -7
  136. package/src/lib/codingAgentEndpoints.ts +54 -0
  137. package/src/lib/instanceContract.ts +236 -0
  138. package/src/lib/managedInstance.ts +104 -0
  139. package/src/lib/piAgentContract.ts +3 -2
  140. package/src/lib/publicBasePathContext.ts +137 -0
  141. package/src/lib/resourceLimits.ts +2 -0
  142. package/src/lib/runContract.ts +3 -3
  143. package/src/lib/sessionInfoContract.ts +3 -2
  144. package/src/mcp/instanceHandlers.ts +150 -0
  145. package/src/mcp/loopback.ts +16 -5
  146. package/src/mcp/mode.ts +25 -0
  147. package/src/mcp/server.ts +274 -39
  148. package/src/mcp/toolHandlers.ts +2 -2
  149. package/src/proxy/config.ts +25 -30
  150. package/src/proxy/dataDir.ts +43 -7
  151. package/src/proxy/ecosystemTasks.ts +161 -70
  152. package/src/proxy/formats/registry.ts +6 -21
  153. package/src/proxy/handler.ts +129 -29
  154. package/src/proxy/identityProxy.ts +1049 -50
  155. package/src/proxy/jsonlRecovery.ts +554 -0
  156. package/src/proxy/logFinalizer.ts +25 -10
  157. package/src/proxy/logImporter.ts +2 -1
  158. package/src/proxy/logIndex.ts +191 -95
  159. package/src/proxy/logger.ts +77 -14
  160. package/src/proxy/platformCommands.ts +41 -0
  161. package/src/proxy/privateDataPath.ts +310 -88
  162. package/src/proxy/rawStreamCapture.ts +194 -13
  163. package/src/proxy/runtimeAdmission.ts +5 -2
  164. package/src/proxy/runtimeHealth.ts +14 -1
  165. package/src/proxy/runtimeShutdown.ts +84 -2
  166. package/src/proxy/schemas.ts +7 -1
  167. package/src/proxy/sessionArchive.ts +78 -14
  168. package/src/proxy/sessionInfo.ts +5 -4
  169. package/src/proxy/sqliteLogIndex.ts +65 -2
  170. package/src/proxy/store.ts +141 -34
  171. package/src/proxy/uiAssetServer.ts +106 -0
  172. package/src/proxy/upstream.ts +29 -2
  173. package/src/ui/bootstrap.ts +167 -0
  174. package/src/ui/index.html +38 -0
  175. package/src/ui/logsStreamClient.ts +20 -0
  176. package/src/ui/main.tsx +13 -0
  177. package/src/ui/public/runtime-config.js +2 -0
  178. package/src/ui/router.tsx +13 -0
  179. package/src/ui/routes/__root.tsx +69 -0
  180. package/src/{routes → ui/routes}/index.tsx +2 -3
  181. package/src/{routes → ui/routes}/session/$sessionId.tsx +5 -11
  182. package/src/ui/runtimeDiscovery.ts +50 -0
  183. package/styles/globals.css +1 -0
  184. package/.output/public/assets/ProxyViewerContainer-BhpIgfBi.js +0 -126
  185. package/.output/public/assets/ResponseView-DUfrajCm.js +0 -2
  186. package/.output/public/assets/StreamingChunkSequence-nbeCQqOz.js +0 -1
  187. package/.output/public/assets/index-BWjeqxbk.css +0 -1
  188. package/.output/public/assets/index-C6qZwYlR.js +0 -70
  189. package/.output/public/assets/json-viewer-BLmF1sOZ.js +0 -1
  190. package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +0 -1
  191. package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +0 -344
  192. package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +0 -2
  193. package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +0 -2
  194. package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +0 -2
  195. package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +0 -11
  196. package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +0 -69
  197. package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +0 -1
  198. package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +0 -28
  199. package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +0 -6
  200. package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +0 -34
  201. package/.output/server/_libs/aria-hidden.mjs +0 -122
  202. package/.output/server/_libs/bail.mjs +0 -8
  203. package/.output/server/_libs/character-entities.mjs +0 -2130
  204. package/.output/server/_libs/class-variance-authority.mjs +0 -44
  205. package/.output/server/_libs/clsx.mjs +0 -16
  206. package/.output/server/_libs/comma-separated-tokens.mjs +0 -10
  207. package/.output/server/_libs/decode-named-character-reference+[...].mjs +0 -8
  208. package/.output/server/_libs/dequal.mjs +0 -27
  209. package/.output/server/_libs/detect-node-es.mjs +0 -1
  210. package/.output/server/_libs/devlop.mjs +0 -8
  211. package/.output/server/_libs/diff.mjs +0 -320
  212. package/.output/server/_libs/estree-util-is-identifier-name.mjs +0 -11
  213. package/.output/server/_libs/floating-ui__core.mjs +0 -725
  214. package/.output/server/_libs/floating-ui__dom.mjs +0 -622
  215. package/.output/server/_libs/floating-ui__react-dom.mjs +0 -292
  216. package/.output/server/_libs/floating-ui__utils.mjs +0 -320
  217. package/.output/server/_libs/get-nonce.mjs +0 -9
  218. package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +0 -388
  219. package/.output/server/_libs/hast-util-whitespace.mjs +0 -10
  220. package/.output/server/_libs/html-url-attributes.mjs +0 -26
  221. package/.output/server/_libs/inline-style-parser.mjs +0 -142
  222. package/.output/server/_libs/is-plain-obj.mjs +0 -10
  223. package/.output/server/_libs/lucide-react.mjs +0 -1027
  224. package/.output/server/_libs/mdast-util-from-markdown.mjs +0 -717
  225. package/.output/server/_libs/mdast-util-to-hast.mjs +0 -710
  226. package/.output/server/_libs/mdast-util-to-string.mjs +0 -38
  227. package/.output/server/_libs/micromark-core-commonmark.mjs +0 -2259
  228. package/.output/server/_libs/micromark-factory-destination.mjs +0 -94
  229. package/.output/server/_libs/micromark-factory-label.mjs +0 -63
  230. package/.output/server/_libs/micromark-factory-space.mjs +0 -24
  231. package/.output/server/_libs/micromark-factory-title.mjs +0 -65
  232. package/.output/server/_libs/micromark-factory-whitespace.mjs +0 -22
  233. package/.output/server/_libs/micromark-util-character.mjs +0 -44
  234. package/.output/server/_libs/micromark-util-chunked.mjs +0 -36
  235. package/.output/server/_libs/micromark-util-classify-character+[...].mjs +0 -12
  236. package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +0 -41
  237. package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -19
  238. package/.output/server/_libs/micromark-util-decode-string.mjs +0 -21
  239. package/.output/server/_libs/micromark-util-encode.mjs +0 -1
  240. package/.output/server/_libs/micromark-util-html-tag-name.mjs +0 -69
  241. package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +0 -6
  242. package/.output/server/_libs/micromark-util-resolve-all.mjs +0 -15
  243. package/.output/server/_libs/micromark-util-sanitize-uri.mjs +0 -41
  244. package/.output/server/_libs/micromark-util-subtokenize.mjs +0 -346
  245. package/.output/server/_libs/micromark.mjs +0 -906
  246. package/.output/server/_libs/property-information.mjs +0 -1209
  247. package/.output/server/_libs/radix-ui.mjs +0 -1
  248. package/.output/server/_libs/radix-ui__number.mjs +0 -6
  249. package/.output/server/_libs/radix-ui__primitive.mjs +0 -11
  250. package/.output/server/_libs/radix-ui__react-accordion.mjs +0 -1
  251. package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +0 -1
  252. package/.output/server/_libs/radix-ui__react-arrow.mjs +0 -23
  253. package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +0 -1
  254. package/.output/server/_libs/radix-ui__react-avatar.mjs +0 -1
  255. package/.output/server/_libs/radix-ui__react-checkbox.mjs +0 -1
  256. package/.output/server/_libs/radix-ui__react-collapsible.mjs +0 -144
  257. package/.output/server/_libs/radix-ui__react-collection.mjs +0 -69
  258. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +0 -38
  259. package/.output/server/_libs/radix-ui__react-context-menu.mjs +0 -1
  260. package/.output/server/_libs/radix-ui__react-context.mjs +0 -64
  261. package/.output/server/_libs/radix-ui__react-dialog.mjs +0 -280
  262. package/.output/server/_libs/radix-ui__react-direction.mjs +0 -9
  263. package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +0 -1
  264. package/.output/server/_libs/radix-ui__react-focus-guards.mjs +0 -39
  265. package/.output/server/_libs/radix-ui__react-focus-scope.mjs +0 -210
  266. package/.output/server/_libs/radix-ui__react-form.mjs +0 -1
  267. package/.output/server/_libs/radix-ui__react-hover-card.mjs +0 -1
  268. package/.output/server/_libs/radix-ui__react-id.mjs +0 -14
  269. package/.output/server/_libs/radix-ui__react-label.mjs +0 -1
  270. package/.output/server/_libs/radix-ui__react-menu.mjs +0 -1
  271. package/.output/server/_libs/radix-ui__react-menubar.mjs +0 -1
  272. package/.output/server/_libs/radix-ui__react-popover.mjs +0 -1
  273. package/.output/server/_libs/radix-ui__react-popper.mjs +0 -340
  274. package/.output/server/_libs/radix-ui__react-portal.mjs +0 -16
  275. package/.output/server/_libs/radix-ui__react-presence.mjs +0 -173
  276. package/.output/server/_libs/radix-ui__react-primitive.mjs +0 -42
  277. package/.output/server/_libs/radix-ui__react-progress.mjs +0 -1
  278. package/.output/server/_libs/radix-ui__react-radio-group.mjs +0 -1
  279. package/.output/server/_libs/radix-ui__react-roving-focus.mjs +0 -235
  280. package/.output/server/_libs/radix-ui__react-scroll-area.mjs +0 -731
  281. package/.output/server/_libs/radix-ui__react-select.mjs +0 -1207
  282. package/.output/server/_libs/radix-ui__react-separator.mjs +0 -28
  283. package/.output/server/_libs/radix-ui__react-slider.mjs +0 -1
  284. package/.output/server/_libs/radix-ui__react-slot.mjs +0 -132
  285. package/.output/server/_libs/radix-ui__react-switch.mjs +0 -1
  286. package/.output/server/_libs/radix-ui__react-tabs.mjs +0 -194
  287. package/.output/server/_libs/radix-ui__react-toast.mjs +0 -2
  288. package/.output/server/_libs/radix-ui__react-toggle-group.mjs +0 -1
  289. package/.output/server/_libs/radix-ui__react-toggle.mjs +0 -1
  290. package/.output/server/_libs/radix-ui__react-toolbar.mjs +0 -1
  291. package/.output/server/_libs/radix-ui__react-tooltip.mjs +0 -498
  292. package/.output/server/_libs/radix-ui__react-use-previous.mjs +0 -14
  293. package/.output/server/_libs/radix-ui__react-use-size.mjs +0 -39
  294. package/.output/server/_libs/react-markdown.mjs +0 -235
  295. package/.output/server/_libs/react-remove-scroll-bar.mjs +0 -82
  296. package/.output/server/_libs/react-remove-scroll.mjs +0 -328
  297. package/.output/server/_libs/react-style-singleton.mjs +0 -69
  298. package/.output/server/_libs/remark-parse.mjs +0 -19
  299. package/.output/server/_libs/remark-rehype.mjs +0 -21
  300. package/.output/server/_libs/space-separated-tokens.mjs +0 -6
  301. package/.output/server/_libs/style-to-js.mjs +0 -72
  302. package/.output/server/_libs/style-to-object.mjs +0 -38
  303. package/.output/server/_libs/swr.mjs +0 -947
  304. package/.output/server/_libs/tailwind-merge.mjs +0 -3255
  305. package/.output/server/_libs/tanstack__react-virtual.mjs +0 -130
  306. package/.output/server/_libs/tanstack__virtual-core.mjs +0 -1319
  307. package/.output/server/_libs/three.mjs +0 -26016
  308. package/.output/server/_libs/trim-lines.mjs +0 -41
  309. package/.output/server/_libs/trough.mjs +0 -85
  310. package/.output/server/_libs/tslib.mjs +0 -1
  311. package/.output/server/_libs/ungap__structured-clone.mjs +0 -212
  312. package/.output/server/_libs/unified.mjs +0 -661
  313. package/.output/server/_libs/unist-util-is.mjs +0 -100
  314. package/.output/server/_libs/unist-util-position.mjs +0 -27
  315. package/.output/server/_libs/unist-util-stringify-position.mjs +0 -27
  316. package/.output/server/_libs/unist-util-visit-parents.mjs +0 -82
  317. package/.output/server/_libs/unist-util-visit.mjs +0 -24
  318. package/.output/server/_libs/use-callback-ref.mjs +0 -66
  319. package/.output/server/_libs/use-sidecar.mjs +0 -106
  320. package/.output/server/_libs/vfile-message.mjs +0 -138
  321. package/.output/server/_libs/vfile.mjs +0 -467
  322. package/.output/server/_sessionId-E_Dmopc-.mjs +0 -144
  323. package/.output/server/_sessionId-U54BAqdp.mjs +0 -82
  324. package/.output/server/_ssr/CompareDrawer-CksatPed.mjs +0 -1058
  325. package/.output/server/_ssr/InspectorPet-DNc4GQ7z.mjs +0 -936
  326. package/.output/server/_ssr/ProxyViewerContainer-B02Ey0p_.mjs +0 -17607
  327. package/.output/server/_ssr/ReplayDialog-DdMvHJF1.mjs +0 -723
  328. package/.output/server/_ssr/RequestAnatomy--vh2Z8__.mjs +0 -835
  329. package/.output/server/_ssr/ResponseView-Dhxc-cKC.mjs +0 -755
  330. package/.output/server/_ssr/StreamingChunkSequence-BG0EQmaD.mjs +0 -272
  331. package/.output/server/_ssr/index-D0At9nfd.mjs +0 -82
  332. package/.output/server/_ssr/index-lcfulIXa.mjs +0 -133
  333. package/.output/server/_ssr/json-viewer-My1J1_5R.mjs +0 -481
  334. package/.output/server/_ssr/start-HYkvq4Ni.mjs +0 -4
  335. package/.output/server/_tanstack-start-manifest_v-B2chR8ef.mjs +0 -4
  336. package/.output/server/node_modules/tslib/modules/index.js +0 -70
  337. package/.output/server/node_modules/tslib/modules/package.json +0 -3
  338. package/.output/server/node_modules/tslib/package.json +0 -47
  339. package/.output/server/node_modules/tslib/tslib.js +0 -484
  340. package/.output/server/package.json +0 -9
  341. package/src/routes/__root.tsx +0 -170
  342. /package/.output/{public → ui}/assets/agent-inspector-58K1_MsC.ico +0 -0
  343. /package/.output/{public → ui}/assets/alibaba-TTwafVwX.svg +0 -0
  344. /package/.output/{public → ui}/assets/minimax-BPMzvuL-.jpeg +0 -0
  345. /package/.output/{public → ui}/assets/qwen-mMn3f5ul.webp +0 -0
  346. /package/.output/{public → ui}/assets/zhipuai-BPNAnxo-.svg +0 -0
  347. /package/src/{routes → backend/routes}/livez.ts +0 -0
@@ -1,7 +1,7 @@
1
1
  import { existsSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { logger, resolveLogDir } from "./logger";
4
- import type { ApiFormat } from "./schemas";
4
+ import type { ApiFormat, CaptureIncompleteReason } from "./schemas";
5
5
  import type { LogIndexEntry, LogIndexSummary } from "./logIndex";
6
6
  import { ensurePrivateDirectorySync, securePrivateFileSync } from "./privateDataPath";
7
7
 
@@ -47,6 +47,10 @@ CREATE TABLE IF NOT EXISTS log_index (
47
47
  streaming_chunks_path TEXT,
48
48
  raw_request_body_bytes INTEGER,
49
49
  response_text_bytes INTEGER,
50
+ capture_incomplete INTEGER NOT NULL DEFAULT 0,
51
+ dropped_chunks INTEGER NOT NULL DEFAULT 0,
52
+ dropped_bytes INTEGER NOT NULL DEFAULT 0,
53
+ capture_incomplete_reason TEXT,
50
54
  warnings_json TEXT,
51
55
  error TEXT
52
56
  );
@@ -89,10 +93,14 @@ INSERT INTO log_index (
89
93
  streaming_chunks_path,
90
94
  raw_request_body_bytes,
91
95
  response_text_bytes,
96
+ capture_incomplete,
97
+ dropped_chunks,
98
+ dropped_bytes,
99
+ capture_incomplete_reason,
92
100
  warnings_json,
93
101
  error
94
102
  ) VALUES (
95
- ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
103
+ ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
96
104
  )
97
105
  ON CONFLICT(id) DO UPDATE SET
98
106
  file = excluded.file,
@@ -126,6 +134,10 @@ ON CONFLICT(id) DO UPDATE SET
126
134
  streaming_chunks_path = excluded.streaming_chunks_path,
127
135
  raw_request_body_bytes = excluded.raw_request_body_bytes,
128
136
  response_text_bytes = excluded.response_text_bytes,
137
+ capture_incomplete = excluded.capture_incomplete,
138
+ dropped_chunks = excluded.dropped_chunks,
139
+ dropped_bytes = excluded.dropped_bytes,
140
+ capture_incomplete_reason = excluded.capture_incomplete_reason,
129
141
  warnings_json = excluded.warnings_json,
130
142
  error = excluded.error
131
143
  `;
@@ -215,6 +227,30 @@ function execSql(db: unknown, sql: string): boolean {
215
227
  return result !== undefined;
216
228
  }
217
229
 
230
+ const REQUIRED_SCHEMA_COLUMNS = [
231
+ { name: "capture_incomplete", definition: "INTEGER NOT NULL DEFAULT 0" },
232
+ { name: "dropped_chunks", definition: "INTEGER NOT NULL DEFAULT 0" },
233
+ { name: "dropped_bytes", definition: "INTEGER NOT NULL DEFAULT 0" },
234
+ { name: "capture_incomplete_reason", definition: "TEXT" },
235
+ ];
236
+
237
+ function ensureSchemaColumns(db: unknown): boolean {
238
+ const rows = allPrepared(db, "PRAGMA table_info(log_index)");
239
+ if (rows === null) return false;
240
+ const existing = new Set<string>();
241
+ for (const row of rows) {
242
+ const name = readProperty(row, "name");
243
+ if (typeof name === "string") existing.add(name);
244
+ }
245
+ for (const column of REQUIRED_SCHEMA_COLUMNS) {
246
+ if (existing.has(column.name)) continue;
247
+ if (!execSql(db, `ALTER TABLE log_index ADD COLUMN ${column.name} ${column.definition}`)) {
248
+ return false;
249
+ }
250
+ }
251
+ return true;
252
+ }
253
+
218
254
  function sqliteConstructorFromModule(
219
255
  moduleValue: unknown,
220
256
  exportName: "default" | "Database",
@@ -316,6 +352,9 @@ async function initializeSqliteState(): Promise<SqliteState> {
316
352
  if (!execSql(db, CREATE_SCHEMA_SQL)) {
317
353
  return { status: "unavailable", path, reason: "SQLite schema initialization failed" };
318
354
  }
355
+ if (!ensureSchemaColumns(db)) {
356
+ return { status: "unavailable", path, reason: "SQLite schema migration failed" };
357
+ }
319
358
  activeDb = db;
320
359
  return { status: "ready", db, path };
321
360
  } catch (err) {
@@ -394,6 +433,10 @@ function entryParams(entry: LogIndexEntry): readonly unknown[] {
394
433
  summary?.streamingChunksPath ?? null,
395
434
  summary?.rawRequestBodyBytes ?? null,
396
435
  summary?.responseTextBytes ?? null,
436
+ boolToInt(summary?.captureIncomplete ?? false),
437
+ summary?.droppedChunks ?? 0,
438
+ summary?.droppedBytes ?? 0,
439
+ summary?.captureIncompleteReason ?? null,
397
440
  warningJson(summary?.warnings),
398
441
  summary?.error ?? null,
399
442
  ];
@@ -428,6 +471,22 @@ function readApiFormat(row: unknown): ApiFormat {
428
471
  }
429
472
  }
430
473
 
474
+ function readCaptureIncompleteReason(row: unknown): CaptureIncompleteReason | null {
475
+ const value = readString(row, "capture_incomplete_reason");
476
+ switch (value) {
477
+ case "capacity-exceeded":
478
+ case "pipeline-closed":
479
+ case "write-failed":
480
+ case "finalize-failed":
481
+ case "upstream-stream-error":
482
+ case "shutdown":
483
+ return value;
484
+ case null:
485
+ default:
486
+ return null;
487
+ }
488
+ }
489
+
431
490
  function readWarnings(row: unknown): string[] | undefined {
432
491
  const value = readString(row, "warnings_json");
433
492
  if (value === null) return undefined;
@@ -481,6 +540,10 @@ function summaryFromRow(row: unknown, id: number): LogIndexSummary {
481
540
  streamingChunksPath: readString(row, "streaming_chunks_path"),
482
541
  rawRequestBodyBytes: readNumber(row, "raw_request_body_bytes"),
483
542
  responseTextBytes: readNumber(row, "response_text_bytes"),
543
+ captureIncomplete: readBoolean(row, "capture_incomplete"),
544
+ droppedChunks: readNumber(row, "dropped_chunks") ?? 0,
545
+ droppedBytes: readNumber(row, "dropped_bytes") ?? 0,
546
+ captureIncompleteReason: readCaptureIncompleteReason(row),
484
547
  warnings: readWarnings(row),
485
548
  error: readString(row, "error"),
486
549
  };
@@ -29,6 +29,7 @@ import {
29
29
  listFilteredIndexEntries,
30
30
  listIndexEntries,
31
31
  rebuildIndex,
32
+ updateLogIndexEntryMetadata,
32
33
  type LogIndexEntry,
33
34
  type LogIndexSummary,
34
35
  } from "./logIndex";
@@ -42,7 +43,7 @@ import { CapturedLogSchema } from "./schemas";
42
43
  import { apiFormatForPath } from "./formats/registry";
43
44
  import type { ImportedLogDraft } from "./logImporter";
44
45
  import {
45
- archiveSessionLog,
46
+ archiveSessionLogs,
46
47
  clearSessionArchives,
47
48
  deleteArchivedLogsByIds,
48
49
  findArchivedLogById,
@@ -55,6 +56,7 @@ import {
55
56
  PRIVATE_FILE_MODE,
56
57
  securePrivateFileSync,
57
58
  } from "./privateDataPath";
59
+ import { recoverCapturedLogStorage } from "./jsonlRecovery";
58
60
  import {
59
61
  clearSessionRegistry,
60
62
  getLogSessionId,
@@ -162,6 +164,43 @@ type LogCursorPageIndex = {
162
164
  const logCursorPageIndexes: Map<string, LogCursorPageIndex> = new Map();
163
165
  let logCursorPageIndexBuildCount = 0;
164
166
  let sessionArchiveQueue: Promise<void> = Promise.resolve();
167
+ const SESSION_ARCHIVE_BATCH_SIZE = 128;
168
+ const SESSION_ARCHIVE_FLUSH_DELAY_MS = 10;
169
+ let sessionArchiveBuffer: CapturedLog[] = [];
170
+ let sessionArchiveFlushTimeout: ReturnType<typeof setTimeout> | null = null;
171
+
172
+ function drainSessionArchiveBuffer(): CapturedLog[] {
173
+ const logs = sessionArchiveBuffer;
174
+ sessionArchiveBuffer = [];
175
+ return logs;
176
+ }
177
+
178
+ function queueSessionArchiveFlush(): void {
179
+ const logs = drainSessionArchiveBuffer();
180
+ if (logs.length === 0) return;
181
+ sessionArchiveQueue = sessionArchiveQueue
182
+ .catch(() => undefined)
183
+ .then(async () => {
184
+ await archiveSessionLogs(logs);
185
+ })
186
+ .catch((err: unknown) => {
187
+ logger.warn("[store] Failed to archive session logs:", String(err));
188
+ });
189
+ }
190
+
191
+ function cancelSessionArchiveFlushTimer(): void {
192
+ if (sessionArchiveFlushTimeout === null) return;
193
+ clearTimeout(sessionArchiveFlushTimeout);
194
+ sessionArchiveFlushTimeout = null;
195
+ }
196
+
197
+ function scheduleSessionArchiveFlush(): void {
198
+ if (sessionArchiveFlushTimeout !== null) return;
199
+ sessionArchiveFlushTimeout = setTimeout(() => {
200
+ sessionArchiveFlushTimeout = null;
201
+ queueSessionArchiveFlush();
202
+ }, SESSION_ARCHIVE_FLUSH_DELAY_MS);
203
+ }
165
204
 
166
205
  function cursorPageIndexKey(
167
206
  options: Pick<ListLogsCursorPageOptions, "sessionId" | "model" | "clientPid">,
@@ -233,8 +272,29 @@ function normalizeLog(log: CapturedLog): CapturedLog {
233
272
  const sessionId = getLogSessionId(log);
234
273
  const pathFormat = apiFormatForPath(log.path);
235
274
  const apiFormat = pathFormat === "unknown" ? log.apiFormat : pathFormat;
236
- if (sessionId === log.sessionId && apiFormat === log.apiFormat) return log;
237
- return { ...log, sessionId, apiFormat };
275
+ const captureIncomplete = log.captureIncomplete ?? false;
276
+ const droppedChunks = log.droppedChunks ?? 0;
277
+ const droppedBytes = log.droppedBytes ?? 0;
278
+ const captureIncompleteReason = log.captureIncompleteReason ?? null;
279
+ if (
280
+ sessionId === log.sessionId &&
281
+ apiFormat === log.apiFormat &&
282
+ log.captureIncomplete !== undefined &&
283
+ log.droppedChunks !== undefined &&
284
+ log.droppedBytes !== undefined &&
285
+ log.captureIncompleteReason !== undefined
286
+ ) {
287
+ return log;
288
+ }
289
+ return {
290
+ ...log,
291
+ sessionId,
292
+ apiFormat,
293
+ captureIncomplete,
294
+ droppedChunks,
295
+ droppedBytes,
296
+ captureIncompleteReason,
297
+ };
238
298
  }
239
299
 
240
300
  function addToCache(log: CapturedLog): void {
@@ -249,19 +309,20 @@ function addToCache(log: CapturedLog): void {
249
309
  }
250
310
 
251
311
  function archiveLogSnapshot(log: CapturedLog): void {
252
- const archivedLog = normalizeLog(log);
253
- sessionArchiveQueue = sessionArchiveQueue
254
- .catch(() => undefined)
255
- .then(async () => {
256
- await archiveSessionLog(archivedLog);
257
- })
258
- .catch((err: unknown) => {
259
- logger.warn("[store] Failed to archive session log:", String(err));
260
- });
312
+ sessionArchiveBuffer.push(normalizeLog(log));
313
+ if (sessionArchiveBuffer.length >= SESSION_ARCHIVE_BATCH_SIZE) {
314
+ cancelSessionArchiveFlushTimer();
315
+ queueSessionArchiveFlush();
316
+ } else if (sessionArchiveBuffer.length === 1) {
317
+ scheduleSessionArchiveFlush();
318
+ }
261
319
  }
262
320
 
263
321
  export async function flushSessionArchiveWrites(): Promise<void> {
322
+ cancelSessionArchiveFlushTimer();
323
+ if (sessionArchiveBuffer.length > 0) queueSessionArchiveFlush();
264
324
  await sessionArchiveQueue;
325
+ if (sessionArchiveBuffer.length > 0) await flushSessionArchiveWrites();
265
326
  }
266
327
 
267
328
  function removeFromCache(id: number): void {
@@ -317,6 +378,10 @@ function compactLogFromIndexSummary(summary: LogIndexSummary): CapturedLog {
317
378
  rawRequestBodyBytes: summary.rawRequestBodyBytes,
318
379
  responseTextBytes: summary.responseTextBytes,
319
380
  bodyContentMode: "compact",
381
+ captureIncomplete: summary.captureIncomplete,
382
+ droppedChunks: summary.droppedChunks,
383
+ droppedBytes: summary.droppedBytes,
384
+ captureIncompleteReason: summary.captureIncompleteReason,
320
385
  warnings: summary.warnings,
321
386
  error: summary.error,
322
387
  });
@@ -441,6 +506,10 @@ export async function createLog(
441
506
  clientCwd: clientInfo?.cwd ?? null,
442
507
  clientProjectFolder: clientInfo?.projectFolder ?? null,
443
508
  streamingChunksPath: null,
509
+ captureIncomplete: false,
510
+ droppedChunks: 0,
511
+ droppedBytes: 0,
512
+ captureIncompleteReason: null,
444
513
  });
445
514
 
446
515
  // Write to disk and update index
@@ -466,6 +535,12 @@ export function finalizeLogUpdate(log: CapturedLog): void {
466
535
  emitLogUpdate(log);
467
536
  }
468
537
 
538
+ /** Persist the terminal cache/session state and refresh both JSON and SQLite index summaries. */
539
+ export async function persistFinalizedLogUpdate(log: CapturedLog): Promise<void> {
540
+ finalizeLogUpdate(log);
541
+ await updateLogIndexEntryMetadata(log);
542
+ }
543
+
469
544
  async function getArchivedLogByIdForStore(id: number): Promise<CapturedLog | null> {
470
545
  await flushSessionArchiveWrites();
471
546
  const archivedLog = await findArchivedLogById(id);
@@ -543,24 +618,31 @@ async function scanLogFileForId(filePath: string, id: number): Promise<CapturedL
543
618
  crlfDelay: Infinity,
544
619
  });
545
620
 
621
+ let lineNumber = 0;
546
622
  for await (const line of fileStream) {
623
+ lineNumber += 1;
547
624
  if (line.trim() === "") continue;
625
+ let parsed: unknown;
548
626
  try {
549
- const parsed: unknown = JSON.parse(line);
550
- if (typeof parsed === "object" && parsed !== null) {
551
- const desc = Object.getOwnPropertyDescriptor(parsed, "id");
552
- if (desc !== undefined && typeof desc.value === "number" && desc.value === id) {
553
- const result = CapturedLogSchema.safeParse(parsed);
554
- if (result.success) {
555
- lastMatch = normalizeLog(result.data);
556
- if (result.data.responseStatus !== null) {
557
- return lastMatch;
558
- }
559
- }
560
- }
627
+ parsed = JSON.parse(line);
628
+ } catch (error) {
629
+ return await Promise.reject(
630
+ new Error(
631
+ `Malformed JSONL record in ${filePath} at line ${String(lineNumber)}: ${String(error)}`,
632
+ ),
633
+ );
634
+ }
635
+ const result = CapturedLogSchema.safeParse(parsed);
636
+ if (!result.success) {
637
+ return await Promise.reject(
638
+ new Error(`Invalid captured-log record in ${filePath} at line ${String(lineNumber)}`),
639
+ );
640
+ }
641
+ if (result.data.id === id) {
642
+ lastMatch = normalizeLog(result.data);
643
+ if (result.data.responseStatus !== null) {
644
+ return lastMatch;
561
645
  }
562
- } catch {
563
- // Skip malformed lines
564
646
  }
565
647
  }
566
648
 
@@ -597,6 +679,13 @@ async function visitPersistedLogs(visitor: PersistedLogVisitor): Promise<void> {
597
679
  const logDir = resolveLogDir();
598
680
  if (!existsSync(logDir)) return;
599
681
 
682
+ const recovery = await recoverCapturedLogStorage(logDir);
683
+ if (recovery.level === "unavailable") {
684
+ return await Promise.reject(
685
+ new Error(recovery.diagnostic ?? "Captured-log recovery blocked persisted-log reads"),
686
+ );
687
+ }
688
+
600
689
  try {
601
690
  const entries = await readdirCallback(logDir);
602
691
  const files = entries.filter((file) => file.endsWith(".jsonl")).sort();
@@ -605,6 +694,9 @@ async function visitPersistedLogs(visitor: PersistedLogVisitor): Promise<void> {
605
694
  }
606
695
  } catch (err) {
607
696
  logger.error("[store] Failed to list persisted logs:", String(err));
697
+ return await Promise.reject(
698
+ err instanceof Error ? err : new Error(`Failed to list persisted logs: ${String(err)}`),
699
+ );
608
700
  }
609
701
  }
610
702
 
@@ -620,21 +712,36 @@ async function visitPersistedLogFile(
620
712
  crlfDelay: Infinity,
621
713
  });
622
714
 
715
+ let lineNumber = 0;
623
716
  for await (const line of fileStream) {
717
+ lineNumber += 1;
624
718
  if (line.trim() === "") continue;
719
+ let parsed: unknown;
625
720
  try {
626
- const parsed: unknown = JSON.parse(line);
627
- const result = CapturedLogSchema.safeParse(parsed);
628
- if (result.success) {
629
- const log = normalizeLog(result.data);
630
- visitor(log);
631
- }
632
- } catch {
633
- // Skip malformed lines.
721
+ parsed = JSON.parse(line);
722
+ } catch (error) {
723
+ return await Promise.reject(
724
+ new Error(
725
+ `Malformed JSONL record in ${filePath} at line ${String(lineNumber)}: ${String(error)}`,
726
+ ),
727
+ );
634
728
  }
729
+ const result = CapturedLogSchema.safeParse(parsed);
730
+ if (!result.success) {
731
+ return await Promise.reject(
732
+ new Error(`Invalid captured-log record in ${filePath} at line ${String(lineNumber)}`),
733
+ );
734
+ }
735
+ const log = normalizeLog(result.data);
736
+ visitor(log);
635
737
  }
636
738
  } catch (err) {
637
739
  logger.error("[store] Failed to read persisted log file:", filePath, String(err));
740
+ return await Promise.reject(
741
+ err instanceof Error
742
+ ? err
743
+ : new Error(`Failed to read persisted log file ${filePath}: ${String(err)}`),
744
+ );
638
745
  }
639
746
  }
640
747
 
@@ -0,0 +1,106 @@
1
+ import { Buffer } from "node:buffer";
2
+ import { readFile } from "node:fs/promises";
3
+ import { extname, relative, resolve, sep } from "node:path";
4
+
5
+ const CONTENT_TYPES: Readonly<Record<string, string>> = {
6
+ ".css": "text/css; charset=utf-8",
7
+ ".html": "text/html; charset=utf-8",
8
+ ".ico": "image/x-icon",
9
+ ".jpeg": "image/jpeg",
10
+ ".jpg": "image/jpeg",
11
+ ".js": "text/javascript; charset=utf-8",
12
+ ".json": "application/json; charset=utf-8",
13
+ ".map": "application/json; charset=utf-8",
14
+ ".png": "image/png",
15
+ ".svg": "image/svg+xml",
16
+ ".webp": "image/webp",
17
+ ".woff": "font/woff",
18
+ ".woff2": "font/woff2",
19
+ };
20
+
21
+ export type UiAsset = {
22
+ body: Buffer;
23
+ cacheControl: string;
24
+ contentType: string;
25
+ document: boolean;
26
+ };
27
+
28
+ function safeDecodedPath(pathname: string): string | null {
29
+ let decoded: string;
30
+ try {
31
+ decoded = decodeURIComponent(pathname);
32
+ } catch {
33
+ return null;
34
+ }
35
+ if (decoded.includes("\\") || decoded.includes("\0")) return null;
36
+ if (decoded.split("/").some((segment) => segment === "." || segment === "..")) return null;
37
+ return decoded;
38
+ }
39
+
40
+ function isInsideDirectory(path: string, directory: string): boolean {
41
+ const child = relative(directory, path);
42
+ return child === "" || (!child.startsWith("..") && !child.startsWith(sep));
43
+ }
44
+
45
+ function assetPath(uiDirectory: string, pathname: string): string | null {
46
+ const decoded = safeDecodedPath(pathname);
47
+ if (decoded === null) return null;
48
+ const target = resolve(uiDirectory, `.${decoded}`);
49
+ return isInsideDirectory(target, resolve(uiDirectory)) ? target : null;
50
+ }
51
+
52
+ async function readAsset(path: string): Promise<Buffer | null> {
53
+ try {
54
+ return await readFile(path);
55
+ } catch {
56
+ return null;
57
+ }
58
+ }
59
+
60
+ function contentTypeFor(path: string): string {
61
+ return CONTENT_TYPES[extname(path).toLowerCase()] ?? "application/octet-stream";
62
+ }
63
+
64
+ function isBackendNamespace(pathname: string): boolean {
65
+ return (
66
+ pathname === "/api" ||
67
+ pathname.startsWith("/api/") ||
68
+ pathname === "/proxy" ||
69
+ pathname.startsWith("/proxy/") ||
70
+ pathname === "/livez" ||
71
+ pathname === "/readyz"
72
+ );
73
+ }
74
+
75
+ function shouldUseDocumentFallback(pathname: string): boolean {
76
+ if (pathname === "/" || pathname.length === 0) return true;
77
+ const lastSegment = pathname.split("/").at(-1) ?? "";
78
+ return !lastSegment.includes(".");
79
+ }
80
+
81
+ export async function loadUiAsset(uiDirectory: string, pathname: string): Promise<UiAsset | null> {
82
+ if (isBackendNamespace(pathname)) return null;
83
+ const requestedPath = assetPath(uiDirectory, pathname);
84
+ if (requestedPath === null) return null;
85
+ const requestedBody = await readAsset(requestedPath);
86
+ if (requestedBody !== null) {
87
+ return {
88
+ body: requestedBody,
89
+ cacheControl: pathname.startsWith("/assets/")
90
+ ? "public, max-age=31536000, immutable"
91
+ : "no-cache",
92
+ contentType: contentTypeFor(requestedPath),
93
+ document: extname(requestedPath).toLowerCase() === ".html",
94
+ };
95
+ }
96
+ if (!shouldUseDocumentFallback(pathname)) return null;
97
+ const indexPath = resolve(uiDirectory, "index.html");
98
+ const indexBody = await readAsset(indexPath);
99
+ if (indexBody === null) return null;
100
+ return {
101
+ body: indexBody,
102
+ cacheControl: "no-store",
103
+ contentType: CONTENT_TYPES[".html"] ?? "text/html; charset=utf-8",
104
+ document: true,
105
+ };
106
+ }
@@ -55,8 +55,9 @@ export function selectUpstreamBase(route: ApiRoute, provider: ProviderConfig | n
55
55
  if (formatSpecificUrl !== undefined && formatSpecificUrl !== "") {
56
56
  return formatSpecificUrl;
57
57
  }
58
- if (provider.baseUrl !== undefined && provider.baseUrl !== "") {
59
- return provider.baseUrl;
58
+ const legacyBaseUrl = selectLegacyBaseUrl(route, provider);
59
+ if (legacyBaseUrl !== undefined) {
60
+ return legacyBaseUrl;
60
61
  }
61
62
 
62
63
  // Legacy records may only contain format. Keep this fallback for compatibility,
@@ -68,6 +69,22 @@ function nonEmptyUrl(value: string | undefined): string | undefined {
68
69
  return value !== undefined && value !== "" ? value : undefined;
69
70
  }
70
71
 
72
+ function hasFormatSpecificUrlFields(provider: ProviderConfig): boolean {
73
+ return (
74
+ provider.anthropicBaseUrl !== undefined ||
75
+ provider.openaiBaseUrl !== undefined ||
76
+ provider.openaiResponsesBaseUrl !== undefined
77
+ );
78
+ }
79
+
80
+ function selectLegacyBaseUrl(route: ApiRoute, provider: ProviderConfig): string | undefined {
81
+ if (hasFormatSpecificUrlFields(provider)) return undefined;
82
+ const baseUrl = nonEmptyUrl(provider.baseUrl);
83
+ if (baseUrl === undefined) return undefined;
84
+ if (route.isOpenAI) return provider.format === "openai" ? baseUrl : undefined;
85
+ return provider.format === "anthropic" ? baseUrl : undefined;
86
+ }
87
+
71
88
  function selectFormatSpecificUrl(route: ApiRoute, provider: ProviderConfig): string | undefined {
72
89
  if (!route.isOpenAI) return provider.anthropicBaseUrl;
73
90
  if (route.isResponses) {
@@ -76,6 +93,16 @@ function selectFormatSpecificUrl(route: ApiRoute, provider: ProviderConfig): str
76
93
  return provider.openaiBaseUrl;
77
94
  }
78
95
 
96
+ /**
97
+ * Whether a model-matched Provider explicitly supports the protocol selected by the request path.
98
+ * Empty current-schema fields are deliberate opt-outs. Only a legacy record with no protocol URL
99
+ * fields may use baseUrl, and then only for the protocol declared by provider.format.
100
+ */
101
+ export function providerSupportsApiRoute(route: ApiRoute, provider: ProviderConfig): boolean {
102
+ if (nonEmptyUrl(selectFormatSpecificUrl(route, provider)) !== undefined) return true;
103
+ return selectLegacyBaseUrl(route, provider) !== undefined;
104
+ }
105
+
79
106
  export function setUpstreamHost(headers: Headers, upstreamBase: string): void {
80
107
  try {
81
108
  headers.set(HEADER_HOST, new URL(upstreamBase).host);