@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.
- package/.output/{nitro.json → backend/nitro.json} +3 -3
- package/.output/backend-public/assets/index-D4LX-sw-.js +11 -0
- package/.output/cli.js +2326 -516
- package/.output/server/_libs/extend.mjs +4 -8
- package/.output/server/_libs/jszip.mjs +9 -35
- package/.output/server/_libs/react-dom.mjs +2 -3
- package/.output/server/_libs/react.mjs +1 -27
- package/.output/server/_libs/tanstack__react-router.mjs +1 -329
- package/.output/server/_libs/tanstack__router-core.mjs +42 -100
- package/.output/server/_libs/use-sync-external-store.mjs +1 -64
- package/.output/server/_libs/ws.mjs +1 -1
- package/.output/server/_ssr/index.mjs +4 -4
- package/.output/server/_ssr/{publicBasePathContext-5264L3rX.mjs → publicBasePathContext-IH2ilOfu.mjs} +52 -24
- package/.output/server/_ssr/{router-BJ_ltLim.mjs → router-D18yUq36.mjs} +19770 -19447
- package/.output/server/_ssr/{start-C6MjPjxp.mjs → start-COQu_AgD.mjs} +1 -1
- package/.output/server/_tanstack-start-manifest_v-DnbdNeun.mjs +4 -0
- package/.output/server/index.mjs +5 -145
- package/.output/{public/assets/CompareDrawer-B3_TLTJh.js → ui/assets/CompareDrawer-DAUuIJ6G.js} +1 -1
- package/.output/{public/assets/InspectorPet-Cpn6hv4P.js → ui/assets/InspectorPet-BRBVjOWI.js} +1 -1
- package/.output/ui/assets/ProxyViewerContainer-D7Sq0ctc.js +59 -0
- package/.output/{public/assets/ReplayDialog-B3EKVdJk.js → ui/assets/ReplayDialog-nDLsjOhs.js} +1 -1
- package/.output/{public/assets/RequestAnatomy-COOQjyUC.js → ui/assets/RequestAnatomy-zd4BDgL0.js} +1 -1
- package/.output/ui/assets/ResponseView-AdIXGcSn.js +2 -0
- package/.output/ui/assets/StreamingChunkSequence-CesTz8He.js +1 -0
- package/.output/{public/assets/_sessionId-zbgYl7ZJ.js → ui/assets/_sessionId-BAfzrhSU.js} +1 -1
- package/.output/{public/assets/_sessionId-BJlM3nmt.js → ui/assets/_sessionId-QnBomgPD.js} +1 -1
- package/.output/ui/assets/favicon-DYEkHSNl.svg +21 -0
- package/.output/{public/assets/index-BIK4bPTv.js → ui/assets/index-BcsdxBAd.js} +1 -1
- package/.output/ui/assets/index-BvXp42al.css +1 -0
- package/.output/{public/assets/index-D2Qw6Ri2.js → ui/assets/index-D0rtCN9V.js} +1 -1
- package/.output/ui/assets/index-DHpwr08Z.js +73 -0
- package/.output/{public/assets/index-xF_NY8Yb.js → ui/assets/index-dNuk2dsU.js} +5 -5
- package/.output/ui/assets/json-viewer-BvFHglMb.js +1 -0
- package/.output/{public/assets/jszip.min-B_rfAUCe.js → ui/assets/jszip.min-B5Z7gNZB.js} +1 -1
- package/.output/ui/index.html +229 -0
- package/.output/ui/runtime-config.js +2 -0
- package/.output/workers/logFinalizer.worker.js +979 -414
- package/.output/workers/sessionWorkerEntry.js +979 -414
- package/README.md +175 -43
- package/docs/instance-control.openapi.yaml +59 -4
- package/package.json +25 -5
- package/scripts/generate-theme-scales.mjs +3 -3
- package/src/{router.tsx → backend/router.tsx} +3 -15
- package/src/backend/routes/$.ts +26 -0
- package/src/backend/routes/__root.ts +4 -0
- package/src/{routes → backend/routes}/api/-instances.ts +3 -3
- package/src/{routes → backend/routes}/api/alerts.summary.ts +3 -3
- package/src/{routes → backend/routes}/api/alerts.ts +4 -4
- package/src/{routes → backend/routes}/api/config.paths.ts +1 -1
- package/src/{routes → backend/routes}/api/config.ts +11 -2
- package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.help.ts +1 -1
- package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.install.ts +1 -1
- package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.runner-presets.ts +1 -1
- package/src/{routes → backend/routes}/api/ecosystem.packages.$packageId.upgrade.ts +1 -1
- package/src/{routes → backend/routes}/api/ecosystem.packages.ts +5 -1
- package/src/{routes → backend/routes}/api/ecosystem.recipes.$recipeId.run.ts +1 -1
- package/src/{routes → backend/routes}/api/ecosystem.tasks.$taskId.ts +1 -1
- package/src/{routes → backend/routes}/api/ecosystem.tasks.ts +1 -1
- package/src/{routes → backend/routes}/api/groups.$groupId.evidence.ts +2 -2
- package/src/{routes → backend/routes}/api/groups.$groupId.sessions.ts +2 -2
- package/src/{routes → backend/routes}/api/groups.$groupId.ts +2 -2
- package/src/{routes → backend/routes}/api/groups.ts +2 -2
- package/src/{routes → backend/routes}/api/health.ts +3 -3
- package/src/{routes → backend/routes}/api/instances.$name.connection.ts +1 -1
- package/src/{routes → backend/routes}/api/instances.$name.restart.ts +2 -2
- package/src/{routes → backend/routes}/api/instances.$name.start.ts +2 -2
- package/src/{routes → backend/routes}/api/instances.$name.stop.ts +2 -2
- package/src/{routes → backend/routes}/api/instances.$name.ts +1 -1
- package/src/{routes → backend/routes}/api/instances.ts +1 -1
- package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.promote.ts +2 -2
- package/src/{routes → backend/routes}/api/knowledge.candidates.$candidateId.ts +2 -2
- package/src/{routes → backend/routes}/api/knowledge.candidates.ts +1 -1
- package/src/{routes → backend/routes}/api/knowledge.project-context.ts +2 -2
- package/src/{routes → backend/routes}/api/knowledge.search.ts +2 -2
- package/src/{routes → backend/routes}/api/knowledge.sessions.$sessionId.candidates.ts +3 -3
- package/src/{routes → backend/routes}/api/logs.$id.body.ts +6 -6
- package/src/{routes → backend/routes}/api/logs.$id.chunks.ts +5 -4
- package/src/{routes → backend/routes}/api/logs.$id.replay.ts +12 -11
- package/src/{routes → backend/routes}/api/logs.$id.ts +4 -3
- package/src/{routes → backend/routes}/api/logs.import.ts +3 -3
- package/src/{routes → backend/routes}/api/logs.stream.ts +11 -7
- package/src/{routes → backend/routes}/api/logs.ts +17 -9
- package/src/{routes → backend/routes}/api/mcp.ts +1 -1
- package/src/{routes → backend/routes}/api/models.ts +1 -1
- package/src/{routes → backend/routes}/api/pi-agent.ts +2 -2
- package/src/{routes → backend/routes}/api/providers.$providerId.model-metadata.ts +5 -5
- package/src/{routes → backend/routes}/api/providers.$providerId.test.log.ts +7 -7
- package/src/{routes → backend/routes}/api/providers.$providerId.ts +4 -4
- package/src/{routes → backend/routes}/api/providers.export.ts +1 -1
- package/src/{routes → backend/routes}/api/providers.import.ts +3 -3
- package/src/{routes → backend/routes}/api/providers.scan.ts +2 -2
- package/src/{routes → backend/routes}/api/providers.ts +9 -4
- package/src/{routes → backend/routes}/api/runs.$runId.evidence.ts +2 -2
- package/src/{routes → backend/routes}/api/runs.$runId.ts +2 -2
- package/src/{routes → backend/routes}/api/runs.ts +4 -4
- package/src/backend/routes/api/runtime.ts +46 -0
- package/src/{routes → backend/routes}/api/sessions.ts +3 -3
- package/src/{routes → backend/routes}/proxy/$.ts +1 -1
- package/src/{routes → backend/routes}/readyz.ts +1 -1
- package/src/{start.ts → backend/start.ts} +1 -1
- package/src/cli/alias.ts +2 -11
- package/src/cli/doctor.ts +32 -9
- package/src/cli/instance.ts +26 -13
- package/src/cli/instanceArgs.ts +30 -11
- package/src/cli/instanceControl.ts +0 -2
- package/src/cli/instanceModel.ts +9 -17
- package/src/cli/instanceRegistry.ts +0 -9
- package/src/cli/networkHints.ts +27 -14
- package/src/cli/onboard.ts +69 -2
- package/src/cli/onboardTarget.ts +89 -40
- package/src/cli/templates/codex-skill-onboard.ts +44 -14
- package/src/cli/templates/skill-onboard.ts +64 -28
- package/src/cli.ts +184 -61
- package/src/components/ProxyViewer.tsx +11 -9
- package/src/components/ProxyViewerContainer.tsx +12 -11
- package/src/components/pi-agent/PiAgentPanel.tsx +2 -2
- package/src/components/providers/ProviderCard.tsx +1 -1
- package/src/components/providers/ProviderTestResultsView.tsx +1 -1
- package/src/components/providers/SettingsDialog.tsx +159 -144
- package/src/components/proxy-viewer/ApplicationBar.tsx +2 -1
- package/src/components/proxy-viewer/LogEntry.tsx +1 -1
- package/src/components/proxy-viewer/log-formats/index.ts +1 -1
- package/src/contracts/index.ts +5 -0
- package/src/contracts/log.ts +33 -3
- package/src/knowledge/types.ts +3 -2
- package/src/lib/alertContract.ts +2 -2
- package/src/lib/apiClient.ts +30 -7
- package/src/lib/apiFormat.ts +29 -0
- package/src/lib/basePath.ts +29 -11
- package/src/lib/browserRuntimeContract.ts +124 -0
- package/src/lib/browserRuntimeResolver.ts +244 -0
- package/src/{proxy → lib}/claudeCodeStrip.ts +6 -7
- package/src/lib/codingAgentEndpoints.ts +38 -0
- package/src/lib/instanceContract.ts +27 -11
- package/src/lib/piAgentContract.ts +3 -2
- package/src/lib/publicBasePathContext.ts +40 -10
- package/src/lib/resourceLimits.ts +2 -0
- package/src/lib/runContract.ts +3 -3
- package/src/lib/sessionInfoContract.ts +3 -2
- package/src/mcp/instanceHandlers.ts +1 -0
- package/src/mcp/server.ts +19 -24
- package/src/proxy/config.ts +25 -30
- package/src/proxy/dataDir.ts +43 -7
- package/src/proxy/ecosystemTasks.ts +161 -70
- package/src/proxy/formats/registry.ts +6 -21
- package/src/proxy/handler.ts +129 -29
- package/src/proxy/identityProxy.ts +419 -39
- package/src/proxy/jsonlRecovery.ts +554 -0
- package/src/proxy/logFinalizer.ts +25 -10
- package/src/proxy/logImporter.ts +2 -1
- package/src/proxy/logIndex.ts +191 -95
- package/src/proxy/logger.ts +77 -14
- package/src/proxy/platformCommands.ts +41 -0
- package/src/proxy/privateDataPath.ts +310 -88
- package/src/proxy/rawStreamCapture.ts +194 -13
- package/src/proxy/runtimeAdmission.ts +5 -2
- package/src/proxy/runtimeHealth.ts +14 -1
- package/src/proxy/runtimeShutdown.ts +11 -1
- package/src/proxy/schemas.ts +7 -1
- package/src/proxy/sessionArchive.ts +78 -14
- package/src/proxy/sqliteLogIndex.ts +65 -2
- package/src/proxy/store.ts +141 -34
- package/src/proxy/uiAssetServer.ts +106 -0
- package/src/proxy/upstream.ts +29 -2
- package/src/ui/bootstrap.ts +167 -0
- package/src/ui/index.html +38 -0
- package/src/ui/logsStreamClient.ts +20 -0
- package/src/ui/main.tsx +13 -0
- package/src/ui/public/runtime-config.js +2 -0
- package/src/ui/router.tsx +13 -0
- package/src/ui/routes/__root.tsx +69 -0
- package/src/{routes → ui/routes}/index.tsx +2 -3
- package/src/{routes → ui/routes}/session/$sessionId.tsx +5 -11
- package/src/ui/runtimeDiscovery.ts +50 -0
- package/styles/globals.css +1 -0
- package/.output/public/assets/ProxyViewerContainer-BEAhuGOJ.js +0 -126
- package/.output/public/assets/ResponseView-DBCjkwye.js +0 -2
- package/.output/public/assets/StreamingChunkSequence-CuXhDgMo.js +0 -1
- package/.output/public/assets/index-BZo_8koU.js +0 -70
- package/.output/public/assets/index-ZWschkCh.css +0 -1
- package/.output/public/assets/json-viewer-B-Ao6pwW.js +0 -1
- package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +0 -1
- package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +0 -344
- package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +0 -2
- package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +0 -2
- package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +0 -2
- package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +0 -11
- package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +0 -69
- package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +0 -1
- package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +0 -28
- package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +0 -6
- package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +0 -34
- package/.output/server/_libs/aria-hidden.mjs +0 -122
- package/.output/server/_libs/bail.mjs +0 -8
- package/.output/server/_libs/character-entities.mjs +0 -2130
- package/.output/server/_libs/class-variance-authority.mjs +0 -44
- package/.output/server/_libs/clsx.mjs +0 -16
- package/.output/server/_libs/comma-separated-tokens.mjs +0 -10
- package/.output/server/_libs/decode-named-character-reference+[...].mjs +0 -8
- package/.output/server/_libs/dequal.mjs +0 -27
- package/.output/server/_libs/detect-node-es.mjs +0 -1
- package/.output/server/_libs/devlop.mjs +0 -8
- package/.output/server/_libs/diff.mjs +0 -320
- package/.output/server/_libs/estree-util-is-identifier-name.mjs +0 -11
- package/.output/server/_libs/floating-ui__core.mjs +0 -725
- package/.output/server/_libs/floating-ui__dom.mjs +0 -622
- package/.output/server/_libs/floating-ui__react-dom.mjs +0 -292
- package/.output/server/_libs/floating-ui__utils.mjs +0 -320
- package/.output/server/_libs/get-nonce.mjs +0 -9
- package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +0 -388
- package/.output/server/_libs/hast-util-whitespace.mjs +0 -10
- package/.output/server/_libs/html-url-attributes.mjs +0 -26
- package/.output/server/_libs/inline-style-parser.mjs +0 -142
- package/.output/server/_libs/is-plain-obj.mjs +0 -10
- package/.output/server/_libs/lucide-react.mjs +0 -1027
- package/.output/server/_libs/mdast-util-from-markdown.mjs +0 -717
- package/.output/server/_libs/mdast-util-to-hast.mjs +0 -710
- package/.output/server/_libs/mdast-util-to-string.mjs +0 -38
- package/.output/server/_libs/micromark-core-commonmark.mjs +0 -2259
- package/.output/server/_libs/micromark-factory-destination.mjs +0 -94
- package/.output/server/_libs/micromark-factory-label.mjs +0 -63
- package/.output/server/_libs/micromark-factory-space.mjs +0 -24
- package/.output/server/_libs/micromark-factory-title.mjs +0 -65
- package/.output/server/_libs/micromark-factory-whitespace.mjs +0 -22
- package/.output/server/_libs/micromark-util-character.mjs +0 -44
- package/.output/server/_libs/micromark-util-chunked.mjs +0 -36
- package/.output/server/_libs/micromark-util-classify-character+[...].mjs +0 -12
- package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +0 -41
- package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +0 -19
- package/.output/server/_libs/micromark-util-decode-string.mjs +0 -21
- package/.output/server/_libs/micromark-util-encode.mjs +0 -1
- package/.output/server/_libs/micromark-util-html-tag-name.mjs +0 -69
- package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +0 -6
- package/.output/server/_libs/micromark-util-resolve-all.mjs +0 -15
- package/.output/server/_libs/micromark-util-sanitize-uri.mjs +0 -41
- package/.output/server/_libs/micromark-util-subtokenize.mjs +0 -346
- package/.output/server/_libs/micromark.mjs +0 -906
- package/.output/server/_libs/property-information.mjs +0 -1209
- package/.output/server/_libs/radix-ui.mjs +0 -1
- package/.output/server/_libs/radix-ui__number.mjs +0 -6
- package/.output/server/_libs/radix-ui__primitive.mjs +0 -11
- package/.output/server/_libs/radix-ui__react-accordion.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-arrow.mjs +0 -23
- package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-avatar.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-checkbox.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-collapsible.mjs +0 -144
- package/.output/server/_libs/radix-ui__react-collection.mjs +0 -69
- package/.output/server/_libs/radix-ui__react-compose-refs.mjs +0 -38
- package/.output/server/_libs/radix-ui__react-context-menu.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-context.mjs +0 -64
- package/.output/server/_libs/radix-ui__react-dialog.mjs +0 -280
- package/.output/server/_libs/radix-ui__react-direction.mjs +0 -9
- package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-focus-guards.mjs +0 -39
- package/.output/server/_libs/radix-ui__react-focus-scope.mjs +0 -210
- package/.output/server/_libs/radix-ui__react-form.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-hover-card.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-id.mjs +0 -14
- package/.output/server/_libs/radix-ui__react-label.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-menu.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-menubar.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-popover.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-popper.mjs +0 -340
- package/.output/server/_libs/radix-ui__react-portal.mjs +0 -16
- package/.output/server/_libs/radix-ui__react-presence.mjs +0 -173
- package/.output/server/_libs/radix-ui__react-primitive.mjs +0 -42
- package/.output/server/_libs/radix-ui__react-progress.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-radio-group.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-roving-focus.mjs +0 -235
- package/.output/server/_libs/radix-ui__react-scroll-area.mjs +0 -731
- package/.output/server/_libs/radix-ui__react-select.mjs +0 -1207
- package/.output/server/_libs/radix-ui__react-separator.mjs +0 -28
- package/.output/server/_libs/radix-ui__react-slider.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-slot.mjs +0 -132
- package/.output/server/_libs/radix-ui__react-switch.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-tabs.mjs +0 -194
- package/.output/server/_libs/radix-ui__react-toast.mjs +0 -2
- package/.output/server/_libs/radix-ui__react-toggle-group.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-toggle.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-toolbar.mjs +0 -1
- package/.output/server/_libs/radix-ui__react-tooltip.mjs +0 -498
- package/.output/server/_libs/radix-ui__react-use-previous.mjs +0 -14
- package/.output/server/_libs/radix-ui__react-use-size.mjs +0 -39
- package/.output/server/_libs/react-markdown.mjs +0 -235
- package/.output/server/_libs/react-remove-scroll-bar.mjs +0 -82
- package/.output/server/_libs/react-remove-scroll.mjs +0 -328
- package/.output/server/_libs/react-style-singleton.mjs +0 -69
- package/.output/server/_libs/remark-parse.mjs +0 -19
- package/.output/server/_libs/remark-rehype.mjs +0 -21
- package/.output/server/_libs/space-separated-tokens.mjs +0 -6
- package/.output/server/_libs/style-to-js.mjs +0 -72
- package/.output/server/_libs/style-to-object.mjs +0 -38
- package/.output/server/_libs/swr.mjs +0 -947
- package/.output/server/_libs/tailwind-merge.mjs +0 -3255
- package/.output/server/_libs/tanstack__react-virtual.mjs +0 -130
- package/.output/server/_libs/tanstack__virtual-core.mjs +0 -1319
- package/.output/server/_libs/three.mjs +0 -26016
- package/.output/server/_libs/trim-lines.mjs +0 -41
- package/.output/server/_libs/trough.mjs +0 -85
- package/.output/server/_libs/tslib.mjs +0 -1
- package/.output/server/_libs/ungap__structured-clone.mjs +0 -212
- package/.output/server/_libs/unified.mjs +0 -661
- package/.output/server/_libs/unist-util-is.mjs +0 -100
- package/.output/server/_libs/unist-util-position.mjs +0 -27
- package/.output/server/_libs/unist-util-stringify-position.mjs +0 -27
- package/.output/server/_libs/unist-util-visit-parents.mjs +0 -82
- package/.output/server/_libs/unist-util-visit.mjs +0 -24
- package/.output/server/_libs/use-callback-ref.mjs +0 -66
- package/.output/server/_libs/use-sidecar.mjs +0 -106
- package/.output/server/_libs/vfile-message.mjs +0 -138
- package/.output/server/_libs/vfile.mjs +0 -467
- package/.output/server/_sessionId-CJ99gZFV.mjs +0 -84
- package/.output/server/_sessionId-DEjScBpK.mjs +0 -146
- package/.output/server/_ssr/CompareDrawer-DtOIMeQB.mjs +0 -1060
- package/.output/server/_ssr/InspectorPet-CXc4oCBQ.mjs +0 -938
- package/.output/server/_ssr/ProxyViewerContainer-DVPlwfkt.mjs +0 -17632
- package/.output/server/_ssr/ReplayDialog-BQEA95qC.mjs +0 -725
- package/.output/server/_ssr/RequestAnatomy-BMyd8B7Q.mjs +0 -837
- package/.output/server/_ssr/ResponseView-qrTaEIM8.mjs +0 -757
- package/.output/server/_ssr/StreamingChunkSequence-BFTL8mIy.mjs +0 -274
- package/.output/server/_ssr/index-Bcj1Hcy4.mjs +0 -135
- package/.output/server/_ssr/index-DW-M7XUG.mjs +0 -84
- package/.output/server/_ssr/json-viewer-DiI0Yjsn.mjs +0 -483
- package/.output/server/_tanstack-start-manifest_v-C6pXXX9R.mjs +0 -4
- package/.output/server/node_modules/tslib/modules/index.js +0 -70
- package/.output/server/node_modules/tslib/modules/package.json +0 -3
- package/.output/server/node_modules/tslib/package.json +0 -47
- package/.output/server/node_modules/tslib/tslib.js +0 -484
- package/.output/server/package.json +0 -9
- package/src/routes/__root.tsx +0 -170
- /package/.output/{public → ui}/assets/agent-inspector-58K1_MsC.ico +0 -0
- /package/.output/{public → ui}/assets/alibaba-TTwafVwX.svg +0 -0
- /package/.output/{public → ui}/assets/minimax-BPMzvuL-.jpeg +0 -0
- /package/.output/{public → ui}/assets/qwen-mMn3f5ul.webp +0 -0
- /package/.output/{public → ui}/assets/zhipuai-BPNAnxo-.svg +0 -0
- /package/src/{routes → backend/routes}/livez.ts +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
|
-
import { getProvider, getModelUsageName } from "
|
|
4
|
-
import { addTestLogEntry } from "
|
|
5
|
-
import { getConfig } from "
|
|
6
|
-
import { buildProviderTestSessionId } from "
|
|
7
|
-
import { buildProviderTestRequestBody } from "
|
|
3
|
+
import { getProvider, getModelUsageName } from "../../../proxy/providers";
|
|
4
|
+
import { addTestLogEntry } from "../../../proxy/store";
|
|
5
|
+
import { getConfig } from "../../../proxy/config";
|
|
6
|
+
import { buildProviderTestSessionId } from "../../../proxy/sessionSupervisor";
|
|
7
|
+
import { buildProviderTestRequestBody } from "../../../lib/providerTestPrompt";
|
|
8
8
|
import {
|
|
9
9
|
ProviderTestResultsSchema,
|
|
10
10
|
type ProviderModelTestResults,
|
|
11
11
|
type ProviderTestResult as TestResult,
|
|
12
12
|
type ProviderTestState,
|
|
13
|
-
} from "
|
|
14
|
-
import { computeTokensPerSecond, firstChunkMsFromChunks } from "
|
|
13
|
+
} from "../../../lib/providerTestContract";
|
|
14
|
+
import { computeTokensPerSecond, firstChunkMsFromChunks } from "../../../proxy/streamTiming";
|
|
15
15
|
|
|
16
16
|
function hasSuccessField(result: ProviderTestState): result is TestResult {
|
|
17
17
|
return Object.prototype.hasOwnProperty.call(result, "success");
|
|
@@ -5,15 +5,15 @@ import {
|
|
|
5
5
|
updateProvider,
|
|
6
6
|
deleteProvider,
|
|
7
7
|
redactProvider,
|
|
8
|
-
} from "
|
|
8
|
+
} from "../../../proxy/providers";
|
|
9
9
|
import {
|
|
10
10
|
getProviderModelLimitViolation,
|
|
11
11
|
ProviderModelMetadataListSchema,
|
|
12
12
|
ProviderModelNameSchema,
|
|
13
13
|
ProviderModelsSchema,
|
|
14
|
-
} from "
|
|
15
|
-
import { evaluateUpstreamUrl } from "
|
|
16
|
-
import { resourceLimitResponse } from "
|
|
14
|
+
} from "../../../lib/providerContract";
|
|
15
|
+
import { evaluateUpstreamUrl } from "../../../lib/ssrfGuard";
|
|
16
|
+
import { resourceLimitResponse } from "../../../lib/resourceLimits";
|
|
17
17
|
|
|
18
18
|
const ALLOW_LOOPBACK = process.env["AGENT_INSPECTOR_ALLOW_LOOPBACK"] === "1";
|
|
19
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import { exportProviders, exportProvidersWithKeys } from "
|
|
3
|
+
import { exportProviders, exportProvidersWithKeys } from "../../../proxy/providers";
|
|
4
4
|
|
|
5
5
|
const SecretExportRequestSchema = z.object({
|
|
6
6
|
confirmation: z.literal("EXPORT_PROVIDER_KEYS"),
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
|
-
import { ProviderScanImportRequestSchema } from "
|
|
5
|
-
import { consumeProviderScan } from "
|
|
6
|
-
import { importProviders } from "
|
|
4
|
+
import { ProviderScanImportRequestSchema } from "../../../lib/providerImportContract";
|
|
5
|
+
import { consumeProviderScan } from "../../../proxy/providerScanStore";
|
|
6
|
+
import { importProviders } from "../../../proxy/providers";
|
|
7
7
|
|
|
8
8
|
const ProviderFileImportSchema = z.union([z.string(), z.object({ providers: z.unknown() })]);
|
|
9
9
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { scanExternalProviders } from "
|
|
3
|
-
import { createProviderScan } from "
|
|
2
|
+
import { scanExternalProviders } from "../../../proxy/providerImporters";
|
|
3
|
+
import { createProviderScan } from "../../../proxy/providerScanStore";
|
|
4
4
|
|
|
5
5
|
export const Route = createFileRoute("/api/providers/scan")({
|
|
6
6
|
server: {
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
getProviders,
|
|
5
|
+
addProvider,
|
|
6
|
+
redactProvider,
|
|
7
|
+
redactProviders,
|
|
8
|
+
} from "../../../proxy/providers";
|
|
4
9
|
import {
|
|
5
10
|
getProviderModelLimitViolation,
|
|
6
11
|
ProviderModelMetadataListSchema,
|
|
7
12
|
ProviderModelNameSchema,
|
|
8
13
|
ProviderModelsSchema,
|
|
9
|
-
} from "
|
|
10
|
-
import { evaluateUpstreamUrl } from "
|
|
11
|
-
import { resourceLimitResponse } from "
|
|
14
|
+
} from "../../../lib/providerContract";
|
|
15
|
+
import { evaluateUpstreamUrl } from "../../../lib/ssrfGuard";
|
|
16
|
+
import { resourceLimitResponse } from "../../../lib/resourceLimits";
|
|
12
17
|
|
|
13
18
|
const ALLOW_LOOPBACK = process.env["AGENT_INSPECTOR_ALLOW_LOOPBACK"] === "1";
|
|
14
19
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { EvidenceExportOptionsSchema } from "
|
|
3
|
-
import { exportInspectorRunEvidence, readInspectorRunEvidence } from "
|
|
2
|
+
import { EvidenceExportOptionsSchema } from "../../../lib/runContract";
|
|
3
|
+
import { exportInspectorRunEvidence, readInspectorRunEvidence } from "../../../services/runs";
|
|
4
4
|
|
|
5
5
|
type JsonBodyResult = { ok: true; value: unknown } | { ok: false };
|
|
6
6
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { UpdateInspectorRunInputSchema } from "
|
|
3
|
-
import { getInspectorRun, updateInspectorRun } from "
|
|
2
|
+
import { UpdateInspectorRunInputSchema } from "../../../lib/runContract";
|
|
3
|
+
import { getInspectorRun, updateInspectorRun } from "../../../services/runs";
|
|
4
4
|
|
|
5
5
|
type JsonBodyResult = { ok: true; value: unknown } | { ok: false };
|
|
6
6
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { CreateInspectorRunInputSchema } from "
|
|
2
|
+
import { CreateInspectorRunInputSchema } from "../../../lib/runContract";
|
|
3
3
|
import {
|
|
4
4
|
RECENT_FAILURES_DEFAULT_LIMIT,
|
|
5
5
|
createInspectorRun,
|
|
6
6
|
listInspectorRecentFailures,
|
|
7
7
|
listInspectorRuns,
|
|
8
|
-
} from "
|
|
9
|
-
import { RECENT_FAILURES_MAX_LIMIT } from "
|
|
10
|
-
import { parseBoundedIntegerParameter } from "
|
|
8
|
+
} from "../../../services/runs";
|
|
9
|
+
import { RECENT_FAILURES_MAX_LIMIT } from "../../../proxy/runFailures";
|
|
10
|
+
import { parseBoundedIntegerParameter } from "../../../lib/resourceLimits";
|
|
11
11
|
|
|
12
12
|
type JsonBodyResult = { ok: true; value: unknown } | { ok: false };
|
|
13
13
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import { appendBasePathToOrigin } from "../../../lib/basePath";
|
|
3
|
+
import {
|
|
4
|
+
BROWSER_RUNTIME_SCHEMA_VERSION,
|
|
5
|
+
type BrowserRuntimeDeployment,
|
|
6
|
+
} from "../../../lib/browserRuntimeContract";
|
|
7
|
+
import { getPublicBasePath, getPublicOrigin } from "../../../lib/publicBasePathContext";
|
|
8
|
+
|
|
9
|
+
type RuntimeEnvironment = Readonly<Record<string, string | undefined>>;
|
|
10
|
+
|
|
11
|
+
export const AGENT_INSPECTOR_BACKEND_ONLY_ENV = "AGENT_INSPECTOR_BACKEND_ONLY";
|
|
12
|
+
|
|
13
|
+
export function runtimeDiscoveryDocument(
|
|
14
|
+
env: RuntimeEnvironment = process.env,
|
|
15
|
+
): BrowserRuntimeDeployment {
|
|
16
|
+
const basePath = getPublicBasePath(env);
|
|
17
|
+
const baseUrl = appendBasePathToOrigin(getPublicOrigin(), "/", basePath);
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
schemaVersion: BROWSER_RUNTIME_SCHEMA_VERSION,
|
|
21
|
+
deploymentMode: env[AGENT_INSPECTOR_BACKEND_ONLY_ENV] === "1" ? "backend-only" : "composed",
|
|
22
|
+
ui: { basePath: basePath.length === 0 ? "/" : basePath },
|
|
23
|
+
control: { baseUrl },
|
|
24
|
+
agent: { baseUrl },
|
|
25
|
+
capabilities: {
|
|
26
|
+
rest: true,
|
|
27
|
+
sse: true,
|
|
28
|
+
proxy: true,
|
|
29
|
+
mcp: true,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function runtimeDiscoveryResponse(env: RuntimeEnvironment = process.env): Response {
|
|
35
|
+
return Response.json(runtimeDiscoveryDocument(env), {
|
|
36
|
+
headers: { "cache-control": "no-store" },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const Route = createFileRoute("/api/runtime")({
|
|
41
|
+
server: {
|
|
42
|
+
handlers: {
|
|
43
|
+
GET: () => runtimeDiscoveryResponse(),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { getSessionInfo, getSessionSnapshots, listSessions } from "
|
|
2
|
+
import { getSessionInfo, getSessionSnapshots, listSessions } from "../../../proxy/store";
|
|
3
3
|
import {
|
|
4
4
|
SESSION_INFO_DEFAULT_LATEST_LOG_LIMIT,
|
|
5
5
|
SESSION_INFO_MAX_LATEST_LOG_LIMIT,
|
|
6
|
-
} from "
|
|
7
|
-
import { parseBoundedIntegerParameter } from "
|
|
6
|
+
} from "../../../proxy/sessionInfo";
|
|
7
|
+
import { parseBoundedIntegerParameter } from "../../../lib/resourceLimits";
|
|
8
8
|
|
|
9
9
|
function parseBooleanFlag(value: string | null): boolean {
|
|
10
10
|
return value === "1" || value === "true";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
-
import { getRuntimeReadiness } from "
|
|
2
|
+
import { getRuntimeReadiness } from "../../proxy/runtimeHealth";
|
|
3
3
|
|
|
4
4
|
export async function readinessResponse(): Promise<Response> {
|
|
5
5
|
const readiness = await getRuntimeReadiness();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createMiddleware, createStart } from "@tanstack/react-start";
|
|
2
2
|
|
|
3
3
|
const publicBasePathMiddleware = createMiddleware().server(async ({ next, request }) => {
|
|
4
|
-
const { runWithRequestPublicBasePath } = await import("
|
|
4
|
+
const { runWithRequestPublicBasePath } = await import("../lib/publicBasePathContext");
|
|
5
5
|
return runWithRequestPublicBasePath(request, () => next());
|
|
6
6
|
});
|
|
7
7
|
|
package/src/cli/alias.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { normalizeBasePath } from "../lib/basePath";
|
|
1
|
+
import { normalizeBasePath, normalizePublicBasePath } from "../lib/basePath";
|
|
2
2
|
|
|
3
3
|
const DEFAULT_ALIAS_HOST = "localhost";
|
|
4
4
|
const DEFAULT_ALIAS_PORT = 9527;
|
|
@@ -67,16 +67,7 @@ function parsePort(raw: string | undefined): number | null {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function normalizeAliasPath(raw: string): string | null {
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
!trimmed.startsWith("/") ||
|
|
73
|
-
trimmed.includes("?") ||
|
|
74
|
-
trimmed.includes("#") ||
|
|
75
|
-
trimmed.includes("\\")
|
|
76
|
-
) {
|
|
77
|
-
return null;
|
|
78
|
-
}
|
|
79
|
-
return normalizeBasePath(trimmed);
|
|
70
|
+
return normalizePublicBasePath(raw);
|
|
80
71
|
}
|
|
81
72
|
|
|
82
73
|
function isValidHost(host: string): boolean {
|
package/src/cli/doctor.ts
CHANGED
|
@@ -249,7 +249,7 @@ function checkProviderConfig(options: DoctorOptions, deps: DoctorDeps): DoctorCh
|
|
|
249
249
|
"Provider config",
|
|
250
250
|
"warn",
|
|
251
251
|
`Provider config exists but no providers were found: ${candidate}`,
|
|
252
|
-
"Add a provider
|
|
252
|
+
"Add a provider through the control API/MCP, or use Settings when a UI is available.",
|
|
253
253
|
);
|
|
254
254
|
}
|
|
255
255
|
|
|
@@ -257,29 +257,51 @@ function checkProviderConfig(options: DoctorOptions, deps: DoctorDeps): DoctorCh
|
|
|
257
257
|
"Provider config",
|
|
258
258
|
"warn",
|
|
259
259
|
"No provider config was found.",
|
|
260
|
-
"Add a provider
|
|
260
|
+
"Add a provider through the control API/MCP, use Settings when a UI is available, or pass --providers for this check.",
|
|
261
261
|
);
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
+
function publicOriginForDoctor(port: number, env: DoctorDeps["env"]): string {
|
|
265
|
+
const configured = env["AGENT_INSPECTOR_PUBLIC_ORIGIN"];
|
|
266
|
+
if (configured !== undefined && configured.trim() === configured) {
|
|
267
|
+
try {
|
|
268
|
+
const parsed = new URL(configured);
|
|
269
|
+
if (
|
|
270
|
+
(parsed.protocol === "http:" || parsed.protocol === "https:") &&
|
|
271
|
+
parsed.username.length === 0 &&
|
|
272
|
+
parsed.password.length === 0 &&
|
|
273
|
+
parsed.pathname === "/" &&
|
|
274
|
+
parsed.search.length === 0 &&
|
|
275
|
+
parsed.hash.length === 0
|
|
276
|
+
) {
|
|
277
|
+
return parsed.origin;
|
|
278
|
+
}
|
|
279
|
+
} catch {
|
|
280
|
+
// Startup reports invalid public-origin configuration; doctor keeps a safe local hint.
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return `http://localhost:${String(port)}`;
|
|
284
|
+
}
|
|
285
|
+
|
|
264
286
|
async function checkProxyHealth(port: number, deps: DoctorDeps): Promise<DoctorCheck> {
|
|
265
287
|
const basePath = getConfiguredBasePath(deps.env);
|
|
266
288
|
const health = await deps.fetchHealth(port, basePath);
|
|
267
|
-
const url =
|
|
289
|
+
const url = publicOriginForDoctor(port, deps.env);
|
|
268
290
|
const proxyUrl = appendBasePathToOrigin(url, "/proxy", basePath);
|
|
269
291
|
const healthPath = appendBasePathToOrigin("", "/api/health", basePath);
|
|
270
292
|
if (health.ok) {
|
|
271
293
|
return check(
|
|
272
|
-
"
|
|
294
|
+
"Backend health",
|
|
273
295
|
"pass",
|
|
274
|
-
`
|
|
275
|
-
`
|
|
296
|
+
`Agent Inspector backend is healthy at ${appendBasePathToOrigin(url, "/", basePath)}.`,
|
|
297
|
+
`Agent proxy URL: ${proxyUrl}. UI availability is not part of this backend check.`,
|
|
276
298
|
);
|
|
277
299
|
}
|
|
278
300
|
|
|
279
301
|
if (await deps.isPortOpen(port)) {
|
|
280
302
|
const suffix = health.status === null ? "" : ` (HTTP ${health.status})`;
|
|
281
303
|
return check(
|
|
282
|
-
"
|
|
304
|
+
"Backend health",
|
|
283
305
|
"fail",
|
|
284
306
|
`Port ${port} is accepting connections, but ${healthPath} is not healthy${suffix}.`,
|
|
285
307
|
"Stop that process, choose --port <n>, or start agent-inspector with --force-restart.",
|
|
@@ -287,7 +309,7 @@ async function checkProxyHealth(port: number, deps: DoctorDeps): Promise<DoctorC
|
|
|
287
309
|
}
|
|
288
310
|
|
|
289
311
|
return check(
|
|
290
|
-
"
|
|
312
|
+
"Backend health",
|
|
291
313
|
"warn",
|
|
292
314
|
`No process is listening on port ${port}.`,
|
|
293
315
|
"Start with `agent-inspector`, `agent-inspector --background`, or `bun run dev`.",
|
|
@@ -578,7 +600,8 @@ export function doctorHelp(): string {
|
|
|
578
600
|
"Usage:",
|
|
579
601
|
" agent-inspector doctor [--port <port>] [--config-dir <dir>] [--providers <json>] [--fix] [--json] [--verbose] [--chrome-extension]",
|
|
580
602
|
"",
|
|
581
|
-
"Checks local
|
|
603
|
+
"Checks local backend health, provider config presence, and package metadata.",
|
|
604
|
+
"The backend check probes the local health endpoint and does not require a composed Web UI.",
|
|
582
605
|
"Pass --fix to run safe local repairs before checks, including legacy data-dir migration.",
|
|
583
606
|
"Pass --json to emit a machine-readable report for CI, scripts, and Jenkins.",
|
|
584
607
|
"Pass --verbose to include local paths, capture mode, and log storage checks.",
|
package/src/cli/instance.ts
CHANGED
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
AGENT_INSPECTOR_BASE_PATH_ENV,
|
|
5
5
|
appendBasePathToOrigin,
|
|
6
6
|
getConfiguredBasePath,
|
|
7
|
-
|
|
7
|
+
normalizePublicBasePath,
|
|
8
8
|
} from "../lib/basePath";
|
|
9
9
|
import {
|
|
10
10
|
type InstanceConnectionOutput,
|
|
@@ -171,6 +171,7 @@ function statusOutput(
|
|
|
171
171
|
upstreamPort: record.upstreamPort,
|
|
172
172
|
basePath: displayBasePath(record.basePath),
|
|
173
173
|
captureMode: record.captureMode,
|
|
174
|
+
uiEnabled: record.uiEnabled,
|
|
174
175
|
dataDir: record.dataDir,
|
|
175
176
|
supervisorPid: live.supervisorPid,
|
|
176
177
|
urls: recordUrls(record),
|
|
@@ -194,7 +195,16 @@ function connectionOutput(instance: InstanceStatusOutput): InstanceConnectionOut
|
|
|
194
195
|
const serverName = `agent-inspector-${instance.name}`;
|
|
195
196
|
return {
|
|
196
197
|
schemaVersion: INSTANCE_API_SCHEMA_VERSION,
|
|
198
|
+
uiEnabled: instance.uiEnabled,
|
|
197
199
|
instance,
|
|
200
|
+
surfaces: {
|
|
201
|
+
ui: {
|
|
202
|
+
enabled: instance.uiEnabled,
|
|
203
|
+
baseUrl: instance.uiEnabled ? instance.urls.ui : null,
|
|
204
|
+
},
|
|
205
|
+
control: { baseUrl: instance.urls.ui },
|
|
206
|
+
agent: { baseUrl: instance.urls.ui },
|
|
207
|
+
},
|
|
198
208
|
baseUrl: instance.urls.ui,
|
|
199
209
|
endpoints: instance.urls,
|
|
200
210
|
environment: {
|
|
@@ -271,7 +281,7 @@ function defaultOpenUrl(targetUrl: string): void {
|
|
|
271
281
|
child.unref();
|
|
272
282
|
}
|
|
273
283
|
|
|
274
|
-
function
|
|
284
|
+
export function buildInstanceLaunchArgs(record: InstanceRecord, open: boolean): string[] {
|
|
275
285
|
const args = [
|
|
276
286
|
"--background",
|
|
277
287
|
"--no-open",
|
|
@@ -282,7 +292,8 @@ function launchArgs(record: InstanceRecord, open: boolean): string[] {
|
|
|
282
292
|
"--mode",
|
|
283
293
|
record.captureMode,
|
|
284
294
|
];
|
|
285
|
-
if (
|
|
295
|
+
if (!record.uiEnabled) args.push("--backend-only");
|
|
296
|
+
if (open && record.uiEnabled) args.push("--open");
|
|
286
297
|
return args;
|
|
287
298
|
}
|
|
288
299
|
|
|
@@ -291,7 +302,7 @@ async function defaultLaunch(
|
|
|
291
302
|
open: boolean,
|
|
292
303
|
cliEntry: string,
|
|
293
304
|
): Promise<boolean> {
|
|
294
|
-
const child = spawn(process.execPath, [cliEntry, ...
|
|
305
|
+
const child = spawn(process.execPath, [cliEntry, ...buildInstanceLaunchArgs(record, open)], {
|
|
295
306
|
stdio: "ignore",
|
|
296
307
|
windowsHide: true,
|
|
297
308
|
env: {
|
|
@@ -468,6 +479,7 @@ function overridesDiffer(
|
|
|
468
479
|
if (overrides.basePath !== null && overrides.basePath !== record.basePath) return true;
|
|
469
480
|
if (overrides.host !== null && overrides.host !== record.host) return true;
|
|
470
481
|
if (overrides.captureMode !== null && overrides.captureMode !== record.captureMode) return true;
|
|
482
|
+
if (overrides.uiEnabled !== null && overrides.uiEnabled !== record.uiEnabled) return true;
|
|
471
483
|
if (overrides.dataDir !== null) {
|
|
472
484
|
const requested = canonicalizeDataDirectory(overrides.dataDir);
|
|
473
485
|
const saved = canonicalizeDataDirectory(record.dataDir);
|
|
@@ -495,6 +507,7 @@ function updatedRecord(
|
|
|
495
507
|
upstreamPort: pair.upstreamPort,
|
|
496
508
|
basePath: action.overrides.basePath ?? record.basePath,
|
|
497
509
|
captureMode: action.overrides.captureMode ?? record.captureMode,
|
|
510
|
+
uiEnabled: action.overrides.uiEnabled ?? record.uiEnabled,
|
|
498
511
|
dataDir,
|
|
499
512
|
};
|
|
500
513
|
const parsed = InstanceRecordSchema.safeParse(candidate);
|
|
@@ -556,6 +569,7 @@ async function createNewRecord(
|
|
|
556
569
|
upstreamPort: pairResult.value.upstreamPort,
|
|
557
570
|
basePath: action.overrides.basePath ?? getConfiguredBasePath(process.env),
|
|
558
571
|
captureMode: action.overrides.captureMode ?? DEFAULT_INSTANCE_CAPTURE_MODE,
|
|
572
|
+
uiEnabled: action.overrides.uiEnabled ?? true,
|
|
559
573
|
dataDir: dataDirResult.value,
|
|
560
574
|
});
|
|
561
575
|
return created.kind === "error" ? fromRegistry(created) : saveRecord(root, created.value);
|
|
@@ -609,7 +623,9 @@ async function startAction(
|
|
|
609
623
|
}
|
|
610
624
|
const live = await classifyRecord(record, deps);
|
|
611
625
|
if (live.state === "running") {
|
|
612
|
-
if (action.overrides.open
|
|
626
|
+
if (action.overrides.open && record.uiEnabled) {
|
|
627
|
+
(deps.openUrl ?? defaultOpenUrl)(recordUrls(record).ui);
|
|
628
|
+
}
|
|
613
629
|
return success(operationOutput("start", "already_running", statusOutput(record, live)));
|
|
614
630
|
}
|
|
615
631
|
if (live.state === "conflict") {
|
|
@@ -793,9 +809,10 @@ function requestActionOverrides(
|
|
|
793
809
|
): Extract<InstanceAction, { kind: "start" }>["overrides"] {
|
|
794
810
|
return {
|
|
795
811
|
port: input.port ?? null,
|
|
796
|
-
basePath: input.basePath === undefined ? null :
|
|
812
|
+
basePath: input.basePath === undefined ? null : normalizePublicBasePath(input.basePath),
|
|
797
813
|
host: input.host ?? null,
|
|
798
814
|
captureMode: input.captureMode ?? null,
|
|
815
|
+
uiEnabled: input.uiEnabled ?? null,
|
|
799
816
|
dataDir: input.dataDir ?? null,
|
|
800
817
|
open: false,
|
|
801
818
|
};
|
|
@@ -873,8 +890,10 @@ export async function listNamedInstances(
|
|
|
873
890
|
function formatStatus(output: InstanceStatusOutput): string {
|
|
874
891
|
const pid = output.supervisorPid === null ? "-" : String(output.supervisorPid);
|
|
875
892
|
const reason = output.stateReason === null ? "-" : output.stateReason;
|
|
893
|
+
const ui = output.uiEnabled ? output.urls.ui : `disabled (configured URL: ${output.urls.ui})`;
|
|
876
894
|
return `Instance ${output.name}: ${output.state}
|
|
877
|
-
UI: ${
|
|
895
|
+
UI: ${ui}
|
|
896
|
+
UI enabled: ${output.uiEnabled ? "yes" : "no"}
|
|
878
897
|
Proxy: ${output.urls.proxy}
|
|
879
898
|
OpenAI /v1: ${output.urls.openai}
|
|
880
899
|
MCP: ${output.urls.mcp}
|
|
@@ -1029,9 +1048,3 @@ export async function runInstance(
|
|
|
1029
1048
|
}
|
|
1030
1049
|
}
|
|
1031
1050
|
}
|
|
1032
|
-
|
|
1033
|
-
export const instanceLifecycleForTests = {
|
|
1034
|
-
classifyRecord,
|
|
1035
|
-
launchArgs,
|
|
1036
|
-
statusOutput,
|
|
1037
|
-
};
|
package/src/cli/instanceArgs.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { normalizePublicBasePath } from "../lib/basePath";
|
|
2
2
|
import { isValidBindHost } from "./networkHints";
|
|
3
3
|
|
|
4
4
|
export type InstanceCaptureMode = "simple" | "full";
|
|
@@ -9,6 +9,7 @@ export type InstanceStartOverrides = {
|
|
|
9
9
|
host: string | null;
|
|
10
10
|
captureMode: InstanceCaptureMode | null;
|
|
11
11
|
dataDir: string | null;
|
|
12
|
+
uiEnabled: boolean | null;
|
|
12
13
|
open: boolean;
|
|
13
14
|
};
|
|
14
15
|
|
|
@@ -36,16 +37,8 @@ function parseMode(value: string | undefined): InstanceCaptureMode | null {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function parseBasePath(value: string | undefined): string | null {
|
|
39
|
-
if (
|
|
40
|
-
|
|
41
|
-
!value.startsWith("/") ||
|
|
42
|
-
value.includes("?") ||
|
|
43
|
-
value.includes("#") ||
|
|
44
|
-
value.includes("\\")
|
|
45
|
-
) {
|
|
46
|
-
return null;
|
|
47
|
-
}
|
|
48
|
-
return normalizeBasePath(value);
|
|
40
|
+
if (value === undefined) return null;
|
|
41
|
+
return normalizePublicBasePath(value);
|
|
49
42
|
}
|
|
50
43
|
|
|
51
44
|
function optionWithEquals(arg: string): { name: string; value: string } | null {
|
|
@@ -61,6 +54,7 @@ function emptyOverrides(): InstanceStartOverrides {
|
|
|
61
54
|
host: null,
|
|
62
55
|
captureMode: null,
|
|
63
56
|
dataDir: null,
|
|
57
|
+
uiEnabled: null,
|
|
64
58
|
open: false,
|
|
65
59
|
};
|
|
66
60
|
}
|
|
@@ -148,6 +142,24 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
|
|
|
148
142
|
case "--open":
|
|
149
143
|
options.overrides.open = true;
|
|
150
144
|
break;
|
|
145
|
+
case "--backend-only":
|
|
146
|
+
if (options.overrides.uiEnabled === true) {
|
|
147
|
+
return {
|
|
148
|
+
kind: "error",
|
|
149
|
+
message: "instance: --backend-only and --with-ui are mutually exclusive",
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
options.overrides.uiEnabled = false;
|
|
153
|
+
break;
|
|
154
|
+
case "--with-ui":
|
|
155
|
+
if (options.overrides.uiEnabled === false) {
|
|
156
|
+
return {
|
|
157
|
+
kind: "error",
|
|
158
|
+
message: "instance: --backend-only and --with-ui are mutually exclusive",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
options.overrides.uiEnabled = true;
|
|
162
|
+
break;
|
|
151
163
|
case "--port":
|
|
152
164
|
case "-p":
|
|
153
165
|
case "--base-path":
|
|
@@ -181,6 +193,7 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
|
|
|
181
193
|
options.overrides.host !== null ||
|
|
182
194
|
options.overrides.captureMode !== null ||
|
|
183
195
|
options.overrides.dataDir !== null ||
|
|
196
|
+
options.overrides.uiEnabled !== null ||
|
|
184
197
|
options.overrides.open
|
|
185
198
|
) {
|
|
186
199
|
return { kind: "error", message: "instance: list accepts only --json" };
|
|
@@ -203,6 +216,7 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
|
|
|
203
216
|
options.overrides.host !== null ||
|
|
204
217
|
options.overrides.captureMode !== null ||
|
|
205
218
|
options.overrides.dataDir !== null ||
|
|
219
|
+
options.overrides.uiEnabled !== null ||
|
|
206
220
|
options.overrides.open
|
|
207
221
|
) {
|
|
208
222
|
return {
|
|
@@ -220,6 +234,9 @@ export function parseInstanceArgs(argv: readonly string[]): InstanceArgsResult {
|
|
|
220
234
|
if (name === undefined || options.positional.length !== 2) {
|
|
221
235
|
return { kind: "error", message: `instance: ${command} requires exactly one instance name` };
|
|
222
236
|
}
|
|
237
|
+
if (options.overrides.uiEnabled === false && options.overrides.open) {
|
|
238
|
+
return { kind: "error", message: "instance: --open cannot be used with --backend-only" };
|
|
239
|
+
}
|
|
223
240
|
return {
|
|
224
241
|
kind: "ok",
|
|
225
242
|
action: { kind: command, name, overrides: options.overrides, json: options.json },
|
|
@@ -251,6 +268,8 @@ Start/restart options:
|
|
|
251
268
|
--host, -H <host> Bind host (default: 127.0.0.1)
|
|
252
269
|
--mode <simple|full> Capture mode (default: simple)
|
|
253
270
|
--data-dir <path> Isolated data/config directory
|
|
271
|
+
--backend-only Persist a headless backend without serving the UI
|
|
272
|
+
--with-ui Persist composed UI serving (the default for new instances)
|
|
254
273
|
--open Open the UI after readiness
|
|
255
274
|
--json Emit machine-readable output
|
|
256
275
|
--help, -h Show this help
|
package/src/cli/instanceModel.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes, randomUUID } from "node:crypto";
|
|
2
2
|
import { isAbsolute } from "node:path";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
import {
|
|
4
|
+
import { normalizePublicBasePath } from "../lib/basePath";
|
|
5
5
|
import { MANAGED_INSTANCE_CONTROL_PATH } from "../lib/managedInstance";
|
|
6
6
|
import { CaptureModeSchema, type CaptureMode } from "../lib/runtimeConfig";
|
|
7
7
|
|
|
@@ -73,26 +73,13 @@ export function validateInstanceName(rawName: string): InstanceRegistryResult<st
|
|
|
73
73
|
export function normalizeInstanceBasePath(
|
|
74
74
|
rawBasePath: string | undefined,
|
|
75
75
|
): InstanceRegistryResult<string> {
|
|
76
|
-
const
|
|
77
|
-
|
|
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
|
-
) {
|
|
76
|
+
const normalized = normalizePublicBasePath(rawBasePath);
|
|
77
|
+
if (normalized === null) {
|
|
90
78
|
return instanceRegistryError(
|
|
91
79
|
"record_invalid",
|
|
92
|
-
"Instance Base Path must
|
|
80
|
+
"Instance Base Path must use URL-safe path segments without traversal, encoded separators, or markup characters.",
|
|
93
81
|
);
|
|
94
82
|
}
|
|
95
|
-
const normalized = normalizeBasePath(trimmed);
|
|
96
83
|
const reservedControlRoot = MANAGED_INSTANCE_CONTROL_PATH.replace(/\/instance$/u, "");
|
|
97
84
|
if (normalized === reservedControlRoot || normalized.startsWith(`${reservedControlRoot}/`)) {
|
|
98
85
|
return instanceRegistryError(
|
|
@@ -137,6 +124,7 @@ export const InstanceRecordSchema = z
|
|
|
137
124
|
upstreamPort: PortSchema,
|
|
138
125
|
basePath: NormalizedBasePathSchema,
|
|
139
126
|
captureMode: CaptureModeSchema,
|
|
127
|
+
uiEnabled: z.boolean().default(true),
|
|
140
128
|
dataDir: z
|
|
141
129
|
.string()
|
|
142
130
|
.min(1)
|
|
@@ -168,6 +156,7 @@ export type InstanceRecordOutput = {
|
|
|
168
156
|
upstreamPort: number;
|
|
169
157
|
basePath: string;
|
|
170
158
|
captureMode: CaptureMode;
|
|
159
|
+
uiEnabled: boolean;
|
|
171
160
|
dataDir: string;
|
|
172
161
|
launch: {
|
|
173
162
|
launchId: string;
|
|
@@ -182,6 +171,7 @@ export type CreateInstanceRecordInput = {
|
|
|
182
171
|
upstreamPort: number;
|
|
183
172
|
basePath?: string;
|
|
184
173
|
captureMode: CaptureMode;
|
|
174
|
+
uiEnabled?: boolean;
|
|
185
175
|
dataDir: string;
|
|
186
176
|
};
|
|
187
177
|
|
|
@@ -222,6 +212,7 @@ export function createInstanceRecord(
|
|
|
222
212
|
upstreamPort: input.upstreamPort,
|
|
223
213
|
basePath: basePath.value,
|
|
224
214
|
captureMode: input.captureMode,
|
|
215
|
+
uiEnabled: input.uiEnabled ?? true,
|
|
225
216
|
dataDir: input.dataDir,
|
|
226
217
|
launch: createLaunch(factory, now),
|
|
227
218
|
};
|
|
@@ -266,6 +257,7 @@ export function toInstanceRecordOutput(record: InstanceRecord): InstanceRecordOu
|
|
|
266
257
|
upstreamPort: record.upstreamPort,
|
|
267
258
|
basePath: record.basePath,
|
|
268
259
|
captureMode: record.captureMode,
|
|
260
|
+
uiEnabled: record.uiEnabled,
|
|
269
261
|
dataDir: record.dataDir,
|
|
270
262
|
launch: {
|
|
271
263
|
launchId: record.launch.launchId,
|