@tonyclaw/agent-inspector 3.0.45 → 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 (338) 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 +2326 -516
  4. package/.output/server/_libs/extend.mjs +4 -8
  5. package/.output/server/_libs/jszip.mjs +9 -35
  6. package/.output/server/_libs/react-dom.mjs +2 -3
  7. package/.output/server/_libs/react.mjs +1 -27
  8. package/.output/server/_libs/tanstack__react-router.mjs +1 -329
  9. package/.output/server/_libs/tanstack__router-core.mjs +42 -100
  10. package/.output/server/_libs/use-sync-external-store.mjs +1 -64
  11. package/.output/server/_libs/ws.mjs +1 -1
  12. package/.output/server/_ssr/index.mjs +4 -4
  13. package/.output/server/_ssr/{publicBasePathContext-5264L3rX.mjs → publicBasePathContext-IH2ilOfu.mjs} +52 -24
  14. package/.output/server/_ssr/{router-BJ_ltLim.mjs → router-D18yUq36.mjs} +19770 -19447
  15. package/.output/server/_ssr/{start-C6MjPjxp.mjs → start-COQu_AgD.mjs} +1 -1
  16. package/.output/server/_tanstack-start-manifest_v-DnbdNeun.mjs +4 -0
  17. package/.output/server/index.mjs +5 -145
  18. package/.output/{public/assets/CompareDrawer-B3_TLTJh.js → ui/assets/CompareDrawer-DAUuIJ6G.js} +1 -1
  19. package/.output/{public/assets/InspectorPet-Cpn6hv4P.js → ui/assets/InspectorPet-BRBVjOWI.js} +1 -1
  20. package/.output/ui/assets/ProxyViewerContainer-D7Sq0ctc.js +59 -0
  21. package/.output/{public/assets/ReplayDialog-B3EKVdJk.js → ui/assets/ReplayDialog-nDLsjOhs.js} +1 -1
  22. package/.output/{public/assets/RequestAnatomy-COOQjyUC.js → ui/assets/RequestAnatomy-zd4BDgL0.js} +1 -1
  23. package/.output/ui/assets/ResponseView-AdIXGcSn.js +2 -0
  24. package/.output/ui/assets/StreamingChunkSequence-CesTz8He.js +1 -0
  25. package/.output/{public/assets/_sessionId-zbgYl7ZJ.js → ui/assets/_sessionId-BAfzrhSU.js} +1 -1
  26. package/.output/{public/assets/_sessionId-BJlM3nmt.js → ui/assets/_sessionId-QnBomgPD.js} +1 -1
  27. package/.output/ui/assets/favicon-DYEkHSNl.svg +21 -0
  28. package/.output/{public/assets/index-BIK4bPTv.js → ui/assets/index-BcsdxBAd.js} +1 -1
  29. package/.output/ui/assets/index-BvXp42al.css +1 -0
  30. package/.output/{public/assets/index-D2Qw6Ri2.js → ui/assets/index-D0rtCN9V.js} +1 -1
  31. package/.output/ui/assets/index-DHpwr08Z.js +73 -0
  32. package/.output/{public/assets/index-xF_NY8Yb.js → ui/assets/index-dNuk2dsU.js} +5 -5
  33. package/.output/ui/assets/json-viewer-BvFHglMb.js +1 -0
  34. package/.output/{public/assets/jszip.min-B_rfAUCe.js → ui/assets/jszip.min-B5Z7gNZB.js} +1 -1
  35. package/.output/ui/index.html +229 -0
  36. package/.output/ui/runtime-config.js +2 -0
  37. package/.output/workers/logFinalizer.worker.js +979 -414
  38. package/.output/workers/sessionWorkerEntry.js +979 -414
  39. package/README.md +175 -43
  40. package/docs/instance-control.openapi.yaml +59 -4
  41. package/package.json +25 -5
  42. package/scripts/generate-theme-scales.mjs +3 -3
  43. package/src/{router.tsx → backend/router.tsx} +3 -15
  44. package/src/backend/routes/$.ts +26 -0
  45. package/src/backend/routes/__root.ts +4 -0
  46. package/src/{routes → backend/routes}/api/-instances.ts +3 -3
  47. package/src/{routes → backend/routes}/api/alerts.summary.ts +3 -3
  48. package/src/{routes → backend/routes}/api/alerts.ts +4 -4
  49. package/src/{routes → backend/routes}/api/config.paths.ts +1 -1
  50. package/src/{routes → backend/routes}/api/config.ts +11 -2
  51. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.help.ts +1 -1
  52. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.install.ts +1 -1
  53. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.runner-presets.ts +1 -1
  54. package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.upgrade.ts +1 -1
  55. package/src/{routes → backend/routes}/api/ecosystem.packages.ts +5 -1
  56. package/src/{routes → backend/routes}/api/ecosystem.recipes.$recipeId.run.ts +1 -1
  57. package/src/{routes → backend/routes}/api/ecosystem.tasks.$taskId.ts +1 -1
  58. package/src/{routes → backend/routes}/api/ecosystem.tasks.ts +1 -1
  59. package/src/{routes → backend/routes}/api/groups.$groupId.evidence.ts +2 -2
  60. package/src/{routes → backend/routes}/api/groups.$groupId.sessions.ts +2 -2
  61. package/src/{routes → backend/routes}/api/groups.$groupId.ts +2 -2
  62. package/src/{routes → backend/routes}/api/groups.ts +2 -2
  63. package/src/{routes → backend/routes}/api/health.ts +3 -3
  64. package/src/{routes → backend/routes}/api/instances.$name.connection.ts +1 -1
  65. package/src/{routes → backend/routes}/api/instances.$name.restart.ts +2 -2
  66. package/src/{routes → backend/routes}/api/instances.$name.start.ts +2 -2
  67. package/src/{routes → backend/routes}/api/instances.$name.stop.ts +2 -2
  68. package/src/{routes → backend/routes}/api/instances.$name.ts +1 -1
  69. package/src/{routes → backend/routes}/api/instances.ts +1 -1
  70. package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.promote.ts +2 -2
  71. package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.ts +2 -2
  72. package/src/{routes → backend/routes}/api/knowledge.candidates.ts +1 -1
  73. package/src/{routes → backend/routes}/api/knowledge.project-context.ts +2 -2
  74. package/src/{routes → backend/routes}/api/knowledge.search.ts +2 -2
  75. package/src/{routes → backend/routes}/api/knowledge.sessions.$sessionId.candidates.ts +3 -3
  76. package/src/{routes → backend/routes}/api/logs.$id.body.ts +6 -6
  77. package/src/{routes → backend/routes}/api/logs.$id.chunks.ts +5 -4
  78. package/src/{routes → backend/routes}/api/logs.$id.replay.ts +12 -11
  79. package/src/{routes → backend/routes}/api/logs.$id.ts +4 -3
  80. package/src/{routes → backend/routes}/api/logs.import.ts +3 -3
  81. package/src/{routes → backend/routes}/api/logs.stream.ts +11 -7
  82. package/src/{routes → backend/routes}/api/logs.ts +17 -9
  83. package/src/{routes → backend/routes}/api/mcp.ts +1 -1
  84. package/src/{routes → backend/routes}/api/models.ts +1 -1
  85. package/src/{routes → backend/routes}/api/pi-agent.ts +2 -2
  86. package/src/{routes → backend/routes}/api/providers.$providerId.model-metadata.ts +5 -5
  87. package/src/{routes → backend/routes}/api/providers.$providerId.test.log.ts +7 -7
  88. package/src/{routes → backend/routes}/api/providers.$providerId.ts +4 -4
  89. package/src/{routes → backend/routes}/api/providers.export.ts +1 -1
  90. package/src/{routes → backend/routes}/api/providers.import.ts +3 -3
  91. package/src/{routes → backend/routes}/api/providers.scan.ts +2 -2
  92. package/src/{routes → backend/routes}/api/providers.ts +9 -4
  93. package/src/{routes → backend/routes}/api/runs.$runId.evidence.ts +2 -2
  94. package/src/{routes → backend/routes}/api/runs.$runId.ts +2 -2
  95. package/src/{routes → backend/routes}/api/runs.ts +4 -4
  96. package/src/backend/routes/api/runtime.ts +46 -0
  97. package/src/{routes → backend/routes}/api/sessions.ts +3 -3
  98. package/src/{routes → backend/routes}/proxy/$.ts +1 -1
  99. package/src/{routes → backend/routes}/readyz.ts +1 -1
  100. package/src/{start.ts → backend/start.ts} +1 -1
  101. package/src/cli/alias.ts +2 -11
  102. package/src/cli/doctor.ts +32 -9
  103. package/src/cli/instance.ts +26 -13
  104. package/src/cli/instanceArgs.ts +30 -11
  105. package/src/cli/instanceControl.ts +0 -2
  106. package/src/cli/instanceModel.ts +9 -17
  107. package/src/cli/instanceRegistry.ts +0 -9
  108. package/src/cli/networkHints.ts +27 -14
  109. package/src/cli/onboard.ts +69 -2
  110. package/src/cli/onboardTarget.ts +89 -40
  111. package/src/cli/templates/codex-skill-onboard.ts +44 -14
  112. package/src/cli/templates/skill-onboard.ts +64 -28
  113. package/src/cli.ts +184 -61
  114. package/src/components/ProxyViewer.tsx +11 -9
  115. package/src/components/ProxyViewerContainer.tsx +12 -11
  116. package/src/components/pi-agent/PiAgentPanel.tsx +2 -2
  117. package/src/components/providers/ProviderCard.tsx +1 -1
  118. package/src/components/providers/ProviderTestResultsView.tsx +1 -1
  119. package/src/components/providers/SettingsDialog.tsx +159 -144
  120. package/src/components/proxy-viewer/ApplicationBar.tsx +2 -1
  121. package/src/components/proxy-viewer/LogEntry.tsx +1 -1
  122. package/src/components/proxy-viewer/log-formats/index.ts +1 -1
  123. package/src/contracts/index.ts +5 -0
  124. package/src/contracts/log.ts +33 -3
  125. package/src/knowledge/types.ts +3 -2
  126. package/src/lib/alertContract.ts +2 -2
  127. package/src/lib/apiClient.ts +30 -7
  128. package/src/lib/apiFormat.ts +29 -0
  129. package/src/lib/basePath.ts +29 -11
  130. package/src/lib/browserRuntimeContract.ts +124 -0
  131. package/src/lib/browserRuntimeResolver.ts +244 -0
  132. package/src/{proxy → lib}/claudeCodeStrip.ts +6 -7
  133. package/src/lib/codingAgentEndpoints.ts +38 -0
  134. package/src/lib/instanceContract.ts +27 -11
  135. package/src/lib/piAgentContract.ts +3 -2
  136. package/src/lib/publicBasePathContext.ts +40 -10
  137. package/src/lib/resourceLimits.ts +2 -0
  138. package/src/lib/runContract.ts +3 -3
  139. package/src/lib/sessionInfoContract.ts +3 -2
  140. package/src/mcp/instanceHandlers.ts +1 -0
  141. package/src/mcp/server.ts +19 -24
  142. package/src/proxy/config.ts +25 -30
  143. package/src/proxy/dataDir.ts +43 -7
  144. package/src/proxy/ecosystemTasks.ts +161 -70
  145. package/src/proxy/formats/registry.ts +6 -21
  146. package/src/proxy/handler.ts +129 -29
  147. package/src/proxy/identityProxy.ts +419 -39
  148. package/src/proxy/jsonlRecovery.ts +554 -0
  149. package/src/proxy/logFinalizer.ts +25 -10
  150. package/src/proxy/logImporter.ts +2 -1
  151. package/src/proxy/logIndex.ts +191 -95
  152. package/src/proxy/logger.ts +77 -14
  153. package/src/proxy/platformCommands.ts +41 -0
  154. package/src/proxy/privateDataPath.ts +310 -88
  155. package/src/proxy/rawStreamCapture.ts +194 -13
  156. package/src/proxy/runtimeAdmission.ts +5 -2
  157. package/src/proxy/runtimeHealth.ts +14 -1
  158. package/src/proxy/runtimeShutdown.ts +11 -1
  159. package/src/proxy/schemas.ts +7 -1
  160. package/src/proxy/sessionArchive.ts +78 -14
  161. package/src/proxy/sqliteLogIndex.ts +65 -2
  162. package/src/proxy/store.ts +141 -34
  163. package/src/proxy/uiAssetServer.ts +106 -0
  164. package/src/proxy/upstream.ts +29 -2
  165. package/src/ui/bootstrap.ts +167 -0
  166. package/src/ui/index.html +38 -0
  167. package/src/ui/logsStreamClient.ts +20 -0
  168. package/src/ui/main.tsx +13 -0
  169. package/src/ui/public/runtime-config.js +2 -0
  170. package/src/ui/router.tsx +13 -0
  171. package/src/ui/routes/__root.tsx +69 -0
  172. package/src/{routes → ui/routes}/index.tsx +2 -3
  173. package/src/{routes → ui/routes}/session/$sessionId.tsx +5 -11
  174. package/src/ui/runtimeDiscovery.ts +50 -0
  175. package/styles/globals.css +1 -0
  176. package/.output/public/assets/ProxyViewerContainer-BEAhuGOJ.js +0 -126
  177. package/.output/public/assets/ResponseView-DBCjkwye.js +0 -2
  178. package/.output/public/assets/StreamingChunkSequence-CuXhDgMo.js +0 -1
  179. package/.output/public/assets/index-BZo_8koU.js +0 -70
  180. package/.output/public/assets/index-ZWschkCh.css +0 -1
  181. package/.output/public/assets/json-viewer-B-Ao6pwW.js +0 -1
  182. package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +0 -1
  183. package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +0 -344
  184. package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +0 -2
  185. package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +0 -2
  186. package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +0 -2
  187. package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +0 -11
  188. package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +0 -69
  189. package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +0 -1
  190. package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +0 -28
  191. package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +0 -6
  192. package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +0 -34
  193. package/.output/server/_libs/aria-hidden.mjs +0 -122
  194. package/.output/server/_libs/bail.mjs +0 -8
  195. package/.output/server/_libs/character-entities.mjs +0 -2130
  196. package/.output/server/_libs/class-variance-authority.mjs +0 -44
  197. package/.output/server/_libs/clsx.mjs +0 -16
  198. package/.output/server/_libs/comma-separated-tokens.mjs +0 -10
  199. package/.output/server/_libs/decode-named-character-reference+[...].mjs +0 -8
  200. package/.output/server/_libs/dequal.mjs +0 -27
  201. package/.output/server/_libs/detect-node-es.mjs +0 -1
  202. package/.output/server/_libs/devlop.mjs +0 -8
  203. package/.output/server/_libs/diff.mjs +0 -320
  204. package/.output/server/_libs/estree-util-is-identifier-name.mjs +0 -11
  205. package/.output/server/_libs/floating-ui__core.mjs +0 -725
  206. package/.output/server/_libs/floating-ui__dom.mjs +0 -622
  207. package/.output/server/_libs/floating-ui__react-dom.mjs +0 -292
  208. package/.output/server/_libs/floating-ui__utils.mjs +0 -320
  209. package/.output/server/_libs/get-nonce.mjs +0 -9
  210. package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +0 -388
  211. package/.output/server/_libs/hast-util-whitespace.mjs +0 -10
  212. package/.output/server/_libs/html-url-attributes.mjs +0 -26
  213. package/.output/server/_libs/inline-style-parser.mjs +0 -142
  214. package/.output/server/_libs/is-plain-obj.mjs +0 -10
  215. package/.output/server/_libs/lucide-react.mjs +0 -1027
  216. package/.output/server/_libs/mdast-util-from-markdown.mjs +0 -717
  217. package/.output/server/_libs/mdast-util-to-hast.mjs +0 -710
  218. package/.output/server/_libs/mdast-util-to-string.mjs +0 -38
  219. package/.output/server/_libs/micromark-core-commonmark.mjs +0 -2259
  220. package/.output/server/_libs/micromark-factory-destination.mjs +0 -94
  221. package/.output/server/_libs/micromark-factory-label.mjs +0 -63
  222. package/.output/server/_libs/micromark-factory-space.mjs +0 -24
  223. package/.output/server/_libs/micromark-factory-title.mjs +0 -65
  224. package/.output/server/_libs/micromark-factory-whitespace.mjs +0 -22
  225. package/.output/server/_libs/micromark-util-character.mjs +0 -44
  226. package/.output/server/_libs/micromark-util-chunked.mjs +0 -36
  227. package/.output/server/_libs/micromark-util-classify-character+[...].mjs +0 -12
  228. package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +0 -41
  229. package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -19
  230. package/.output/server/_libs/micromark-util-decode-string.mjs +0 -21
  231. package/.output/server/_libs/micromark-util-encode.mjs +0 -1
  232. package/.output/server/_libs/micromark-util-html-tag-name.mjs +0 -69
  233. package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +0 -6
  234. package/.output/server/_libs/micromark-util-resolve-all.mjs +0 -15
  235. package/.output/server/_libs/micromark-util-sanitize-uri.mjs +0 -41
  236. package/.output/server/_libs/micromark-util-subtokenize.mjs +0 -346
  237. package/.output/server/_libs/micromark.mjs +0 -906
  238. package/.output/server/_libs/property-information.mjs +0 -1209
  239. package/.output/server/_libs/radix-ui.mjs +0 -1
  240. package/.output/server/_libs/radix-ui__number.mjs +0 -6
  241. package/.output/server/_libs/radix-ui__primitive.mjs +0 -11
  242. package/.output/server/_libs/radix-ui__react-accordion.mjs +0 -1
  243. package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +0 -1
  244. package/.output/server/_libs/radix-ui__react-arrow.mjs +0 -23
  245. package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +0 -1
  246. package/.output/server/_libs/radix-ui__react-avatar.mjs +0 -1
  247. package/.output/server/_libs/radix-ui__react-checkbox.mjs +0 -1
  248. package/.output/server/_libs/radix-ui__react-collapsible.mjs +0 -144
  249. package/.output/server/_libs/radix-ui__react-collection.mjs +0 -69
  250. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +0 -38
  251. package/.output/server/_libs/radix-ui__react-context-menu.mjs +0 -1
  252. package/.output/server/_libs/radix-ui__react-context.mjs +0 -64
  253. package/.output/server/_libs/radix-ui__react-dialog.mjs +0 -280
  254. package/.output/server/_libs/radix-ui__react-direction.mjs +0 -9
  255. package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +0 -1
  256. package/.output/server/_libs/radix-ui__react-focus-guards.mjs +0 -39
  257. package/.output/server/_libs/radix-ui__react-focus-scope.mjs +0 -210
  258. package/.output/server/_libs/radix-ui__react-form.mjs +0 -1
  259. package/.output/server/_libs/radix-ui__react-hover-card.mjs +0 -1
  260. package/.output/server/_libs/radix-ui__react-id.mjs +0 -14
  261. package/.output/server/_libs/radix-ui__react-label.mjs +0 -1
  262. package/.output/server/_libs/radix-ui__react-menu.mjs +0 -1
  263. package/.output/server/_libs/radix-ui__react-menubar.mjs +0 -1
  264. package/.output/server/_libs/radix-ui__react-popover.mjs +0 -1
  265. package/.output/server/_libs/radix-ui__react-popper.mjs +0 -340
  266. package/.output/server/_libs/radix-ui__react-portal.mjs +0 -16
  267. package/.output/server/_libs/radix-ui__react-presence.mjs +0 -173
  268. package/.output/server/_libs/radix-ui__react-primitive.mjs +0 -42
  269. package/.output/server/_libs/radix-ui__react-progress.mjs +0 -1
  270. package/.output/server/_libs/radix-ui__react-radio-group.mjs +0 -1
  271. package/.output/server/_libs/radix-ui__react-roving-focus.mjs +0 -235
  272. package/.output/server/_libs/radix-ui__react-scroll-area.mjs +0 -731
  273. package/.output/server/_libs/radix-ui__react-select.mjs +0 -1207
  274. package/.output/server/_libs/radix-ui__react-separator.mjs +0 -28
  275. package/.output/server/_libs/radix-ui__react-slider.mjs +0 -1
  276. package/.output/server/_libs/radix-ui__react-slot.mjs +0 -132
  277. package/.output/server/_libs/radix-ui__react-switch.mjs +0 -1
  278. package/.output/server/_libs/radix-ui__react-tabs.mjs +0 -194
  279. package/.output/server/_libs/radix-ui__react-toast.mjs +0 -2
  280. package/.output/server/_libs/radix-ui__react-toggle-group.mjs +0 -1
  281. package/.output/server/_libs/radix-ui__react-toggle.mjs +0 -1
  282. package/.output/server/_libs/radix-ui__react-toolbar.mjs +0 -1
  283. package/.output/server/_libs/radix-ui__react-tooltip.mjs +0 -498
  284. package/.output/server/_libs/radix-ui__react-use-previous.mjs +0 -14
  285. package/.output/server/_libs/radix-ui__react-use-size.mjs +0 -39
  286. package/.output/server/_libs/react-markdown.mjs +0 -235
  287. package/.output/server/_libs/react-remove-scroll-bar.mjs +0 -82
  288. package/.output/server/_libs/react-remove-scroll.mjs +0 -328
  289. package/.output/server/_libs/react-style-singleton.mjs +0 -69
  290. package/.output/server/_libs/remark-parse.mjs +0 -19
  291. package/.output/server/_libs/remark-rehype.mjs +0 -21
  292. package/.output/server/_libs/space-separated-tokens.mjs +0 -6
  293. package/.output/server/_libs/style-to-js.mjs +0 -72
  294. package/.output/server/_libs/style-to-object.mjs +0 -38
  295. package/.output/server/_libs/swr.mjs +0 -947
  296. package/.output/server/_libs/tailwind-merge.mjs +0 -3255
  297. package/.output/server/_libs/tanstack__react-virtual.mjs +0 -130
  298. package/.output/server/_libs/tanstack__virtual-core.mjs +0 -1319
  299. package/.output/server/_libs/three.mjs +0 -26016
  300. package/.output/server/_libs/trim-lines.mjs +0 -41
  301. package/.output/server/_libs/trough.mjs +0 -85
  302. package/.output/server/_libs/tslib.mjs +0 -1
  303. package/.output/server/_libs/ungap__structured-clone.mjs +0 -212
  304. package/.output/server/_libs/unified.mjs +0 -661
  305. package/.output/server/_libs/unist-util-is.mjs +0 -100
  306. package/.output/server/_libs/unist-util-position.mjs +0 -27
  307. package/.output/server/_libs/unist-util-stringify-position.mjs +0 -27
  308. package/.output/server/_libs/unist-util-visit-parents.mjs +0 -82
  309. package/.output/server/_libs/unist-util-visit.mjs +0 -24
  310. package/.output/server/_libs/use-callback-ref.mjs +0 -66
  311. package/.output/server/_libs/use-sidecar.mjs +0 -106
  312. package/.output/server/_libs/vfile-message.mjs +0 -138
  313. package/.output/server/_libs/vfile.mjs +0 -467
  314. package/.output/server/_sessionId-CJ99gZFV.mjs +0 -84
  315. package/.output/server/_sessionId-DEjScBpK.mjs +0 -146
  316. package/.output/server/_ssr/CompareDrawer-DtOIMeQB.mjs +0 -1060
  317. package/.output/server/_ssr/InspectorPet-CXc4oCBQ.mjs +0 -938
  318. package/.output/server/_ssr/ProxyViewerContainer-DVPlwfkt.mjs +0 -17632
  319. package/.output/server/_ssr/ReplayDialog-BQEA95qC.mjs +0 -725
  320. package/.output/server/_ssr/RequestAnatomy-BMyd8B7Q.mjs +0 -837
  321. package/.output/server/_ssr/ResponseView-qrTaEIM8.mjs +0 -757
  322. package/.output/server/_ssr/StreamingChunkSequence-BFTL8mIy.mjs +0 -274
  323. package/.output/server/_ssr/index-Bcj1Hcy4.mjs +0 -135
  324. package/.output/server/_ssr/index-DW-M7XUG.mjs +0 -84
  325. package/.output/server/_ssr/json-viewer-DiI0Yjsn.mjs +0 -483
  326. package/.output/server/_tanstack-start-manifest_v-C6pXXX9R.mjs +0 -4
  327. package/.output/server/node_modules/tslib/modules/index.js +0 -70
  328. package/.output/server/node_modules/tslib/modules/package.json +0 -3
  329. package/.output/server/node_modules/tslib/package.json +0 -47
  330. package/.output/server/node_modules/tslib/tslib.js +0 -484
  331. package/.output/server/package.json +0 -9
  332. package/src/routes/__root.tsx +0 -170
  333. /package/.output/{public → ui}/assets/agent-inspector-58K1_MsC.ico +0 -0
  334. /package/.output/{public → ui}/assets/alibaba-TTwafVwX.svg +0 -0
  335. /package/.output/{public → ui}/assets/minimax-BPMzvuL-.jpeg +0 -0
  336. /package/.output/{public → ui}/assets/qwen-mMn3f5ul.webp +0 -0
  337. /package/.output/{public → ui}/assets/zhipuai-BPNAnxo-.svg +0 -0
  338. /package/src/{routes → backend/routes}/livez.ts +0 -0
@@ -24,8 +24,14 @@ export type SkillOnboardContext = {
24
24
  readonly version: string;
25
25
  /** The default proxy port (mirrors `DEFAULT_PORT` in `src/cli.ts`). */
26
26
  readonly port: number;
27
- /** Public UI base URL, including the configured base path. */
27
+ /** Public backend control/agent Base URL, including the configured Base Path. */
28
28
  readonly baseUrl: string;
29
+ /** Optional composed or standalone UI URL. Undefined preserves the legacy composed default. */
30
+ readonly uiUrl?: string | null;
31
+ /** REST/SSE Base URL. Falls back to baseUrl for compatibility. */
32
+ readonly controlBaseUrl?: string;
33
+ /** Proxy/MCP Base URL. Falls back to baseUrl for compatibility. */
34
+ readonly agentBaseUrl?: string;
29
35
  /** MCP config key selected by onboarding. */
30
36
  readonly mcpName?: string;
31
37
  /** Selected onboarding target type. */
@@ -56,24 +62,29 @@ export const REQUIRED_PHASE_HEADINGS = [
56
62
  ] as const;
57
63
 
58
64
  export function renderSkillOnboard(ctx: SkillOnboardContext): string {
59
- const { version, port, baseUrl, detectedSummary } = ctx;
65
+ const { version, port, detectedSummary } = ctx;
66
+ const controlBaseUrl = ctx.controlBaseUrl ?? ctx.baseUrl;
67
+ const agentBaseUrl = ctx.agentBaseUrl ?? ctx.baseUrl;
68
+ const uiUrl = ctx.uiUrl === undefined ? ctx.baseUrl : ctx.uiUrl;
60
69
  const mcpName = ctx.mcpName ?? "agent-inspector";
61
70
  const targetKind = ctx.targetKind ?? "default";
62
71
  const targetArguments = ctx.onboardTargetArguments ?? "";
63
72
  const instanceName = ctx.instanceName ?? null;
64
- const healthUrl = `${baseUrl}/api/health`;
65
- const configUrl = `${baseUrl}/api/config`;
66
- const anthropicProxyUrl = `${baseUrl}/proxy`;
67
- const openAiProxyUrl = `${baseUrl}/proxy/v1`;
68
- const mcpUrl = `${baseUrl}/api/mcp`;
69
- const logsUrl = `${baseUrl}/api/logs`;
73
+ const healthUrl = `${controlBaseUrl}/api/health`;
74
+ const runtimeUrl = `${controlBaseUrl}/api/runtime`;
75
+ const configUrl = `${controlBaseUrl}/api/config`;
76
+ const anthropicProxyUrl = `${agentBaseUrl}/proxy`;
77
+ const openAiProxyUrl = `${agentBaseUrl}/proxy/v1`;
78
+ const mcpUrl = `${agentBaseUrl}/api/mcp`;
79
+ const logsUrl = `${controlBaseUrl}/api/logs`;
80
+ const providersUrl = `${controlBaseUrl}/api/providers`;
70
81
  const statusCommand = `agent-inspector onboard --status${targetArguments}`;
71
82
  const refreshCommand = `agent-inspector onboard --force${targetArguments}`;
72
83
  const startCommand =
73
84
  targetKind === "instance" && instanceName !== null
74
85
  ? `agent-inspector instance start ${instanceName}`
75
86
  : targetKind === "base-url"
76
- ? `# Explicit target ${baseUrl}: do not start a replacement local runtime.`
87
+ ? `# Explicit control target ${controlBaseUrl}: do not start a replacement local runtime.`
77
88
  : "agent-inspector --mode simple --background --no-open";
78
89
  const fullModeCommand =
79
90
  targetKind === "instance" && instanceName !== null
@@ -95,17 +106,27 @@ if (-not $found) { throw 'agent-inspector is not on PATH' }
95
106
  & $found.Source ${windowsStartArguments}`;
96
107
  const startExplanation =
97
108
  targetKind === "base-url"
98
- ? `The selected Inspector target is the explicit Base URL \`${baseUrl}\`. Do not launch a default local runtime as a substitute; verify the selected target and ask its operator for help if it is unavailable.`
99
- : `Start or reuse the selected Inspector runtime. It listens on port ${String(port)} and preserves the selected Base Path. Use \`${fullModeCommand}\` only when the user needs raw headers, raw response, or SSE chunks.`;
109
+ ? `The selected Inspector target uses control Base URL \`${controlBaseUrl}\` and agent Base URL \`${agentBaseUrl}\`. Do not launch a default local runtime as a substitute; verify the selected target and ask its operator for help if it is unavailable.`
110
+ : `Start or reuse the selected Inspector backend. Its public control and agent endpoints preserve the selected Base Path; a Web UI may be composed at the same URL, hosted separately, or intentionally absent in backend-only mode. Use \`${fullModeCommand}\` only when the user needs raw headers, raw response, or SSE chunks.`;
100
111
  const stopSnippet =
101
112
  targetKind === "instance" && instanceName !== null
102
113
  ? `agent-inspector instance stop ${instanceName}`
103
114
  : targetKind === "base-url"
104
- ? `# Ask the operator of ${baseUrl} to stop the selected runtime.`
115
+ ? `# Ask the operator of ${controlBaseUrl} to stop the selected runtime.`
105
116
  : `# Unix / macOS\n lsof -ti:${String(port)} | xargs -r kill -9\n\n # Windows PowerShell\n Get-NetTCPConnection -LocalPort ${String(port)} | ForEach-Object { Stop-Process -Id $_.OwningProcess -Force }`;
117
+ const providerScopeGuidance =
118
+ targetKind === "default"
119
+ ? "The unmanaged default target owns the local Agent Inspector data directory used by the file checks below."
120
+ : `The selected target is not the unmanaged default data directory. Do not inspect or edit local ~/.agent-inspector Provider files as a substitute. Query \`${providersUrl}\`, use the selected target's MCP Provider tools with explicit approval, or ask its operator to configure Providers. Skip local-file commands below.`;
121
+ const selectedUi =
122
+ uiUrl === null ? "not supplied (do not infer one from a backend URL)" : `\`${uiUrl}\``;
123
+ const uiTour =
124
+ uiUrl === null
125
+ ? "not supplied; continue with MCP/REST, and ask the operator for a standalone UI URL only if the user needs one"
126
+ : `\`${uiUrl}\` — use this explicit composed or standalone browser URL; do not replace it with the control or agent Base URL`;
106
127
  return `---
107
128
  name: agent-inspector-onboard
108
- description: Guided setup for Agent Inspector v${version}: start the proxy, wire your AI coding tool, capture your first request, and learn the Web UI.
129
+ description: Guided setup for Agent Inspector v${version}: start or select the backend, wire your AI coding tool, and capture your first request with or without a Web UI.
109
130
  metadata:
110
131
  author: agent-inspector
111
132
  version: ${version}
@@ -113,12 +134,16 @@ metadata:
113
134
 
114
135
  # Agent Inspector onboard
115
136
 
116
- Guide the user from "I just installed Agent Inspector" to "I can see my AI tool's traffic in the Web UI". This is a teaching experience: you'll do real work in their environment while explaining each step.
137
+ Guide the user from "I just installed Agent Inspector" to "my coding agent can use the proxy, REST API, and MCP surface". The backend works in composed and headless deployments; treat the Web UI as an optional presentation surface.
117
138
 
118
139
  Environment detected by the installer:
119
140
  ${detectedSummary || " (no known AI tool detected — the user can still use the generic curl example in Phase 4)"}
120
141
 
121
- Selected Inspector target: \`${baseUrl}\` (MCP key: \`${mcpName}\`).
142
+ Selected Inspector surfaces:
143
+ - UI URL: ${selectedUi}
144
+ - Control Base URL: \`${controlBaseUrl}\`
145
+ - Agent Base URL: \`${agentBaseUrl}\`
146
+ - MCP key: \`${mcpName}\`
122
147
 
123
148
  > **PAUSE protocol.** Every \`**PAUSE**\` marker in this skill is a real stop.
124
149
  > Use the \`AskUserQuestion\` tool to actually wait for the user before
@@ -146,9 +171,11 @@ ${statusCommand}
146
171
 
147
172
  **DO:** Then probe the three pieces of state this skill touches. Use targeted checks — do **not** read large JSON files into the conversation.
148
173
 
174
+ **DO:** ${providerScopeGuidance}
175
+
149
176
  \`\`\`bash
150
- # 1. Is the proxy already up?
151
- curl -fsS "${healthUrl}" 2>/dev/null && echo "PROXY: up" || echo "PROXY: down"
177
+ # 1. Is the backend already up?
178
+ curl -fsS "${healthUrl}" 2>/dev/null && echo "BACKEND: up" || echo "BACKEND: down"
152
179
 
153
180
  # 2. Does the provider config have a real provider key?
154
181
  agent_inspector_data_dir() {
@@ -209,12 +236,12 @@ $dataDir = Resolve-AgentInspectorDataDir
209
236
  $providers = Join-Path $dataDir 'providers.json'
210
237
  $legacyConfig = Join-Path $dataDir 'config.json'
211
238
 
212
- # 1. Is the proxy already up?
239
+ # 1. Is the backend already up?
213
240
  try {
214
241
  $null = Invoke-RestMethod -Uri "${healthUrl}" -TimeoutSec 2 -ErrorAction Stop
215
- Write-Host 'PROXY: up'
242
+ Write-Host 'BACKEND: up'
216
243
  } catch {
217
- Write-Host 'PROXY: down'
244
+ Write-Host 'BACKEND: down'
218
245
  }
219
246
 
220
247
  # 2. Does the config have a real provider key?
@@ -284,7 +311,7 @@ node -e "const fs=require('node:fs'),p=require('node:path');const names=process.
284
311
  \`\`\`
285
312
  ## Welcome to Agent Inspector!
286
313
 
287
- Agent Inspector is an agent observability and knowledge-capture platform for AI coding tools. The \`agent-inspector\` CLI runs a transparent local proxy + Web UI, so you can see model requests and responses, system prompts, tool definitions, message history, timing, and token counts captured live in a browser tab.
314
+ Agent Inspector is an agent observability and knowledge-capture platform for AI coding tools. Its backend owns the transparent model proxy, REST/SSE APIs, capture storage, and MCP server. The default CLI composes a Web UI at the same public Base URL, while \`--backend-only\` keeps every Coding Agent surface available without serving UI files.
288
315
 
289
316
  Agent Inspector starts in **Simple mode** by default. Simple mode is the right habit for everyday use: it keeps requests, responses, tools, timing, and token usage while avoiding heavier raw headers, raw response, and detailed SSE chunk artifacts. Use **Full mode** only when the user is debugging provider headers, raw response payloads, or SSE stream details.
290
317
 
@@ -304,6 +331,8 @@ Ready? Let's start with the provider.
304
331
 
305
332
  ## Phase 2: Provider setup
306
333
 
334
+ **DO:** ${providerScopeGuidance}
335
+
307
336
  **EXPLAIN:** "A 'provider' is an upstream LLM endpoint — Anthropic, OpenAI, MiniMax, etc. agent-inspector routes each request to the right upstream based on the model name. You need at least one provider configured for the proxy to forward traffic."
308
337
 
309
338
  **DO:** First, re-check whether \`<dataDir>/providers.json\` already has a real key (Phase 0 may have raced with a manual edit). Use the same data-dir resolution and \`grep -qE '"apiKey":"sk-'\` (bash) or \`Select-String\` (PowerShell) check from Phase 0. If a real key is present, skip the rest of this phase.
@@ -399,7 +428,7 @@ $json | Set-Content -Path $file -Encoding UTF8
399
428
 
400
429
  **EXPLAIN:** "${startExplanation}"
401
430
 
402
- **DO:** Skip this phase entirely if the Phase 0 health check already reported \`PROXY: up\` and the user opted to skip done phases.
431
+ **DO:** Skip this phase entirely if the Phase 0 health check already reported \`BACKEND: up\` and the user opted to skip done phases.
403
432
 
404
433
  **DO:** Otherwise, use the selected target command below. An explicit wrapper Base URL is connection-only and must not cause a replacement local runtime to start.
405
434
 
@@ -412,7 +441,7 @@ ${bashStartSnippet}
412
441
  ${powershellStartSnippet}
413
442
  \`\`\`
414
443
 
415
- Then wait for the port to be ready:
444
+ Then wait for the selected backend health URL to be ready:
416
445
 
417
446
  \`\`\`bash
418
447
  for i in $(seq 1 20); do
@@ -421,12 +450,18 @@ for i in $(seq 1 20); do
421
450
  done
422
451
  \`\`\`
423
452
 
424
- **DO:** Hit the health endpoint to confirm the proxy is alive:
453
+ **DO:** Hit the health endpoint to confirm the backend is alive:
425
454
 
426
455
  \`\`\`bash
427
456
  curl -sS "${healthUrl}"
428
457
  \`\`\`
429
458
 
459
+ **DO:** Read the token-free runtime discovery document. Report \`deploymentMode\` and capabilities; do not treat \`backend-only\` as a failure or infer that a UI is present.
460
+
461
+ \`\`\`bash
462
+ curl -sS "${runtimeUrl}"
463
+ \`\`\`
464
+
430
465
  **DO:** Read \`/api/config\` and tell the user which capture mode is active. If deeper capture is required, offer \`${fullModeCommand}\`.
431
466
 
432
467
  \`\`\`bash
@@ -566,10 +601,11 @@ done
566
601
 
567
602
  ## Phase 6: Tour & wrap
568
603
 
569
- **EXPLAIN:** "Everything's working. Here's the cheat sheet for the Web UI and the supporting surfaces:"
604
+ **EXPLAIN:** "Everything's working. Here's the cheat sheet for the backend surfaces and the optional Web UI:"
570
605
 
571
- - **Web UI**: \`${baseUrl}\` — collapsible log rows, per-tab Copy/Expand in the log header, Diff with Raw (request body), Diff with Previous (compare adjacent requests), Replay (re-send a request), Export (JSON ZIP).
572
- - **MCP server**: \`${mcpUrl}\` — connect from your coding agent to query logs, replay, and test providers without leaving the editor. Look for the "MCP Ready" badge in the Web UI header.
606
+ - **Runtime discovery**: \`${runtimeUrl}\` — token-free deployment mode, UI Base Path, control/agent Base URLs, and capabilities.
607
+ - **Web UI**: ${uiTour}.
608
+ - **MCP server**: \`${mcpUrl}\` — connect from the coding agent to query logs, replay, and test providers; it does not require a Web UI process.
573
609
  - **REST API**: \`/api/logs\`, \`/api/sessions\`, \`/api/providers\` — for scripting and shell-based inspection.
574
610
  - **Stop the proxy**:
575
611
 
@@ -580,7 +616,7 @@ ${stopSnippet}
580
616
  - **Re-run onboard**: \`${refreshCommand}\` refreshes this skill.
581
617
  - **Check onboard files**: \`${statusCommand}\` shows whether generated skills are
582
618
  current, outdated, missing, newer, or custom.
583
- - **Full docs**: see the project README (linked from the Web UI footer).
619
+ - **Full docs**: see the project README; do not depend on a UI footer being available.
584
620
 
585
621
  > **PAUSE** — use \`AskUserQuestion\` with header \`All set?\` and options \`["All set, I'm done", "Wait, I want to revisit a phase"]\`. Wait for the answer.
586
622
 
package/src/cli.ts CHANGED
@@ -8,9 +8,11 @@ import { existsSync } from "node:fs";
8
8
  import type { Readable, Writable } from "node:stream";
9
9
  import packageJson from "../package.json";
10
10
  import {
11
+ AGENT_INSPECTOR_BASE_PATH_ENV,
11
12
  AGENT_INSPECTOR_INTERNAL_STRIPPED_BASE_PATH_ENV,
12
13
  appendBasePathToOrigin,
13
14
  getConfiguredBasePath,
15
+ normalizePublicBasePath,
14
16
  } from "./lib/basePath.js";
15
17
  import {
16
18
  AGENT_INSPECTOR_CLI_ENTRY_ENV,
@@ -34,6 +36,7 @@ import {
34
36
  import {
35
37
  closeIdentityProxyGracefully,
36
38
  forceCloseIdentityProxy,
39
+ parseUiOriginAllowlist,
37
40
  startIdentityProxy,
38
41
  stopIdentityProxyAdmission,
39
42
  type ManagedInstanceControlOptions,
@@ -83,6 +86,14 @@ Global options:
83
86
  -h, --help Show this help without starting a runtime
84
87
  -v, --version Print the package version
85
88
 
89
+ Start options:
90
+ --backend-only, --headless Start the API, proxy, and MCP runtime without serving the UI
91
+ --with-ui Serve the independently built UI through the protected ingress
92
+ --port, -p <port> Public ingress port (default: 9527)
93
+ --host, -H <host> Bind host (default: 127.0.0.1)
94
+ --background Start a hidden supervisor and return after readiness
95
+ --no-open Do not open the UI after startup
96
+
86
97
  Run \`agent-inspector instance --help\`, \`agent-inspector onboard --help\`, or
87
98
  \`agent-inspector doctor --help\` for command-specific options.`);
88
99
  }
@@ -309,11 +320,26 @@ function readCaptureMode(raw: unknown): CaptureMode | null {
309
320
  return typeof value === "string" ? parseCaptureMode(value) : null;
310
321
  }
311
322
 
312
- function printAccessHints(port: number, host?: string, basePath = ""): void {
323
+ function printAccessHints(
324
+ port: number,
325
+ host: string | undefined,
326
+ basePath: string,
327
+ serveUi: boolean,
328
+ publicOrigin: string | undefined,
329
+ ): void {
313
330
  const networkUrls = networkUrlsForBindHost(port, host);
314
- for (const line of formatAccessHintLines(port, networkUrls, host, basePath)) {
331
+ for (const line of formatAccessHintLines(port, networkUrls, host, basePath, serveUi)) {
315
332
  console.log(line);
316
333
  }
334
+ if (publicOrigin !== undefined) {
335
+ const publicBaseUrl = appendBasePathToOrigin(publicOrigin, "/", basePath);
336
+ if (serveUi) console.log(` Public UI: ${publicBaseUrl}`);
337
+ console.log(` Public control Base: ${publicBaseUrl}`);
338
+ console.log(` Public agent Base: ${publicBaseUrl}`);
339
+ console.log(` Public REST API: ${appendBasePathToOrigin(publicOrigin, "/api", basePath)}`);
340
+ console.log(` Public proxy: ${appendBasePathToOrigin(publicOrigin, "/proxy", basePath)}`);
341
+ console.log(` Public MCP: ${appendBasePathToOrigin(publicOrigin, "/api/mcp", basePath)}`);
342
+ }
317
343
  if (!isLoopbackHost(host)) {
318
344
  const proxyTokenConfigured = (process.env["AGENT_INSPECTOR_PROXY_TOKEN"] ?? "") !== "";
319
345
  const legacyProxyEnabled =
@@ -345,6 +371,19 @@ function readPositiveIntegerEnv(name: string): number | undefined {
345
371
  return undefined;
346
372
  }
347
373
 
374
+ function normalizeExplicitPublicOrigin(value: string | undefined): string | null | undefined {
375
+ if (value === undefined || value.trim().length === 0) return undefined;
376
+ try {
377
+ const parsed = new URL(value.trim());
378
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
379
+ if (parsed.username.length > 0 || parsed.password.length > 0) return null;
380
+ if (parsed.pathname !== "/" || parsed.search.length > 0 || parsed.hash.length > 0) return null;
381
+ return parsed.origin;
382
+ } catch {
383
+ return null;
384
+ }
385
+ }
386
+
348
387
  type BackgroundSupervisorOptions = {
349
388
  port: number;
350
389
  host: string | undefined;
@@ -353,6 +392,7 @@ type BackgroundSupervisorOptions = {
353
392
  captureMode: CaptureMode;
354
393
  enableIdentityProxy: boolean;
355
394
  legacyAliasEnabled: boolean;
395
+ serveUi: boolean;
356
396
  };
357
397
 
358
398
  function buildBackgroundSupervisorArgs(options: BackgroundSupervisorOptions): string[] {
@@ -372,6 +412,9 @@ function buildBackgroundSupervisorArgs(options: BackgroundSupervisorOptions): st
372
412
  if (options.legacyAliasEnabled) {
373
413
  args.push("--legacy-port");
374
414
  }
415
+ if (!options.serveUi) {
416
+ args.push("--backend-only");
417
+ }
375
418
  return args;
376
419
  }
377
420
 
@@ -395,17 +438,17 @@ function pickUpstreamPort(publicPort: number, legacyAliasPort: number | null): n
395
438
  return DEFAULT_UPSTREAM_PORT;
396
439
  }
397
440
 
398
- /** Try to start the identity proxy. Returns `null` (and prints a warning)
399
- * if the listen port is already in use by another process — e.g. when
400
- * restarting a previous instance that didn't shut down cleanly. The
401
- * TanStack Start server keeps running either way; clients just lose the
402
- * per-PID attribution until they fall back to direct port `port` access. */
441
+ /** Try to start an identity-proxy ingress. The primary caller treats a
442
+ * `null` result as fatal; only an optional compatibility alias may degrade. */
403
443
  async function tryStartIdentityProxy(
404
444
  identityPort: number,
405
445
  upstreamPort: number,
406
446
  listenHost: string,
407
447
  upstreamHost: string,
408
448
  managedInstance: ManagedInstanceControlOptions | undefined,
449
+ allowedUiOrigins: readonly string[],
450
+ uiDirectory: string | undefined,
451
+ publicOrigin: string | undefined,
409
452
  ): Promise<import("node:http").Server | null> {
410
453
  try {
411
454
  const server = await startIdentityProxy({
@@ -423,6 +466,9 @@ async function tryStartIdentityProxy(
423
466
  .split(",")
424
467
  .map((host) => host.trim())
425
468
  .filter((host) => host.length > 0),
469
+ allowedUiOrigins,
470
+ uiDirectory,
471
+ publicOrigin,
426
472
  maxRequestBytes: readPositiveIntegerEnv("AGENT_INSPECTOR_MAX_REQUEST_BYTES"),
427
473
  requestTimeoutMs: readPositiveIntegerEnv("AGENT_INSPECTOR_REQUEST_TIMEOUT_MS"),
428
474
  managedInstance,
@@ -430,11 +476,7 @@ async function tryStartIdentityProxy(
430
476
  return server;
431
477
  } catch (err) {
432
478
  const message = err instanceof Error ? err.message : String(err);
433
- console.warn(
434
- `[identity-proxy] Could not listen on port ${identityPort}: ${message}. ` +
435
- `Falling back to OS-scan heuristic on port ${upstreamPort}. ` +
436
- `Pass --identity-proxy-port <n> to choose another port, or --no-identity-proxy to disable.`,
437
- );
479
+ console.warn(`[identity-proxy] Could not listen on port ${identityPort}: ${message}.`);
438
480
  return null;
439
481
  }
440
482
  }
@@ -467,6 +509,7 @@ async function runStart(args: string[]): Promise<void> {
467
509
  let captureModeWasSpecified = false;
468
510
  let enableIdentityProxy = true;
469
511
  let legacyAliasEnabled = false;
512
+ let serveUi = process.env["AGENT_INSPECTOR_BACKEND_ONLY"] !== "1";
470
513
 
471
514
  if (envMode !== undefined && envMode !== "") {
472
515
  const parsedMode = parseCaptureMode(envMode);
@@ -546,6 +589,14 @@ async function runStart(args: string[]): Promise<void> {
546
589
  case "--background":
547
590
  background = true;
548
591
  break;
592
+ case "--backend-only":
593
+ case "--headless":
594
+ serveUi = false;
595
+ open = false;
596
+ break;
597
+ case "--with-ui":
598
+ serveUi = true;
599
+ break;
549
600
  case "--config-dir":
550
601
  configDir = args[i + 1];
551
602
  i++;
@@ -618,6 +669,40 @@ async function runStart(args: string[]): Promise<void> {
618
669
  process.exitCode = 1;
619
670
  return;
620
671
  }
672
+ if (!serveUi) open = false;
673
+ if (!enableIdentityProxy && serveUi) {
674
+ console.error(
675
+ "The decoupled UI is composed only by the protected ingress. Use --backend-only with --no-identity-proxy, or keep the identity proxy enabled.",
676
+ );
677
+ process.exitCode = 1;
678
+ return;
679
+ }
680
+ const uiOriginAllowlist = parseUiOriginAllowlist(process.env["AGENT_INSPECTOR_UI_ORIGINS"]);
681
+ if (uiOriginAllowlist.rejected.length > 0) {
682
+ console.error(
683
+ `Invalid AGENT_INSPECTOR_UI_ORIGINS entries: ${uiOriginAllowlist.rejected.join(", ")}. Only exact loopback http(s) origins are accepted; use a same-origin authenticated gateway for remote UI hosting.`,
684
+ );
685
+ process.exitCode = 1;
686
+ return;
687
+ }
688
+ const publicOrigin = normalizeExplicitPublicOrigin(process.env["AGENT_INSPECTOR_PUBLIC_ORIGIN"]);
689
+ if (publicOrigin === null) {
690
+ console.error(
691
+ "Invalid AGENT_INSPECTOR_PUBLIC_ORIGIN. Use an exact http(s) origin without credentials, path, query, or fragment.",
692
+ );
693
+ process.exitCode = 1;
694
+ return;
695
+ }
696
+ const uiDirectoryCandidate = join(__dirname, "../.output/ui");
697
+ const uiIndexPath = join(uiDirectoryCandidate, "index.html");
698
+ const uiDirectory = serveUi && existsSync(uiIndexPath) ? uiDirectoryCandidate : undefined;
699
+ if (serveUi && uiDirectory === undefined) {
700
+ console.error(
701
+ `Agent Inspector UI artifact is missing at ${uiIndexPath}. Run the composed build or use --backend-only.`,
702
+ );
703
+ process.exitCode = 1;
704
+ return;
705
+ }
621
706
 
622
707
  /**
623
708
  * Check if a port is in use and kill the process using it
@@ -655,11 +740,22 @@ async function runStart(args: string[]): Promise<void> {
655
740
  const upstreamHost = enableIdentityProxy ? DEFAULT_BIND_HOST : host;
656
741
  process.env["PORT"] = String(upstreamPort);
657
742
 
743
+ const configuredBasePath = process.env[AGENT_INSPECTOR_BASE_PATH_ENV];
744
+ if (configuredBasePath !== undefined && normalizePublicBasePath(configuredBasePath) === null) {
745
+ console.error(
746
+ `Invalid ${AGENT_INSPECTOR_BASE_PATH_ENV}. Use / for root or URL-safe path segments such as /inspector or /foo-bar/v1.`,
747
+ );
748
+ process.exitCode = 1;
749
+ return;
750
+ }
658
751
  const basePath = getConfiguredBasePath(process.env);
659
- const url = urlForHost(port, host);
660
- const uiUrl = appendBasePathToOrigin(url, "/", basePath);
661
- const proxyUrl = appendBasePathToOrigin(url, "/proxy", basePath);
662
- const proxyMessagesUrl = appendBasePathToOrigin(url, "/proxy/v1/messages", basePath);
752
+ const bindOrigin = urlForHost(port, host);
753
+ const outwardOrigin = publicOrigin ?? bindOrigin;
754
+ const surfaceBaseUrl = appendBasePathToOrigin(outwardOrigin, "/", basePath);
755
+ const uiUrl = serveUi ? surfaceBaseUrl : null;
756
+ const proxyUrl = appendBasePathToOrigin(outwardOrigin, "/proxy", basePath);
757
+ const openAiProxyUrl = appendBasePathToOrigin(outwardOrigin, "/proxy/v1", basePath);
758
+ const proxyMessagesUrl = appendBasePathToOrigin(outwardOrigin, "/proxy/v1/messages", basePath);
663
759
  const legacyUrl =
664
760
  legacyAliasPort === null
665
761
  ? null
@@ -674,8 +770,10 @@ async function runStart(args: string[]): Promise<void> {
674
770
  : appendBasePathToOrigin(localUrlForPort(legacyAliasPort), "/api/mcp", basePath);
675
771
 
676
772
  if (!forceRestart && (await isInspectorHealthy(port, host, basePath))) {
677
- console.log(`agent-inspector is already running at ${uiUrl}`);
678
- printAccessHints(port, host, basePath);
773
+ console.log(
774
+ `agent-inspector ${serveUi ? "is already running" : "backend is already running"} at ${surfaceBaseUrl}`,
775
+ );
776
+ printAccessHints(port, host, basePath, serveUi, publicOrigin);
679
777
  if (captureModeWasSpecified) {
680
778
  const runningMode = await getRunningCaptureMode(port, host, basePath);
681
779
  if (runningMode !== null && runningMode !== captureMode) {
@@ -684,7 +782,7 @@ async function runStart(args: string[]): Promise<void> {
684
782
  }
685
783
  }
686
784
  console.log(`Use --force-restart to restart the existing instance.`);
687
- if (open && openWasSpecified) {
785
+ if (open && openWasSpecified && uiUrl !== null) {
688
786
  openBrowser(uiUrl);
689
787
  }
690
788
  return;
@@ -725,6 +823,7 @@ async function runStart(args: string[]): Promise<void> {
725
823
  captureMode,
726
824
  enableIdentityProxy,
727
825
  legacyAliasEnabled,
826
+ serveUi,
728
827
  });
729
828
  const supervisorProcess = spawn(process.execPath, [cliEntry, ...supervisorArgs], {
730
829
  stdio: "ignore",
@@ -738,8 +837,10 @@ async function runStart(args: string[]): Promise<void> {
738
837
  supervisorProcess.unref();
739
838
 
740
839
  if (await waitForInspectorHealthy(port, 10000, host, basePath)) {
741
- console.log(`agent-inspector background server is ready at ${uiUrl}`);
742
- printAccessHints(port, host, basePath);
840
+ console.log(
841
+ `agent-inspector background ${serveUi ? "server" : "backend"} is ready at ${surfaceBaseUrl}`,
842
+ );
843
+ printAccessHints(port, host, basePath, serveUi, publicOrigin);
743
844
  if (legacyProxyUrl !== null && legacyMcpUrl !== null) {
744
845
  console.log(` Legacy proxy: ${legacyProxyUrl}`);
745
846
  console.log(` Legacy MCP: ${legacyMcpUrl}`);
@@ -748,48 +849,18 @@ async function runStart(args: string[]): Promise<void> {
748
849
  console.log(`Route AI coding tools through the identity proxy for accurate PID attribution:`);
749
850
  console.log(` Claude Code: ANTHROPIC_BASE_URL=${proxyUrl} claude`);
750
851
  console.log(` OpenCode: LLM_BASE_URL=${proxyUrl} opencode`);
751
- console.log(` MiMo Code: OPENAI_BASE_URL=${proxyUrl} mimo`);
752
- if (open && openWasSpecified) {
852
+ console.log(` MiMo Code: OPENAI_BASE_URL=${openAiProxyUrl} mimo`);
853
+ if (open && openWasSpecified && uiUrl !== null) {
753
854
  openBrowser(uiUrl);
754
855
  }
755
856
  return;
756
857
  }
757
858
 
758
- console.error(`agent-inspector background server did not become ready at ${uiUrl}.`);
859
+ console.error(`agent-inspector background server did not become ready at ${surfaceBaseUrl}.`);
759
860
  process.exitCode = 1;
760
861
  return;
761
862
  }
762
863
 
763
- console.log(`Server running at ${uiUrl}`);
764
- console.log(` Capture mode: ${captureMode}`);
765
- console.log(` Proxy: ${proxyUrl}`);
766
- printAccessHints(port, host, basePath);
767
- if (legacyUrl !== null && legacyProxyUrl !== null && legacyMcpUrl !== null) {
768
- console.log(` Legacy UI: ${legacyUrl}`);
769
- console.log(` Legacy proxy: ${legacyProxyUrl}`);
770
- console.log(` Legacy MCP: ${legacyMcpUrl}`);
771
- }
772
- console.log(``);
773
- console.log(`Route AI coding tools through the proxy:`);
774
- console.log(` Claude Code: ANTHROPIC_BASE_URL=${proxyUrl} claude`);
775
- console.log(` OpenCode: LLM_BASE_URL=${proxyUrl} opencode`);
776
- console.log(` MiMo Code: OPENAI_BASE_URL=${proxyUrl} mimo`);
777
- console.log(` Direct HTTP: curl ${proxyMessagesUrl} -d '{"model":"...","messages":[...]}'`);
778
- console.log(
779
- ` Remote/container tools: use the Network proxy URL above when shown; otherwise restart with --host 0.0.0.0 or a reachable IP.`,
780
- );
781
- console.log(``);
782
- console.log(`Routing environment variables:`);
783
- console.log(` ROUTES JSON map of model prefix -> upstream URL`);
784
- console.log(` DEFAULT_UPSTREAM Fallback upstream for unmatched models`);
785
- console.log(
786
- ` Example: ROUTES='{"claude-":"https://api.anthropic.com","MiniMax":"https://api.minimaxi.com/anthropic"}'`,
787
- );
788
-
789
- if (open) {
790
- openBrowser(uiUrl);
791
- }
792
-
793
864
  // Compute server path
794
865
  const outputDir = __dirname;
795
866
  const serverPath = join(outputDir, "../.output/server/index.mjs");
@@ -831,6 +902,7 @@ async function runStart(args: string[]): Promise<void> {
831
902
  serverEnv["AGENT_INSPECTOR_PUBLIC_PORT"] = String(port);
832
903
  serverEnv["PROXY_PORT"] = String(port);
833
904
  serverEnv["AGENT_INSPECTOR_CAPTURE_MODE"] = captureMode;
905
+ serverEnv["AGENT_INSPECTOR_BACKEND_ONLY"] = serveUi ? "0" : "1";
834
906
  const workerDir = join(__dirname, "workers");
835
907
  if (existsSync(workerDir)) {
836
908
  serverEnv["AGENT_INSPECTOR_WORKER_DIR"] = workerDir;
@@ -933,10 +1005,23 @@ async function runStart(args: string[]): Promise<void> {
933
1005
  host,
934
1006
  upstreamHost,
935
1007
  managedInstanceControl,
1008
+ uiOriginAllowlist.origins,
1009
+ uiDirectory,
1010
+ publicOrigin,
936
1011
  );
937
- if (primaryProxy !== null) {
938
- identityProxies.push({ label: "primary", port, server: primaryProxy });
1012
+ if (primaryProxy === null) {
1013
+ console.error(
1014
+ `Agent Inspector could not bind its protected public ingress at ${bindOrigin}; stopping the private backend.`,
1015
+ );
1016
+ requestSupervisorShutdown("SIGTERM");
1017
+ const failedStartupShutdown = currentSupervisorShutdown();
1018
+ if (failedStartupShutdown !== null) await failedStartupShutdown;
1019
+ process.off("SIGINT", handleSigint);
1020
+ process.off("SIGTERM", handleSigterm);
1021
+ process.exitCode = 1;
1022
+ return;
939
1023
  }
1024
+ identityProxies.push({ label: "primary", port, server: primaryProxy });
940
1025
  if (legacyAliasPort !== null) {
941
1026
  const legacyProxy = await tryStartIdentityProxy(
942
1027
  legacyAliasPort,
@@ -944,6 +1029,9 @@ async function runStart(args: string[]): Promise<void> {
944
1029
  host,
945
1030
  upstreamHost,
946
1031
  managedInstanceControl,
1032
+ uiOriginAllowlist.origins,
1033
+ uiDirectory,
1034
+ publicOrigin,
947
1035
  );
948
1036
  if (legacyProxy !== null) {
949
1037
  identityProxies.push({ label: "legacy", port: legacyAliasPort, server: legacyProxy });
@@ -957,11 +1045,13 @@ async function runStart(args: string[]): Promise<void> {
957
1045
  // not started yet so the public port is not yet accepting traffic.
958
1046
  const upstreamProbeBasePath = enableIdentityProxy ? "" : basePath;
959
1047
  if (await waitForInspectorHealthy(upstreamPort, 5000, host, upstreamProbeBasePath)) {
960
- console.log(`agent-inspector background server is ready at ${uiUrl}`);
1048
+ console.log(
1049
+ `agent-inspector background ${serveUi ? "server" : "backend"} is ready at ${surfaceBaseUrl}`,
1050
+ );
961
1051
  if (identityProxies.length > 0) {
962
1052
  console.log(`Identity proxy ready on port ${port} (PID-attributing proxy).`);
963
1053
  }
964
- printAccessHints(port, host, basePath);
1054
+ printAccessHints(port, host, basePath, serveUi, publicOrigin);
965
1055
  if (legacyProxyUrl !== null && legacyMcpUrl !== null) {
966
1056
  console.log(` Legacy proxy: ${legacyProxyUrl}`);
967
1057
  console.log(` Legacy MCP: ${legacyMcpUrl}`);
@@ -972,7 +1062,7 @@ async function runStart(args: string[]): Promise<void> {
972
1062
  `Route AI coding tools through the identity proxy for accurate PID attribution:`,
973
1063
  ` Claude Code: ANTHROPIC_BASE_URL=${proxyUrl} claude`,
974
1064
  ` OpenCode: LLM_BASE_URL=${proxyUrl} opencode`,
975
- ` MiMo Code: OPENAI_BASE_URL=${proxyUrl} mimo`,
1065
+ ` MiMo Code: OPENAI_BASE_URL=${openAiProxyUrl} mimo`,
976
1066
  legacyProxyUrl === null
977
1067
  ? ` Override the port with --port <n> when needed.`
978
1068
  : ` Legacy configs using ${legacyProxyUrl} still work.`,
@@ -980,14 +1070,25 @@ async function runStart(args: string[]): Promise<void> {
980
1070
  }
981
1071
  return;
982
1072
  }
983
- console.error(`agent-inspector background server did not become ready at ${uiUrl}.`);
1073
+ console.error(`agent-inspector background server did not become ready at ${surfaceBaseUrl}.`);
1074
+ process.exitCode = 1;
1075
+ return;
1076
+ }
1077
+
1078
+ if (!(await waitForInspectorHealthy(port, 10_000, host, basePath))) {
1079
+ console.error(`Agent Inspector did not become ready at ${surfaceBaseUrl}; stopping startup.`);
1080
+ requestSupervisorShutdown("SIGTERM");
1081
+ const failedStartupShutdown = currentSupervisorShutdown();
1082
+ if (failedStartupShutdown !== null) await failedStartupShutdown;
1083
+ process.off("SIGINT", handleSigint);
1084
+ process.off("SIGTERM", handleSigterm);
984
1085
  process.exitCode = 1;
985
1086
  return;
986
1087
  }
987
1088
 
988
1089
  if (identityProxies.length > 0) {
989
1090
  console.log(``);
990
- console.log(`Identity proxy ready at ${url} (PID-attributing public entrypoint).`);
1091
+ console.log(`Identity proxy ready at ${bindOrigin} (PID-attributing ingress).`);
991
1092
  if (legacyAliasPort !== null) {
992
1093
  const legacyReady = identityProxies.some((proxy) => proxy.label === "legacy");
993
1094
  if (legacyReady) {
@@ -999,6 +1100,28 @@ async function runStart(args: string[]): Promise<void> {
999
1100
  }
1000
1101
  }
1001
1102
 
1103
+ console.log(
1104
+ `${serveUi ? "UI and backend" : "Backend control and agent runtime"} running at ${surfaceBaseUrl}`,
1105
+ );
1106
+ console.log(` Capture mode: ${captureMode}`);
1107
+ console.log(` Proxy: ${proxyUrl}`);
1108
+ printAccessHints(port, host, basePath, serveUi, publicOrigin);
1109
+ if (legacyUrl !== null && legacyProxyUrl !== null && legacyMcpUrl !== null) {
1110
+ console.log(` Legacy UI: ${legacyUrl}`);
1111
+ console.log(` Legacy proxy: ${legacyProxyUrl}`);
1112
+ console.log(` Legacy MCP: ${legacyMcpUrl}`);
1113
+ }
1114
+ console.log(``);
1115
+ console.log(`Route AI coding tools through the proxy:`);
1116
+ console.log(` Claude Code: ANTHROPIC_BASE_URL=${proxyUrl} claude`);
1117
+ console.log(` OpenCode: LLM_BASE_URL=${proxyUrl} opencode`);
1118
+ console.log(` MiMo Code: OPENAI_BASE_URL=${openAiProxyUrl} mimo`);
1119
+ console.log(` Direct HTTP: curl ${proxyMessagesUrl} -d '{"model":"...","messages":[...]}'`);
1120
+ console.log(
1121
+ ` Remote/container tools: use the Network proxy URL above when shown; otherwise restart with --host 0.0.0.0 or a reachable IP.`,
1122
+ );
1123
+ if (open && uiUrl !== null) openBrowser(uiUrl);
1124
+
1002
1125
  process.exitCode = await serverExit;
1003
1126
 
1004
1127
  const activeSupervisorShutdown = currentSupervisorShutdown();