@tonyclaw/agent-inspector 3.0.45 → 3.0.47

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 (343) 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 +8018 -5451
  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-BwZEsYfS.mjs} +19794 -19444
  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-V-8lPASC.js} +1 -1
  19. package/.output/{public/assets/InspectorPet-Cpn6hv4P.js → ui/assets/InspectorPet-D4CVnfdf.js} +1 -1
  20. package/.output/ui/assets/ProxyViewerContainer-CO3ZVHLX.js +59 -0
  21. package/.output/{public/assets/ReplayDialog-B3EKVdJk.js → ui/assets/ReplayDialog-CpGyTLtt.js} +1 -1
  22. package/.output/{public/assets/RequestAnatomy-COOQjyUC.js → ui/assets/RequestAnatomy-BLuJL9dZ.js} +1 -1
  23. package/.output/ui/assets/ResponseView-BuSC-CH7.js +2 -0
  24. package/.output/ui/assets/StreamingChunkSequence-DeA-JJKa.js +1 -0
  25. package/.output/{public/assets/_sessionId-zbgYl7ZJ.js → ui/assets/_sessionId-8HuHFhjo.js} +1 -1
  26. package/.output/{public/assets/_sessionId-BJlM3nmt.js → ui/assets/_sessionId-Chp67th6.js} +1 -1
  27. package/.output/ui/assets/favicon-DYEkHSNl.svg +21 -0
  28. package/.output/ui/assets/index-BvXp42al.css +1 -0
  29. package/.output/{public/assets/index-xF_NY8Yb.js → ui/assets/index-DPmKK_5d.js} +5 -5
  30. package/.output/{public/assets/index-BIK4bPTv.js → ui/assets/index-atoQrlb8.js} +1 -1
  31. package/.output/ui/assets/index-nY3E1vxV.js +73 -0
  32. package/.output/{public/assets/index-D2Qw6Ri2.js → ui/assets/index-nl9-dpZn.js} +1 -1
  33. package/.output/ui/assets/json-viewer-B9kIzqeX.js +1 -0
  34. package/.output/{public/assets/jszip.min-B_rfAUCe.js → ui/assets/jszip.min-B7tfyE-I.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 +182 -43
  40. package/docs/instance-control.openapi.yaml +59 -4
  41. package/package.json +40 -6
  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/backend/routes/api/-instances.ts +7 -0
  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 +36 -13
  104. package/src/cli/instanceApi.ts +213 -0
  105. package/src/cli/instanceArgs.ts +46 -11
  106. package/src/cli/instanceControl.ts +10 -2
  107. package/src/cli/instanceModel.ts +18 -17
  108. package/src/cli/instanceRegistry.ts +0 -9
  109. package/src/cli/networkHints.ts +27 -14
  110. package/src/cli/onboard.ts +69 -2
  111. package/src/cli/onboardTarget.ts +89 -40
  112. package/src/cli/rustBackendPackage.ts +450 -0
  113. package/src/cli/templates/codex-skill-onboard.ts +44 -14
  114. package/src/cli/templates/skill-onboard.ts +64 -28
  115. package/src/cli.ts +341 -75
  116. package/src/components/ProxyViewer.tsx +11 -9
  117. package/src/components/ProxyViewerContainer.tsx +12 -11
  118. package/src/components/pi-agent/PiAgentPanel.tsx +2 -2
  119. package/src/components/providers/ProviderCard.tsx +1 -1
  120. package/src/components/providers/ProviderTestResultsView.tsx +1 -1
  121. package/src/components/providers/SettingsDialog.tsx +159 -144
  122. package/src/components/proxy-viewer/ApplicationBar.tsx +2 -1
  123. package/src/components/proxy-viewer/LogEntry.tsx +1 -1
  124. package/src/components/proxy-viewer/log-formats/index.ts +1 -1
  125. package/src/contracts/index.ts +5 -0
  126. package/src/contracts/log.ts +33 -3
  127. package/src/knowledge/types.ts +3 -2
  128. package/src/lib/alertContract.ts +2 -2
  129. package/src/lib/apiClient.ts +30 -7
  130. package/src/lib/apiFormat.ts +29 -0
  131. package/src/lib/backendImplementation.ts +16 -0
  132. package/src/lib/basePath.ts +29 -11
  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 +38 -0
  137. package/src/lib/instanceContract.ts +30 -11
  138. package/src/lib/managedInstance.ts +9 -1
  139. package/src/lib/piAgentContract.ts +3 -2
  140. package/src/lib/publicBasePathContext.ts +40 -10
  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 +2 -0
  145. package/src/mcp/server.ts +19 -24
  146. package/src/proxy/config.ts +25 -30
  147. package/src/proxy/dataDir.ts +43 -7
  148. package/src/proxy/ecosystemTasks.ts +161 -70
  149. package/src/proxy/formats/registry.ts +6 -21
  150. package/src/proxy/handler.ts +129 -29
  151. package/src/proxy/identityProxy.ts +567 -39
  152. package/src/proxy/jsonlRecovery.ts +554 -0
  153. package/src/proxy/logFinalizer.ts +25 -10
  154. package/src/proxy/logImporter.ts +2 -1
  155. package/src/proxy/logIndex.ts +191 -95
  156. package/src/proxy/logger.ts +77 -14
  157. package/src/proxy/platformCommands.ts +41 -0
  158. package/src/proxy/privateDataPath.ts +310 -88
  159. package/src/proxy/rawStreamCapture.ts +194 -13
  160. package/src/proxy/runtimeAdmission.ts +5 -2
  161. package/src/proxy/runtimeHealth.ts +14 -1
  162. package/src/proxy/runtimeShutdown.ts +11 -1
  163. package/src/proxy/schemas.ts +7 -1
  164. package/src/proxy/sessionArchive.ts +70 -14
  165. package/src/proxy/sqliteLogIndex.ts +65 -42
  166. package/src/proxy/store.ts +141 -34
  167. package/src/proxy/uiAssetServer.ts +106 -0
  168. package/src/proxy/upstream.ts +29 -2
  169. package/src/ui/bootstrap.ts +167 -0
  170. package/src/ui/index.html +38 -0
  171. package/src/ui/logsStreamClient.ts +20 -0
  172. package/src/ui/main.tsx +13 -0
  173. package/src/ui/public/runtime-config.js +2 -0
  174. package/src/ui/router.tsx +13 -0
  175. package/src/ui/routes/__root.tsx +69 -0
  176. package/src/{routes → ui/routes}/index.tsx +2 -3
  177. package/src/{routes → ui/routes}/session/$sessionId.tsx +5 -11
  178. package/src/ui/runtimeDiscovery.ts +50 -0
  179. package/styles/globals.css +1 -0
  180. package/.output/public/assets/ProxyViewerContainer-BEAhuGOJ.js +0 -126
  181. package/.output/public/assets/ResponseView-DBCjkwye.js +0 -2
  182. package/.output/public/assets/StreamingChunkSequence-CuXhDgMo.js +0 -1
  183. package/.output/public/assets/index-BZo_8koU.js +0 -70
  184. package/.output/public/assets/index-ZWschkCh.css +0 -1
  185. package/.output/public/assets/json-viewer-B-Ao6pwW.js +0 -1
  186. package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +0 -1
  187. package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +0 -344
  188. package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +0 -2
  189. package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +0 -2
  190. package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +0 -2
  191. package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +0 -11
  192. package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +0 -69
  193. package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +0 -1
  194. package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +0 -28
  195. package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +0 -6
  196. package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +0 -34
  197. package/.output/server/_libs/aria-hidden.mjs +0 -122
  198. package/.output/server/_libs/bail.mjs +0 -8
  199. package/.output/server/_libs/character-entities.mjs +0 -2130
  200. package/.output/server/_libs/class-variance-authority.mjs +0 -44
  201. package/.output/server/_libs/clsx.mjs +0 -16
  202. package/.output/server/_libs/comma-separated-tokens.mjs +0 -10
  203. package/.output/server/_libs/decode-named-character-reference+[...].mjs +0 -8
  204. package/.output/server/_libs/dequal.mjs +0 -27
  205. package/.output/server/_libs/detect-node-es.mjs +0 -1
  206. package/.output/server/_libs/devlop.mjs +0 -8
  207. package/.output/server/_libs/diff.mjs +0 -320
  208. package/.output/server/_libs/estree-util-is-identifier-name.mjs +0 -11
  209. package/.output/server/_libs/floating-ui__core.mjs +0 -725
  210. package/.output/server/_libs/floating-ui__dom.mjs +0 -622
  211. package/.output/server/_libs/floating-ui__react-dom.mjs +0 -292
  212. package/.output/server/_libs/floating-ui__utils.mjs +0 -320
  213. package/.output/server/_libs/get-nonce.mjs +0 -9
  214. package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +0 -388
  215. package/.output/server/_libs/hast-util-whitespace.mjs +0 -10
  216. package/.output/server/_libs/html-url-attributes.mjs +0 -26
  217. package/.output/server/_libs/inline-style-parser.mjs +0 -142
  218. package/.output/server/_libs/is-plain-obj.mjs +0 -10
  219. package/.output/server/_libs/lucide-react.mjs +0 -1027
  220. package/.output/server/_libs/mdast-util-from-markdown.mjs +0 -717
  221. package/.output/server/_libs/mdast-util-to-hast.mjs +0 -710
  222. package/.output/server/_libs/mdast-util-to-string.mjs +0 -38
  223. package/.output/server/_libs/micromark-core-commonmark.mjs +0 -2259
  224. package/.output/server/_libs/micromark-factory-destination.mjs +0 -94
  225. package/.output/server/_libs/micromark-factory-label.mjs +0 -63
  226. package/.output/server/_libs/micromark-factory-space.mjs +0 -24
  227. package/.output/server/_libs/micromark-factory-title.mjs +0 -65
  228. package/.output/server/_libs/micromark-factory-whitespace.mjs +0 -22
  229. package/.output/server/_libs/micromark-util-character.mjs +0 -44
  230. package/.output/server/_libs/micromark-util-chunked.mjs +0 -36
  231. package/.output/server/_libs/micromark-util-classify-character+[...].mjs +0 -12
  232. package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +0 -41
  233. package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -19
  234. package/.output/server/_libs/micromark-util-decode-string.mjs +0 -21
  235. package/.output/server/_libs/micromark-util-encode.mjs +0 -1
  236. package/.output/server/_libs/micromark-util-html-tag-name.mjs +0 -69
  237. package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +0 -6
  238. package/.output/server/_libs/micromark-util-resolve-all.mjs +0 -15
  239. package/.output/server/_libs/micromark-util-sanitize-uri.mjs +0 -41
  240. package/.output/server/_libs/micromark-util-subtokenize.mjs +0 -346
  241. package/.output/server/_libs/micromark.mjs +0 -906
  242. package/.output/server/_libs/property-information.mjs +0 -1209
  243. package/.output/server/_libs/radix-ui.mjs +0 -1
  244. package/.output/server/_libs/radix-ui__number.mjs +0 -6
  245. package/.output/server/_libs/radix-ui__primitive.mjs +0 -11
  246. package/.output/server/_libs/radix-ui__react-accordion.mjs +0 -1
  247. package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +0 -1
  248. package/.output/server/_libs/radix-ui__react-arrow.mjs +0 -23
  249. package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +0 -1
  250. package/.output/server/_libs/radix-ui__react-avatar.mjs +0 -1
  251. package/.output/server/_libs/radix-ui__react-checkbox.mjs +0 -1
  252. package/.output/server/_libs/radix-ui__react-collapsible.mjs +0 -144
  253. package/.output/server/_libs/radix-ui__react-collection.mjs +0 -69
  254. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +0 -38
  255. package/.output/server/_libs/radix-ui__react-context-menu.mjs +0 -1
  256. package/.output/server/_libs/radix-ui__react-context.mjs +0 -64
  257. package/.output/server/_libs/radix-ui__react-dialog.mjs +0 -280
  258. package/.output/server/_libs/radix-ui__react-direction.mjs +0 -9
  259. package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +0 -1
  260. package/.output/server/_libs/radix-ui__react-focus-guards.mjs +0 -39
  261. package/.output/server/_libs/radix-ui__react-focus-scope.mjs +0 -210
  262. package/.output/server/_libs/radix-ui__react-form.mjs +0 -1
  263. package/.output/server/_libs/radix-ui__react-hover-card.mjs +0 -1
  264. package/.output/server/_libs/radix-ui__react-id.mjs +0 -14
  265. package/.output/server/_libs/radix-ui__react-label.mjs +0 -1
  266. package/.output/server/_libs/radix-ui__react-menu.mjs +0 -1
  267. package/.output/server/_libs/radix-ui__react-menubar.mjs +0 -1
  268. package/.output/server/_libs/radix-ui__react-popover.mjs +0 -1
  269. package/.output/server/_libs/radix-ui__react-popper.mjs +0 -340
  270. package/.output/server/_libs/radix-ui__react-portal.mjs +0 -16
  271. package/.output/server/_libs/radix-ui__react-presence.mjs +0 -173
  272. package/.output/server/_libs/radix-ui__react-primitive.mjs +0 -42
  273. package/.output/server/_libs/radix-ui__react-progress.mjs +0 -1
  274. package/.output/server/_libs/radix-ui__react-radio-group.mjs +0 -1
  275. package/.output/server/_libs/radix-ui__react-roving-focus.mjs +0 -235
  276. package/.output/server/_libs/radix-ui__react-scroll-area.mjs +0 -731
  277. package/.output/server/_libs/radix-ui__react-select.mjs +0 -1207
  278. package/.output/server/_libs/radix-ui__react-separator.mjs +0 -28
  279. package/.output/server/_libs/radix-ui__react-slider.mjs +0 -1
  280. package/.output/server/_libs/radix-ui__react-slot.mjs +0 -132
  281. package/.output/server/_libs/radix-ui__react-switch.mjs +0 -1
  282. package/.output/server/_libs/radix-ui__react-tabs.mjs +0 -194
  283. package/.output/server/_libs/radix-ui__react-toast.mjs +0 -2
  284. package/.output/server/_libs/radix-ui__react-toggle-group.mjs +0 -1
  285. package/.output/server/_libs/radix-ui__react-toggle.mjs +0 -1
  286. package/.output/server/_libs/radix-ui__react-toolbar.mjs +0 -1
  287. package/.output/server/_libs/radix-ui__react-tooltip.mjs +0 -498
  288. package/.output/server/_libs/radix-ui__react-use-previous.mjs +0 -14
  289. package/.output/server/_libs/radix-ui__react-use-size.mjs +0 -39
  290. package/.output/server/_libs/react-markdown.mjs +0 -235
  291. package/.output/server/_libs/react-remove-scroll-bar.mjs +0 -82
  292. package/.output/server/_libs/react-remove-scroll.mjs +0 -328
  293. package/.output/server/_libs/react-style-singleton.mjs +0 -69
  294. package/.output/server/_libs/remark-parse.mjs +0 -19
  295. package/.output/server/_libs/remark-rehype.mjs +0 -21
  296. package/.output/server/_libs/space-separated-tokens.mjs +0 -6
  297. package/.output/server/_libs/style-to-js.mjs +0 -72
  298. package/.output/server/_libs/style-to-object.mjs +0 -38
  299. package/.output/server/_libs/swr.mjs +0 -947
  300. package/.output/server/_libs/tailwind-merge.mjs +0 -3255
  301. package/.output/server/_libs/tanstack__react-virtual.mjs +0 -130
  302. package/.output/server/_libs/tanstack__virtual-core.mjs +0 -1319
  303. package/.output/server/_libs/three.mjs +0 -26016
  304. package/.output/server/_libs/trim-lines.mjs +0 -41
  305. package/.output/server/_libs/trough.mjs +0 -85
  306. package/.output/server/_libs/tslib.mjs +0 -1
  307. package/.output/server/_libs/ungap__structured-clone.mjs +0 -212
  308. package/.output/server/_libs/unified.mjs +0 -661
  309. package/.output/server/_libs/unist-util-is.mjs +0 -100
  310. package/.output/server/_libs/unist-util-position.mjs +0 -27
  311. package/.output/server/_libs/unist-util-stringify-position.mjs +0 -27
  312. package/.output/server/_libs/unist-util-visit-parents.mjs +0 -82
  313. package/.output/server/_libs/unist-util-visit.mjs +0 -24
  314. package/.output/server/_libs/use-callback-ref.mjs +0 -66
  315. package/.output/server/_libs/use-sidecar.mjs +0 -106
  316. package/.output/server/_libs/vfile-message.mjs +0 -138
  317. package/.output/server/_libs/vfile.mjs +0 -467
  318. package/.output/server/_sessionId-CJ99gZFV.mjs +0 -84
  319. package/.output/server/_sessionId-DEjScBpK.mjs +0 -146
  320. package/.output/server/_ssr/CompareDrawer-DtOIMeQB.mjs +0 -1060
  321. package/.output/server/_ssr/InspectorPet-CXc4oCBQ.mjs +0 -938
  322. package/.output/server/_ssr/ProxyViewerContainer-DVPlwfkt.mjs +0 -17632
  323. package/.output/server/_ssr/ReplayDialog-BQEA95qC.mjs +0 -725
  324. package/.output/server/_ssr/RequestAnatomy-BMyd8B7Q.mjs +0 -837
  325. package/.output/server/_ssr/ResponseView-qrTaEIM8.mjs +0 -757
  326. package/.output/server/_ssr/StreamingChunkSequence-BFTL8mIy.mjs +0 -274
  327. package/.output/server/_ssr/index-Bcj1Hcy4.mjs +0 -135
  328. package/.output/server/_ssr/index-DW-M7XUG.mjs +0 -84
  329. package/.output/server/_ssr/json-viewer-DiI0Yjsn.mjs +0 -483
  330. package/.output/server/_tanstack-start-manifest_v-C6pXXX9R.mjs +0 -4
  331. package/.output/server/node_modules/tslib/modules/index.js +0 -70
  332. package/.output/server/node_modules/tslib/modules/package.json +0 -3
  333. package/.output/server/node_modules/tslib/package.json +0 -47
  334. package/.output/server/node_modules/tslib/tslib.js +0 -484
  335. package/.output/server/package.json +0 -9
  336. package/src/routes/__root.tsx +0 -170
  337. package/src/routes/api/-instances.ts +0 -109
  338. /package/.output/{public → ui}/assets/agent-inspector-58K1_MsC.ico +0 -0
  339. /package/.output/{public → ui}/assets/alibaba-TTwafVwX.svg +0 -0
  340. /package/.output/{public → ui}/assets/minimax-BPMzvuL-.jpeg +0 -0
  341. /package/.output/{public → ui}/assets/qwen-mMn3f5ul.webp +0 -0
  342. /package/.output/{public → ui}/assets/zhipuai-BPNAnxo-.svg +0 -0
  343. /package/src/{routes → backend/routes}/livez.ts +0 -0
@@ -0,0 +1,213 @@
1
+ import { type z } from "zod";
2
+ import {
3
+ getNamedInstance,
4
+ getNamedInstanceConnection,
5
+ type InstanceLifecycleError,
6
+ type InstanceLifecycleResult,
7
+ listNamedInstances,
8
+ restartNamedInstance,
9
+ startNamedInstance,
10
+ stopNamedInstance,
11
+ } from "./instance";
12
+ import {
13
+ type InstancePublicErrorCode,
14
+ INSTANCE_API_SCHEMA_VERSION,
15
+ InstanceEmptyRequestSchema,
16
+ InstanceStartRequestSchema,
17
+ instanceErrorOutput,
18
+ } from "../lib/instanceContract";
19
+ import { readManagedInstanceLaunch } from "../lib/managedInstance";
20
+
21
+ const NO_STORE_HEADERS = { "cache-control": "no-store" };
22
+
23
+ type ParsedBody<T> = { ok: true; value: T } | { ok: false; response: Response };
24
+
25
+ function errorStatus(code: InstancePublicErrorCode): number {
26
+ switch (code) {
27
+ case "argument_invalid":
28
+ case "data_dir_invalid":
29
+ case "name_invalid":
30
+ case "port_invalid":
31
+ case "record_invalid":
32
+ return 400;
33
+ case "instance_not_found":
34
+ return 404;
35
+ case "config_mismatch":
36
+ case "data_dir_conflict":
37
+ case "identity_mismatch":
38
+ case "port_conflict":
39
+ case "self_lifecycle_unsupported":
40
+ return 409;
41
+ case "lock_not_owned":
42
+ case "lock_timeout":
43
+ return 423;
44
+ case "launch_failed":
45
+ case "launch_unavailable":
46
+ case "port_exhausted":
47
+ case "registry_io":
48
+ case "restart_failed_degraded":
49
+ case "restart_failed_rolled_back":
50
+ case "shutdown_failed":
51
+ return 503;
52
+ }
53
+ }
54
+
55
+ export function instanceErrorResponse(error: InstanceLifecycleError): Response {
56
+ return Response.json(instanceErrorOutput(error), {
57
+ status: errorStatus(error.code),
58
+ headers: NO_STORE_HEADERS,
59
+ });
60
+ }
61
+
62
+ export function instanceResultResponse<T>(
63
+ result: InstanceLifecycleResult<T>,
64
+ successStatus = 200,
65
+ ): Response {
66
+ return result.kind === "error"
67
+ ? instanceErrorResponse(result.error)
68
+ : Response.json(result.value, { status: successStatus, headers: NO_STORE_HEADERS });
69
+ }
70
+
71
+ export async function parseInstanceBody<T extends z.ZodType>(
72
+ request: Request,
73
+ schema: T,
74
+ ): Promise<ParsedBody<z.output<T>>> {
75
+ let value: unknown;
76
+ try {
77
+ const text = await request.text();
78
+ value = text.trim().length === 0 ? {} : JSON.parse(text);
79
+ } catch {
80
+ return {
81
+ ok: false,
82
+ response: instanceErrorResponse({
83
+ code: "argument_invalid",
84
+ message: "Request body must be valid JSON.",
85
+ retryable: false,
86
+ }),
87
+ };
88
+ }
89
+ const parsed = schema.safeParse(value);
90
+ if (!parsed.success) {
91
+ return {
92
+ ok: false,
93
+ response: instanceErrorResponse({
94
+ code: "argument_invalid",
95
+ message: `Invalid instance request: ${parsed.error.issues[0]?.message ?? "invalid body"}`,
96
+ retryable: false,
97
+ }),
98
+ };
99
+ }
100
+ return { ok: true, value: parsed.data };
101
+ }
102
+
103
+ export function selfLifecycleError(rawName: string): InstanceLifecycleError | null {
104
+ const current = readManagedInstanceLaunch(process.env);
105
+ return current.kind === "managed" && current.launch.name.toLowerCase() === rawName.toLowerCase()
106
+ ? {
107
+ code: "self_lifecycle_unsupported",
108
+ message:
109
+ "A managed runtime cannot stop or restart itself through its own REST/MCP transport; use the CLI or a different controller instance.",
110
+ retryable: false,
111
+ }
112
+ : null;
113
+ }
114
+
115
+ export function instanceListResponse(instances: readonly unknown[]): Response {
116
+ return Response.json(
117
+ { schemaVersion: INSTANCE_API_SCHEMA_VERSION, instances },
118
+ { headers: NO_STORE_HEADERS },
119
+ );
120
+ }
121
+
122
+ function methodNotAllowed(allow: string): Response {
123
+ return Response.json(
124
+ { error: "Method not allowed" },
125
+ { status: 405, headers: { ...NO_STORE_HEADERS, allow } },
126
+ );
127
+ }
128
+
129
+ function endpointNotFound(): Response {
130
+ return Response.json(
131
+ { error: "Instance endpoint not found" },
132
+ { status: 404, headers: NO_STORE_HEADERS },
133
+ );
134
+ }
135
+
136
+ function decodedName(value: string): string | null {
137
+ try {
138
+ return decodeURIComponent(value);
139
+ } catch {
140
+ return null;
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Framework-neutral named-instance API owned by the Node supervisor plane.
146
+ *
147
+ * The protected ingress uses this when a Rust backend is selected, keeping process lifecycle and
148
+ * OS-specific background behavior in the existing CLI instead of reimplementing it in Rust.
149
+ */
150
+ export async function handleNamedInstanceApi(request: Request): Promise<Response> {
151
+ const url = new URL(request.url);
152
+ const segments = url.pathname.split("/").filter((segment) => segment.length > 0);
153
+ if (segments.length === 2 && segments[0] === "api" && segments[1] === "instances") {
154
+ if (request.method !== "GET") return methodNotAllowed("GET");
155
+ const result = await listNamedInstances();
156
+ return result.kind === "error"
157
+ ? instanceResultResponse(result)
158
+ : instanceListResponse(result.value);
159
+ }
160
+ if (segments.length < 3 || segments[0] !== "api" || segments[1] !== "instances") {
161
+ return endpointNotFound();
162
+ }
163
+ const name = decodedName(segments[2] ?? "");
164
+ if (name === null) {
165
+ return instanceErrorResponse({
166
+ code: "name_invalid",
167
+ message: "Instance name is not valid URL encoding.",
168
+ retryable: false,
169
+ });
170
+ }
171
+ if (segments.length === 3) {
172
+ return request.method === "GET"
173
+ ? instanceResultResponse(await getNamedInstance(name))
174
+ : methodNotAllowed("GET");
175
+ }
176
+ if (segments.length !== 4) return endpointNotFound();
177
+ const action = segments[3];
178
+ if (action === undefined) return endpointNotFound();
179
+ switch (action) {
180
+ case "connection":
181
+ return request.method === "GET"
182
+ ? instanceResultResponse(await getNamedInstanceConnection(name))
183
+ : methodNotAllowed("GET");
184
+ case "start": {
185
+ if (request.method !== "POST") return methodNotAllowed("POST");
186
+ const body = await parseInstanceBody(request, InstanceStartRequestSchema);
187
+ if (!body.ok) return body.response;
188
+ const result = await startNamedInstance(name, body.value);
189
+ const status = result.kind === "success" && result.value.outcome === "created" ? 201 : 200;
190
+ return instanceResultResponse(result, status);
191
+ }
192
+ case "stop": {
193
+ if (request.method !== "POST") return methodNotAllowed("POST");
194
+ const body = await parseInstanceBody(request, InstanceEmptyRequestSchema);
195
+ if (!body.ok) return body.response;
196
+ const selfError = selfLifecycleError(name);
197
+ return selfError === null
198
+ ? instanceResultResponse(await stopNamedInstance(name))
199
+ : instanceErrorResponse(selfError);
200
+ }
201
+ case "restart": {
202
+ if (request.method !== "POST") return methodNotAllowed("POST");
203
+ const body = await parseInstanceBody(request, InstanceStartRequestSchema);
204
+ if (!body.ok) return body.response;
205
+ const selfError = selfLifecycleError(name);
206
+ return selfError === null
207
+ ? instanceResultResponse(await restartNamedInstance(name, body.value))
208
+ : instanceErrorResponse(selfError);
209
+ }
210
+ default:
211
+ return endpointNotFound();
212
+ }
213
+ }
@@ -1,14 +1,20 @@
1
- import { normalizeBasePath } from "../lib/basePath";
1
+ import { normalizePublicBasePath } from "../lib/basePath";
2
+ import {
3
+ BackendImplementationSchema,
4
+ type BackendImplementation,
5
+ } from "../lib/backendImplementation";
2
6
  import { isValidBindHost } from "./networkHints";
3
7
 
4
8
  export type InstanceCaptureMode = "simple" | "full";
5
9
 
6
10
  export type InstanceStartOverrides = {
11
+ backend: BackendImplementation | null;
7
12
  port: number | null;
8
13
  basePath: string | null;
9
14
  host: string | null;
10
15
  captureMode: InstanceCaptureMode | null;
11
16
  dataDir: string | null;
17
+ uiEnabled: boolean | null;
12
18
  open: boolean;
13
19
  };
14
20
 
@@ -36,16 +42,8 @@ function parseMode(value: string | undefined): InstanceCaptureMode | null {
36
42
  }
37
43
 
38
44
  function parseBasePath(value: string | undefined): string | null {
39
- if (
40
- value === undefined ||
41
- !value.startsWith("/") ||
42
- value.includes("?") ||
43
- value.includes("#") ||
44
- value.includes("\\")
45
- ) {
46
- return null;
47
- }
48
- return normalizeBasePath(value);
45
+ if (value === undefined) return null;
46
+ return normalizePublicBasePath(value);
49
47
  }
50
48
 
51
49
  function optionWithEquals(arg: string): { name: string; value: string } | null {
@@ -56,11 +54,13 @@ function optionWithEquals(arg: string): { name: string; value: string } | null {
56
54
 
57
55
  function emptyOverrides(): InstanceStartOverrides {
58
56
  return {
57
+ backend: null,
59
58
  port: null,
60
59
  basePath: null,
61
60
  host: null,
62
61
  captureMode: null,
63
62
  dataDir: null,
63
+ uiEnabled: null,
64
64
  open: false,
65
65
  };
66
66
  }
@@ -78,6 +78,12 @@ function setValueOption(
78
78
  value: string | undefined,
79
79
  ): string | null {
80
80
  switch (name) {
81
+ case "--backend": {
82
+ const backend = BackendImplementationSchema.safeParse(value?.trim().toLowerCase());
83
+ if (!backend.success) return "instance: --backend must be typescript or rust";
84
+ options.overrides.backend = backend.data;
85
+ return null;
86
+ }
81
87
  case "--port":
82
88
  case "-p": {
83
89
  const port = parsePort(value);
@@ -148,8 +154,27 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
148
154
  case "--open":
149
155
  options.overrides.open = true;
150
156
  break;
157
+ case "--backend-only":
158
+ if (options.overrides.uiEnabled === true) {
159
+ return {
160
+ kind: "error",
161
+ message: "instance: --backend-only and --with-ui are mutually exclusive",
162
+ };
163
+ }
164
+ options.overrides.uiEnabled = false;
165
+ break;
166
+ case "--with-ui":
167
+ if (options.overrides.uiEnabled === false) {
168
+ return {
169
+ kind: "error",
170
+ message: "instance: --backend-only and --with-ui are mutually exclusive",
171
+ };
172
+ }
173
+ options.overrides.uiEnabled = true;
174
+ break;
151
175
  case "--port":
152
176
  case "-p":
177
+ case "--backend":
153
178
  case "--base-path":
154
179
  case "--host":
155
180
  case "-H":
@@ -176,11 +201,13 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
176
201
  return { kind: "error", message: "instance: list does not accept an instance name" };
177
202
  }
178
203
  if (
204
+ options.overrides.backend !== null ||
179
205
  options.overrides.port !== null ||
180
206
  options.overrides.basePath !== null ||
181
207
  options.overrides.host !== null ||
182
208
  options.overrides.captureMode !== null ||
183
209
  options.overrides.dataDir !== null ||
210
+ options.overrides.uiEnabled !== null ||
184
211
  options.overrides.open
185
212
  ) {
186
213
  return { kind: "error", message: "instance: list accepts only --json" };
@@ -198,11 +225,13 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
198
225
  return { kind: "error", message: `instance: ${command} requires exactly one instance name` };
199
226
  }
200
227
  if (
228
+ options.overrides.backend !== null ||
201
229
  options.overrides.port !== null ||
202
230
  options.overrides.basePath !== null ||
203
231
  options.overrides.host !== null ||
204
232
  options.overrides.captureMode !== null ||
205
233
  options.overrides.dataDir !== null ||
234
+ options.overrides.uiEnabled !== null ||
206
235
  options.overrides.open
207
236
  ) {
208
237
  return {
@@ -220,6 +249,9 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
220
249
  if (name === undefined || options.positional.length !== 2) {
221
250
  return { kind: "error", message: `instance: ${command} requires exactly one instance name` };
222
251
  }
252
+ if (options.overrides.uiEnabled === false && options.overrides.open) {
253
+ return { kind: "error", message: "instance: --open cannot be used with --backend-only" };
254
+ }
223
255
  return {
224
256
  kind: "ok",
225
257
  action: { kind: command, name, overrides: options.overrides, json: options.json },
@@ -246,11 +278,14 @@ Usage:
246
278
  agent-inspector instance restart <name> [options]
247
279
 
248
280
  Start/restart options:
281
+ --backend <typescript|rust> Persist the backend implementation (default: typescript)
249
282
  --port, -p <port> Public ingress port (auto-allocated on first start)
250
283
  --base-path <path> Public Base Path (default: /inspector; use / for root)
251
284
  --host, -H <host> Bind host (default: 127.0.0.1)
252
285
  --mode <simple|full> Capture mode (default: simple)
253
286
  --data-dir <path> Isolated data/config directory
287
+ --backend-only Persist a headless backend without serving the UI
288
+ --with-ui Persist composed UI serving (the default for new instances)
254
289
  --open Open the UI after readiness
255
290
  --json Emit machine-readable output
256
291
  --help, -h Show this help
@@ -3,12 +3,17 @@ import {
3
3
  MANAGED_INSTANCE_SHUTDOWN_PATH,
4
4
  MANAGED_INSTANCE_TOKEN_HEADER,
5
5
  } from "../lib/managedInstance";
6
+ import {
7
+ BackendImplementationSchema,
8
+ type BackendImplementation,
9
+ } from "../lib/backendImplementation";
6
10
 
7
11
  const DEFAULT_CONTROL_TIMEOUT_MS = 2_000;
8
12
 
9
13
  export type InstanceControlFetch = (input: string, init?: RequestInit) => Promise<Response>;
10
14
 
11
15
  export type ExpectedInstanceControlIdentity = {
16
+ backend?: BackendImplementation;
12
17
  instanceId: string;
13
18
  launchId: string;
14
19
  controlToken: string;
@@ -18,6 +23,7 @@ export type ExpectedInstanceControlIdentity = {
18
23
 
19
24
  export type InstanceControlIdentity = {
20
25
  schemaVersion: 1;
26
+ backend: BackendImplementation;
21
27
  instanceId: string;
22
28
  launchId: string;
23
29
  supervisorPid: number;
@@ -45,6 +51,7 @@ function isRecord(value: unknown): value is Record<string, unknown> {
45
51
  function parseIdentity(value: unknown): InstanceControlIdentity | null {
46
52
  if (!isRecord(value)) return null;
47
53
  const schemaVersion = value["schemaVersion"];
54
+ const backend = BackendImplementationSchema.safeParse(value["backend"] ?? "typescript");
48
55
  const instanceId = value["instanceId"];
49
56
  const launchId = value["launchId"];
50
57
  const supervisorPid = value["supervisorPid"];
@@ -53,6 +60,7 @@ function parseIdentity(value: unknown): InstanceControlIdentity | null {
53
60
  const upstreamPort = value["upstreamPort"];
54
61
  if (
55
62
  schemaVersion !== 1 ||
63
+ !backend.success ||
56
64
  typeof instanceId !== "string" ||
57
65
  instanceId.length === 0 ||
58
66
  typeof launchId !== "string" ||
@@ -75,6 +83,7 @@ function parseIdentity(value: unknown): InstanceControlIdentity | null {
75
83
  }
76
84
  return {
77
85
  schemaVersion: 1,
86
+ backend: backend.data,
78
87
  instanceId,
79
88
  launchId,
80
89
  supervisorPid,
@@ -136,6 +145,7 @@ export async function probeInstanceControl(
136
145
  if (
137
146
  identity.instanceId !== expected.instanceId ||
138
147
  identity.launchId !== expected.launchId ||
148
+ identity.backend !== (expected.backend ?? "typescript") ||
139
149
  identity.publicPort !== expected.publicPort
140
150
  ) {
141
151
  return { kind: "identity-mismatch" };
@@ -179,5 +189,3 @@ export async function requestInstanceShutdown(
179
189
  clearTimeout(timeout);
180
190
  }
181
191
  }
182
-
183
- export const instanceControlForTests = { parseIdentity };
@@ -1,7 +1,11 @@
1
1
  import { randomBytes, randomUUID } from "node:crypto";
2
2
  import { isAbsolute } from "node:path";
3
3
  import { z } from "zod";
4
- import { normalizeBasePath } from "../lib/basePath";
4
+ import {
5
+ BackendImplementationSchema,
6
+ type BackendImplementation,
7
+ } from "../lib/backendImplementation";
8
+ import { normalizePublicBasePath } from "../lib/basePath";
5
9
  import { MANAGED_INSTANCE_CONTROL_PATH } from "../lib/managedInstance";
6
10
  import { CaptureModeSchema, type CaptureMode } from "../lib/runtimeConfig";
7
11
 
@@ -73,26 +77,13 @@ export function validateInstanceName(rawName: string): InstanceRegistryResult<st
73
77
  export function normalizeInstanceBasePath(
74
78
  rawBasePath: string | undefined,
75
79
  ): InstanceRegistryResult<string> {
76
- const value = rawBasePath ?? "";
77
- const trimmed = value.trim();
78
- const hasControlCharacter = [...trimmed].some((character) => {
79
- const codePoint = character.codePointAt(0) ?? 0;
80
- return codePoint < 32 || codePoint === 127;
81
- });
82
- if (
83
- trimmed.length > 0 &&
84
- (!trimmed.startsWith("/") ||
85
- trimmed.includes("?") ||
86
- trimmed.includes("#") ||
87
- trimmed.includes("\\") ||
88
- hasControlCharacter)
89
- ) {
80
+ const normalized = normalizePublicBasePath(rawBasePath);
81
+ if (normalized === null) {
90
82
  return instanceRegistryError(
91
83
  "record_invalid",
92
- "Instance Base Path must be an absolute URL path without a query, hash, backslash, or control character.",
84
+ "Instance Base Path must use URL-safe path segments without traversal, encoded separators, or markup characters.",
93
85
  );
94
86
  }
95
- const normalized = normalizeBasePath(trimmed);
96
87
  const reservedControlRoot = MANAGED_INSTANCE_CONTROL_PATH.replace(/\/instance$/u, "");
97
88
  if (normalized === reservedControlRoot || normalized.startsWith(`${reservedControlRoot}/`)) {
98
89
  return instanceRegistryError(
@@ -137,6 +128,8 @@ export const InstanceRecordSchema = z
137
128
  upstreamPort: PortSchema,
138
129
  basePath: NormalizedBasePathSchema,
139
130
  captureMode: CaptureModeSchema,
131
+ backend: BackendImplementationSchema.default("typescript"),
132
+ uiEnabled: z.boolean().default(true),
140
133
  dataDir: z
141
134
  .string()
142
135
  .min(1)
@@ -168,6 +161,8 @@ export type InstanceRecordOutput = {
168
161
  upstreamPort: number;
169
162
  basePath: string;
170
163
  captureMode: CaptureMode;
164
+ backend: BackendImplementation;
165
+ uiEnabled: boolean;
171
166
  dataDir: string;
172
167
  launch: {
173
168
  launchId: string;
@@ -182,6 +177,8 @@ export type CreateInstanceRecordInput = {
182
177
  upstreamPort: number;
183
178
  basePath?: string;
184
179
  captureMode: CaptureMode;
180
+ backend?: BackendImplementation;
181
+ uiEnabled?: boolean;
185
182
  dataDir: string;
186
183
  };
187
184
 
@@ -222,6 +219,8 @@ export function createInstanceRecord(
222
219
  upstreamPort: input.upstreamPort,
223
220
  basePath: basePath.value,
224
221
  captureMode: input.captureMode,
222
+ backend: input.backend ?? "typescript",
223
+ uiEnabled: input.uiEnabled ?? true,
225
224
  dataDir: input.dataDir,
226
225
  launch: createLaunch(factory, now),
227
226
  };
@@ -266,6 +265,8 @@ export function toInstanceRecordOutput(record: InstanceRecord): InstanceRecordOu
266
265
  upstreamPort: record.upstreamPort,
267
266
  basePath: record.basePath,
268
267
  captureMode: record.captureMode,
268
+ backend: record.backend,
269
+ uiEnabled: record.uiEnabled,
269
270
  dataDir: record.dataDir,
270
271
  launch: {
271
272
  launchId: record.launch.launchId,
@@ -500,15 +500,6 @@ export function withRegistryLock<T>(
500
500
  return runWithLock(acquireRegistryLock(root, options), operation);
501
501
  }
502
502
 
503
- export function withInstanceLock<T>(
504
- root: string,
505
- rawName: string,
506
- operation: LockedOperation<T>,
507
- options: InstanceLockOptions = {},
508
- ): Promise<InstanceRegistryResult<T>> {
509
- return runWithLock(acquireInstanceLock(root, rawName, options), operation);
510
- }
511
-
512
503
  type PathApi = typeof win32;
513
504
 
514
505
  export type CanonicalDataDirectory = {
@@ -1,4 +1,5 @@
1
1
  import { networkInterfaces } from "node:os";
2
+ import { isIP } from "node:net";
2
3
  import { appendBasePathToOrigin, normalizeBasePath } from "../lib/basePath";
3
4
 
4
5
  export type NetworkInterfaceMap = ReturnType<typeof networkInterfaces>;
@@ -22,12 +23,12 @@ export function isWildcardHost(host: BindHost): boolean {
22
23
  export function isLoopbackHost(host: BindHost): boolean {
23
24
  const trimmed = trimHost(host);
24
25
  if (trimmed === undefined) return false;
25
- return (
26
- trimmed === "localhost" ||
27
- trimmed === "::1" ||
28
- trimmed === "[::1]" ||
29
- trimmed.startsWith("127.")
30
- );
26
+ const normalized =
27
+ trimmed.startsWith("[") && trimmed.endsWith("]")
28
+ ? trimmed.slice(1, -1).toLowerCase()
29
+ : trimmed.toLowerCase();
30
+ if (normalized === "localhost" || normalized === "::1") return true;
31
+ return isIP(normalized) === 4 && normalized.split(".", 1)[0] === "127";
31
32
  }
32
33
 
33
34
  function bracketIpv6(host: string): string {
@@ -112,11 +113,28 @@ function accessUrl(origin: string, path: string, basePath: string): string {
112
113
  return appendBasePathToOrigin(origin, path, basePath);
113
114
  }
114
115
 
116
+ function appendSurfaceLines(
117
+ lines: string[],
118
+ label: "Local" | "Bound" | "Network",
119
+ origin: string,
120
+ basePath: string,
121
+ uiEnabled: boolean,
122
+ ): void {
123
+ const baseUrl = accessUrl(origin, "/", basePath);
124
+ if (uiEnabled) lines.push(` ${label} UI: ${baseUrl}`);
125
+ lines.push(` ${label} control Base: ${baseUrl}`);
126
+ lines.push(` ${label} agent Base: ${baseUrl}`);
127
+ lines.push(` ${label} REST API: ${accessUrl(origin, "/api", basePath)}`);
128
+ lines.push(` ${label} proxy: ${accessUrl(origin, "/proxy", basePath)}`);
129
+ lines.push(` ${label} MCP: ${accessUrl(origin, "/api/mcp", basePath)}`);
130
+ }
131
+
115
132
  export function formatAccessHintLines(
116
133
  port: number,
117
134
  networkUrls: readonly string[],
118
135
  host: BindHost = undefined,
119
136
  basePath = "",
137
+ uiEnabled = true,
120
138
  ): string[] {
121
139
  const normalizedBasePath = normalizeBasePath(basePath);
122
140
  const localUrl = localUrlForPort(port);
@@ -124,14 +142,10 @@ export function formatAccessHintLines(
124
142
  const lines = ["Access URLs:", ` Bind host: ${hostLabel}`];
125
143
 
126
144
  if (isLoopbackHost(host) || isWildcardHost(host)) {
127
- lines.push(` Local UI: ${accessUrl(localUrl, "/", normalizedBasePath)}`);
128
- lines.push(` Local proxy: ${accessUrl(localUrl, "/proxy", normalizedBasePath)}`);
129
- lines.push(` Local MCP: ${accessUrl(localUrl, "/api/mcp", normalizedBasePath)}`);
145
+ appendSurfaceLines(lines, "Local", localUrl, normalizedBasePath, uiEnabled);
130
146
  } else {
131
147
  const boundUrl = urlForHost(port, host);
132
- lines.push(` Bound UI: ${accessUrl(boundUrl, "/", normalizedBasePath)}`);
133
- lines.push(` Bound proxy: ${accessUrl(boundUrl, "/proxy", normalizedBasePath)}`);
134
- lines.push(` Bound MCP: ${accessUrl(boundUrl, "/api/mcp", normalizedBasePath)}`);
148
+ appendSurfaceLines(lines, "Bound", boundUrl, normalizedBasePath, uiEnabled);
135
149
  lines.push(" Localhost: may not work because the server is bound to a specific host");
136
150
  }
137
151
 
@@ -141,8 +155,7 @@ export function formatAccessHintLines(
141
155
  } else if (firstNetworkUrl === undefined) {
142
156
  lines.push(" Network: no non-loopback IPv4 address detected");
143
157
  } else {
144
- lines.push(` Network UI: ${accessUrl(firstNetworkUrl, "/", normalizedBasePath)}`);
145
- lines.push(` Network proxy: ${accessUrl(firstNetworkUrl, "/proxy", normalizedBasePath)}`);
158
+ appendSurfaceLines(lines, "Network", firstNetworkUrl, normalizedBasePath, uiEnabled);
146
159
  const moreUrls = networkUrls.slice(1);
147
160
  if (moreUrls.length > 0) {
148
161
  lines.push(` Other IPs: ${moreUrls.join(", ")}`);