@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,7 +1,13 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { normalizePublicBasePath } from "./basePath";
|
|
2
3
|
|
|
3
4
|
export const INSTANCE_API_SCHEMA_VERSION = 1;
|
|
4
5
|
|
|
6
|
+
function isCanonicalPublicBasePath(value: string): boolean {
|
|
7
|
+
const normalized = normalizePublicBasePath(value);
|
|
8
|
+
return normalized !== null && (normalized.length === 0 ? "/" : normalized) === value;
|
|
9
|
+
}
|
|
10
|
+
|
|
5
11
|
export const InstanceStateSchema = z.enum(["running", "stopped", "conflict"]);
|
|
6
12
|
export const InstanceStateReasonSchema = z.enum(["identity_mismatch", "port_conflict"]);
|
|
7
13
|
|
|
@@ -35,18 +41,35 @@ export const InstanceStatusOutputSchema = z
|
|
|
35
41
|
host: z.string().min(1),
|
|
36
42
|
publicPort: z.number().int().min(1).max(65_535),
|
|
37
43
|
upstreamPort: z.number().int().min(1).max(65_535),
|
|
38
|
-
basePath: z.string().
|
|
44
|
+
basePath: z.string().refine(isCanonicalPublicBasePath, "Invalid public Base Path"),
|
|
39
45
|
captureMode: z.enum(["simple", "full"]),
|
|
46
|
+
uiEnabled: z.boolean(),
|
|
40
47
|
dataDir: z.string().min(1),
|
|
41
48
|
supervisorPid: z.number().int().positive().nullable(),
|
|
42
49
|
urls: InstanceUrlsSchema,
|
|
43
50
|
})
|
|
44
51
|
.strict();
|
|
45
52
|
|
|
53
|
+
export const InstanceConnectionSurfacesSchema = z
|
|
54
|
+
.object({
|
|
55
|
+
ui: z
|
|
56
|
+
.object({
|
|
57
|
+
enabled: z.boolean(),
|
|
58
|
+
baseUrl: z.url().nullable(),
|
|
59
|
+
})
|
|
60
|
+
.strict(),
|
|
61
|
+
control: z.object({ baseUrl: z.url() }).strict(),
|
|
62
|
+
agent: z.object({ baseUrl: z.url() }).strict(),
|
|
63
|
+
})
|
|
64
|
+
.strict();
|
|
65
|
+
|
|
46
66
|
export const InstanceConnectionOutputSchema = z
|
|
47
67
|
.object({
|
|
48
68
|
schemaVersion: z.literal(INSTANCE_API_SCHEMA_VERSION),
|
|
69
|
+
uiEnabled: z.boolean(),
|
|
49
70
|
instance: InstanceStatusOutputSchema,
|
|
71
|
+
surfaces: InstanceConnectionSurfacesSchema,
|
|
72
|
+
/** @deprecated Use surfaces.control.baseUrl or surfaces.agent.baseUrl. */
|
|
50
73
|
baseUrl: z.url(),
|
|
51
74
|
endpoints: InstanceUrlsSchema,
|
|
52
75
|
environment: z
|
|
@@ -82,12 +105,8 @@ export const InstanceStartRequestSchema = z
|
|
|
82
105
|
.min(1)
|
|
83
106
|
.max(2_048)
|
|
84
107
|
.refine(
|
|
85
|
-
(value) =>
|
|
86
|
-
|
|
87
|
-
!value.includes("?") &&
|
|
88
|
-
!value.includes("#") &&
|
|
89
|
-
!value.includes("\\"),
|
|
90
|
-
"Base Path must be an absolute URL path without query, hash, or backslash",
|
|
108
|
+
(value) => normalizePublicBasePath(value) !== null,
|
|
109
|
+
"Base Path must use URL-safe path segments without traversal, encoded separators, or markup characters",
|
|
91
110
|
)
|
|
92
111
|
.optional(),
|
|
93
112
|
host: z
|
|
@@ -105,6 +124,7 @@ export const InstanceStartRequestSchema = z
|
|
|
105
124
|
)
|
|
106
125
|
.optional(),
|
|
107
126
|
captureMode: z.enum(["simple", "full"]).optional(),
|
|
127
|
+
uiEnabled: z.boolean().optional(),
|
|
108
128
|
dataDir: z.string().trim().min(1).max(32_767).optional(),
|
|
109
129
|
})
|
|
110
130
|
.strict();
|
|
@@ -175,15 +195,11 @@ export const InstanceErrorOutputSchema = z
|
|
|
175
195
|
})
|
|
176
196
|
.strict();
|
|
177
197
|
|
|
178
|
-
export type InstanceState = z.infer<typeof InstanceStateSchema>;
|
|
179
|
-
export type InstanceStateReason = z.infer<typeof InstanceStateReasonSchema>;
|
|
180
198
|
export type InstanceStatusOutput = z.infer<typeof InstanceStatusOutputSchema>;
|
|
181
199
|
export type InstanceConnectionOutput = z.infer<typeof InstanceConnectionOutputSchema>;
|
|
182
200
|
export type InstanceStartRequest = z.infer<typeof InstanceStartRequestSchema>;
|
|
183
|
-
export type InstanceOperation = z.infer<typeof InstanceOperationSchema>;
|
|
184
201
|
export type InstanceOperationOutcome = z.infer<typeof InstanceOperationOutcomeSchema>;
|
|
185
202
|
export type InstanceOperationOutput = z.infer<typeof InstanceOperationOutputSchema>;
|
|
186
|
-
export type InstanceListOutput = z.infer<typeof InstanceListOutputSchema>;
|
|
187
203
|
export type InstancePublicErrorCode = z.infer<typeof InstancePublicErrorCodeSchema>;
|
|
188
204
|
export type InstancePublicError = z.infer<typeof InstancePublicErrorSchema>;
|
|
189
205
|
export type InstanceErrorOutput = z.infer<typeof InstanceErrorOutputSchema>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { LogIdSchema } from "../contracts";
|
|
2
3
|
|
|
3
4
|
export const PiAgentHistoryMessageSchema = z.object({
|
|
4
5
|
role: z.enum(["user", "assistant"]),
|
|
@@ -55,9 +56,9 @@ export const PiAgentQueryStatsSchema = z.object({
|
|
|
55
56
|
export const PiAgentEvidenceSchema = z.object({
|
|
56
57
|
source: PiAgentEvidenceSourceSchema,
|
|
57
58
|
id: z.string(),
|
|
58
|
-
logId:
|
|
59
|
+
logId: LogIdSchema.optional(),
|
|
59
60
|
knowledgeId: z.string().optional(),
|
|
60
|
-
logIds: z.array(
|
|
61
|
+
logIds: z.array(LogIdSchema).optional(),
|
|
61
62
|
timestamp: z.string().optional(),
|
|
62
63
|
sessionId: z.string().optional(),
|
|
63
64
|
model: z.string().optional(),
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
2
|
import {
|
|
3
3
|
AGENT_INSPECTOR_PUBLIC_BASE_PATH_HEADER,
|
|
4
|
+
AGENT_INSPECTOR_PUBLIC_ORIGIN_HEADER,
|
|
4
5
|
AGENT_INSPECTOR_PUBLIC_PORT_HEADER,
|
|
5
6
|
getConfiguredBasePath,
|
|
6
|
-
|
|
7
|
+
normalizePublicBasePath,
|
|
7
8
|
} from "./basePath";
|
|
8
9
|
import { getCurrentPort } from "./serverPort";
|
|
9
10
|
|
|
@@ -11,17 +12,12 @@ type BasePathEnv = Readonly<Record<string, string | undefined>>;
|
|
|
11
12
|
|
|
12
13
|
type PublicRequestContext = {
|
|
13
14
|
basePath: string;
|
|
15
|
+
publicOrigin: string | null;
|
|
14
16
|
publicPort: number | null;
|
|
15
17
|
};
|
|
16
18
|
|
|
17
19
|
const publicRequestStorage = new AsyncLocalStorage<PublicRequestContext>();
|
|
18
20
|
|
|
19
|
-
function isSafePublicBasePath(value: string): boolean {
|
|
20
|
-
if (value.length === 0) return true;
|
|
21
|
-
if (!/^\/[A-Za-z0-9._~-]+(?:\/[A-Za-z0-9._~-]+)*$/u.test(value)) return false;
|
|
22
|
-
return !value.split("/").some((segment) => segment === "." || segment === "..");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
21
|
/**
|
|
26
22
|
* Resolve the public Base Path attached by the trusted ingress. Invalid or
|
|
27
23
|
* missing values fall back to the process's canonical Base Path.
|
|
@@ -29,8 +25,8 @@ function isSafePublicBasePath(value: string): boolean {
|
|
|
29
25
|
export function resolveRequestPublicBasePath(request: Request, env?: BasePathEnv): string {
|
|
30
26
|
const rawValue = request.headers.get(AGENT_INSPECTOR_PUBLIC_BASE_PATH_HEADER);
|
|
31
27
|
if (rawValue !== null) {
|
|
32
|
-
const normalized =
|
|
33
|
-
if (
|
|
28
|
+
const normalized = normalizePublicBasePath(rawValue);
|
|
29
|
+
if (normalized !== null) return normalized;
|
|
34
30
|
}
|
|
35
31
|
return getConfiguredBasePath(env ?? process.env);
|
|
36
32
|
}
|
|
@@ -59,6 +55,29 @@ export function resolveRequestPublicPort(request: Request): number | null {
|
|
|
59
55
|
}
|
|
60
56
|
}
|
|
61
57
|
|
|
58
|
+
function normalizedPublicOrigin(value: string): string | null {
|
|
59
|
+
try {
|
|
60
|
+
const parsed = new URL(value);
|
|
61
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
62
|
+
if (parsed.username.length > 0 || parsed.password.length > 0) return null;
|
|
63
|
+
if (parsed.pathname !== "/" || parsed.search.length > 0 || parsed.hash.length > 0) return null;
|
|
64
|
+
return parsed.origin;
|
|
65
|
+
} catch {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Resolve the public origin set by trusted ingress without consulting forwarded headers. */
|
|
71
|
+
export function resolveRequestPublicOrigin(request: Request): string | null {
|
|
72
|
+
const headerOrigin = request.headers.get(AGENT_INSPECTOR_PUBLIC_ORIGIN_HEADER);
|
|
73
|
+
if (headerOrigin !== null) return normalizedPublicOrigin(headerOrigin);
|
|
74
|
+
try {
|
|
75
|
+
return normalizedPublicOrigin(new URL(request.url).origin);
|
|
76
|
+
} catch {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
62
81
|
/** Return the originating request's public Base Path, or the canonical path outside a request. */
|
|
63
82
|
export function getPublicBasePath(env?: BasePathEnv): string {
|
|
64
83
|
return publicRequestStorage.getStore()?.basePath ?? getConfiguredBasePath(env ?? process.env);
|
|
@@ -69,12 +88,21 @@ export function getPublicPort(): number {
|
|
|
69
88
|
return publicRequestStorage.getStore()?.publicPort ?? getCurrentPort();
|
|
70
89
|
}
|
|
71
90
|
|
|
91
|
+
/** Return the trusted public origin, with a loopback fallback outside an ingress request. */
|
|
92
|
+
export function getPublicOrigin(): string {
|
|
93
|
+
return (
|
|
94
|
+
publicRequestStorage.getStore()?.publicOrigin ?? `http://localhost:${String(getCurrentPort())}`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
72
98
|
/** Run work with an explicitly selected public Base Path. Primarily useful for internal calls. */
|
|
73
99
|
export function runWithPublicBasePath<T>(basePath: string, callback: () => T): T {
|
|
74
100
|
const current = publicRequestStorage.getStore();
|
|
101
|
+
const normalized = normalizePublicBasePath(basePath) ?? getConfiguredBasePath(process.env);
|
|
75
102
|
return publicRequestStorage.run(
|
|
76
103
|
{
|
|
77
|
-
basePath:
|
|
104
|
+
basePath: normalized,
|
|
105
|
+
publicOrigin: current?.publicOrigin ?? null,
|
|
78
106
|
publicPort: current?.publicPort ?? null,
|
|
79
107
|
},
|
|
80
108
|
callback,
|
|
@@ -89,6 +117,7 @@ export function runWithPublicPort<T>(publicPort: number, callback: () => T): T {
|
|
|
89
117
|
return publicRequestStorage.run(
|
|
90
118
|
{
|
|
91
119
|
basePath: current?.basePath ?? getConfiguredBasePath(process.env),
|
|
120
|
+
publicOrigin: current?.publicOrigin ?? null,
|
|
92
121
|
publicPort: normalizedPort,
|
|
93
122
|
},
|
|
94
123
|
callback,
|
|
@@ -100,6 +129,7 @@ export function runWithRequestPublicBasePath<T>(request: Request, callback: () =
|
|
|
100
129
|
return publicRequestStorage.run(
|
|
101
130
|
{
|
|
102
131
|
basePath: resolveRequestPublicBasePath(request),
|
|
132
|
+
publicOrigin: resolveRequestPublicOrigin(request),
|
|
103
133
|
publicPort: resolveRequestPublicPort(request),
|
|
104
134
|
},
|
|
105
135
|
callback,
|
|
@@ -9,6 +9,7 @@ export const MAX_PROVIDER_MODEL_METADATA = 64;
|
|
|
9
9
|
export const MAX_SSE_CLIENTS = 32;
|
|
10
10
|
export const MAX_ACTIVE_PROVIDER_TESTS = 2;
|
|
11
11
|
export const MAX_PROVIDER_TEST_CONCURRENCY = 4;
|
|
12
|
+
export const MAX_ACTIVE_PROXY_REQUESTS = 16;
|
|
12
13
|
|
|
13
14
|
export const ResourceLimitErrorCodeSchema = z.enum([
|
|
14
15
|
"invalid-page-request",
|
|
@@ -16,6 +17,7 @@ export const ResourceLimitErrorCodeSchema = z.enum([
|
|
|
16
17
|
"provider-model-limit-exceeded",
|
|
17
18
|
"sse-capacity-exceeded",
|
|
18
19
|
"provider-test-capacity-exceeded",
|
|
20
|
+
"proxy-capacity-exceeded",
|
|
19
21
|
]);
|
|
20
22
|
|
|
21
23
|
export const ResourceLimitStatusSchema = z.union([
|
package/src/lib/runContract.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { JsonValueSchema } from "../contracts";
|
|
2
|
+
import { JsonValueSchema, LogIdSchema } from "../contracts";
|
|
3
3
|
import { SessionInfoSchema } from "./sessionInfoContract";
|
|
4
4
|
|
|
5
5
|
export const InspectorRunStatusSchema = z.enum([
|
|
@@ -33,7 +33,7 @@ export const RunTimelineEventSchema = z.object({
|
|
|
33
33
|
severity: RunTimelineEventSeveritySchema,
|
|
34
34
|
title: z.string(),
|
|
35
35
|
details: z.string(),
|
|
36
|
-
logId:
|
|
36
|
+
logId: LogIdSchema.nullable(),
|
|
37
37
|
status: z.number().nullable(),
|
|
38
38
|
model: z.string().nullable(),
|
|
39
39
|
provider: z.string().nullable(),
|
|
@@ -62,7 +62,7 @@ export const FailureClassificationSchema = z.object({
|
|
|
62
62
|
severity: z.enum(["none", "low", "medium", "high"]),
|
|
63
63
|
category: FailureCategorySchema,
|
|
64
64
|
summary: z.string(),
|
|
65
|
-
evidenceLogIds: z.array(
|
|
65
|
+
evidenceLogIds: z.array(LogIdSchema),
|
|
66
66
|
hints: z.array(z.string()),
|
|
67
67
|
});
|
|
68
68
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { LogIdSchema } from "../contracts";
|
|
2
3
|
|
|
3
4
|
export const SessionTokenUsageSchema = z.object({
|
|
4
5
|
input: z.number().int().nonnegative(),
|
|
@@ -9,7 +10,7 @@ export const SessionTokenUsageSchema = z.object({
|
|
|
9
10
|
});
|
|
10
11
|
|
|
11
12
|
export const SessionLogSummarySchema = z.object({
|
|
12
|
-
id:
|
|
13
|
+
id: LogIdSchema,
|
|
13
14
|
sessionLogNumber: z.number().int().positive().optional(),
|
|
14
15
|
timestamp: z.string(),
|
|
15
16
|
provider: z.string().nullable(),
|
|
@@ -57,7 +58,7 @@ export const SessionInfoSchema = z.object({
|
|
|
57
58
|
models: z.array(z.string()),
|
|
58
59
|
providers: z.array(z.string()),
|
|
59
60
|
tokenUsage: SessionTokenUsageSchema,
|
|
60
|
-
lastLogId:
|
|
61
|
+
lastLogId: LogIdSchema.nullable(),
|
|
61
62
|
lastModel: z.string().nullable(),
|
|
62
63
|
clientUserAgent: z.string().nullable().optional(),
|
|
63
64
|
clientPid: z.number().nullable(),
|
package/src/mcp/server.ts
CHANGED
|
@@ -36,10 +36,10 @@ import { InspectorRunStatusSchema, UpdateInspectorRunInputSchema } from "../lib/
|
|
|
36
36
|
import { withBasePath } from "../lib/basePath";
|
|
37
37
|
import {
|
|
38
38
|
getPublicBasePath,
|
|
39
|
-
|
|
39
|
+
getPublicOrigin,
|
|
40
40
|
runWithRequestPublicBasePath,
|
|
41
41
|
} from "../lib/publicBasePathContext";
|
|
42
|
-
import { JsonValueSchema } from "../contracts";
|
|
42
|
+
import { JsonValueSchema, LogIdSchema, parseLogId } from "../contracts";
|
|
43
43
|
import { InstanceListOutputSchema } from "../lib/instanceContract";
|
|
44
44
|
import {
|
|
45
45
|
MAX_PROVIDER_MODEL_NAME_CHARS,
|
|
@@ -335,7 +335,15 @@ const UpdateProviderInputSchema = z.object({
|
|
|
335
335
|
});
|
|
336
336
|
|
|
337
337
|
const LogResourceListResponseSchema = z.object({
|
|
338
|
-
logs: z.array(z.object({ id:
|
|
338
|
+
logs: z.array(z.object({ id: LogIdSchema })),
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
export const McpLogIdInputSchema = z.object({
|
|
342
|
+
id: LogIdSchema.describe("The log id."),
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
export const McpOptionalLogIdInputSchema = z.object({
|
|
346
|
+
id: LogIdSchema.optional().describe("Optional log id to inspect."),
|
|
339
347
|
});
|
|
340
348
|
|
|
341
349
|
const ProcessResourceListResponseSchema = z.object({
|
|
@@ -361,10 +369,7 @@ function jsonResource(uri: URL, data: unknown): ReadResourceResult {
|
|
|
361
369
|
}
|
|
362
370
|
|
|
363
371
|
function mcpEndpointUrl(): string {
|
|
364
|
-
return
|
|
365
|
-
"/api/mcp",
|
|
366
|
-
getPublicBasePath(),
|
|
367
|
-
)}`;
|
|
372
|
+
return `${getPublicOrigin()}${withBasePath("/api/mcp", getPublicBasePath())}`;
|
|
368
373
|
}
|
|
369
374
|
|
|
370
375
|
function mcpHealth(): Record<string, unknown> {
|
|
@@ -968,9 +973,7 @@ function registerTools(server: McpServer): void {
|
|
|
968
973
|
title: "Get a single captured log by id",
|
|
969
974
|
description:
|
|
970
975
|
"Returns the full CapturedLog for the given id, including rawRequestBody and responseText with no truncation. SSE streaming chunks are NOT included — use inspector_get_log_chunks for those. Returns an error if the id does not exist.",
|
|
971
|
-
inputSchema:
|
|
972
|
-
id: z.number().int().positive().describe("The log id."),
|
|
973
|
-
}),
|
|
976
|
+
inputSchema: McpLogIdInputSchema,
|
|
974
977
|
},
|
|
975
978
|
({ id }) => safeCall(() => getLogImpl(callApi, id)),
|
|
976
979
|
);
|
|
@@ -981,9 +984,7 @@ function registerTools(server: McpServer): void {
|
|
|
981
984
|
title: "Get SSE streaming chunks for a captured log",
|
|
982
985
|
description:
|
|
983
986
|
"Returns the SSE chunks array for a streaming log, in the order they were received. Returns an error if the log has no chunks (i.e. was non-streaming or the log id is unknown).",
|
|
984
|
-
inputSchema:
|
|
985
|
-
id: z.number().int().positive().describe("The log id."),
|
|
986
|
-
}),
|
|
987
|
+
inputSchema: McpLogIdInputSchema,
|
|
987
988
|
},
|
|
988
989
|
({ id }) => safeCall(() => getLogChunksImpl(callApi, id)),
|
|
989
990
|
);
|
|
@@ -994,9 +995,7 @@ function registerTools(server: McpServer): void {
|
|
|
994
995
|
title: "Get captured log headers",
|
|
995
996
|
description:
|
|
996
997
|
"Returns header-focused evidence for one log without large request/response bodies: raw headers, upstream headers, user-agent, origin, client PID/port, session id, model, and API path.",
|
|
997
|
-
inputSchema:
|
|
998
|
-
id: z.number().int().positive().describe("The log id."),
|
|
999
|
-
}),
|
|
998
|
+
inputSchema: McpLogIdInputSchema,
|
|
1000
999
|
},
|
|
1001
1000
|
({ id }) => safeCall(() => getLogHeadersImpl(callApi, id)),
|
|
1002
1001
|
);
|
|
@@ -1174,9 +1173,7 @@ function registerTools(server: McpServer): void {
|
|
|
1174
1173
|
title: "Diagnose capture detail availability",
|
|
1175
1174
|
description:
|
|
1176
1175
|
"Explains why headers or bodies may be missing for the current runtime or a specific log, including captureMode, compact body mode, rawHeaders presence, and next-step recommendations.",
|
|
1177
|
-
inputSchema:
|
|
1178
|
-
id: z.number().int().positive().optional().describe("Optional log id to inspect."),
|
|
1179
|
-
}),
|
|
1176
|
+
inputSchema: McpOptionalLogIdInputSchema,
|
|
1180
1177
|
},
|
|
1181
1178
|
(args) => safeCall(() => diagnoseCaptureImpl(callApi, args)),
|
|
1182
1179
|
);
|
|
@@ -1504,9 +1501,7 @@ function registerTools(server: McpServer): void {
|
|
|
1504
1501
|
title: "Replay a captured log against its provider",
|
|
1505
1502
|
description:
|
|
1506
1503
|
"Re-sends the captured request body to the upstream LLM and returns the response summary: success flag, status, responseText, input/output token counts, elapsedMs, and whether the response was streaming. Useful for re-running a request after a fix or a transient failure. Returns an error if the log id is unknown or the upstream call fails.",
|
|
1507
|
-
inputSchema:
|
|
1508
|
-
id: z.number().int().positive().describe("The log id to replay."),
|
|
1509
|
-
}),
|
|
1504
|
+
inputSchema: McpLogIdInputSchema,
|
|
1510
1505
|
},
|
|
1511
1506
|
(args) => safeWriteCall("inspector_replay_log", () => replayLogImpl(callApi, args)),
|
|
1512
1507
|
);
|
|
@@ -1815,8 +1810,8 @@ function registerResources(server: McpServer): void {
|
|
|
1815
1810
|
},
|
|
1816
1811
|
async (uri, variables) => {
|
|
1817
1812
|
const id = variableString(variables, "id");
|
|
1818
|
-
const parsed = id === null ?
|
|
1819
|
-
if (
|
|
1813
|
+
const parsed = id === null ? null : parseLogId(id);
|
|
1814
|
+
if (parsed === null) {
|
|
1820
1815
|
return textResource(uri, "text/plain", "Invalid log id");
|
|
1821
1816
|
}
|
|
1822
1817
|
const result = await getLogImpl(callApi, parsed);
|
package/src/proxy/config.ts
CHANGED
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
writeFileSync,
|
|
3
|
-
readFileSync,
|
|
4
|
-
unlinkSync,
|
|
5
|
-
existsSync,
|
|
6
|
-
renameSync,
|
|
7
|
-
copyFileSync,
|
|
8
|
-
} from "node:fs";
|
|
1
|
+
import { writeFileSync, readFileSync, unlinkSync, existsSync, renameSync } from "node:fs";
|
|
9
2
|
import { join } from "node:path";
|
|
10
3
|
import { logger } from "./logger";
|
|
11
4
|
import { getDataDir } from "./dataDir";
|
|
@@ -128,19 +121,19 @@ export function getConfig(): RuntimeConfig {
|
|
|
128
121
|
}
|
|
129
122
|
|
|
130
123
|
/**
|
|
131
|
-
* Applies a partial update
|
|
132
|
-
* Returns the updated full config
|
|
133
|
-
*
|
|
134
|
-
*
|
|
124
|
+
* Applies a partial update after atomically persisting it to disk.
|
|
125
|
+
* Returns the updated full config on success or null when persistence
|
|
126
|
+
* fails. A failed write leaves both the in-memory value and the existing
|
|
127
|
+
* on-disk value unchanged.
|
|
135
128
|
*/
|
|
136
|
-
export function setConfig(patch: Partial<MutableRuntimeConfig>): RuntimeConfig {
|
|
129
|
+
export function setConfig(patch: Partial<MutableRuntimeConfig>): RuntimeConfig | null {
|
|
137
130
|
const next: RuntimeConfig = {
|
|
138
131
|
...currentConfig,
|
|
139
132
|
...patch,
|
|
140
133
|
captureMode: currentConfig.captureMode,
|
|
141
134
|
};
|
|
135
|
+
if (!persistConfig(next)) return null;
|
|
142
136
|
currentConfig = next;
|
|
143
|
-
persistConfig(next);
|
|
144
137
|
return next;
|
|
145
138
|
}
|
|
146
139
|
|
|
@@ -164,8 +157,10 @@ export function _rebootForTests(): void {
|
|
|
164
157
|
// --- Atomic write ---
|
|
165
158
|
|
|
166
159
|
/**
|
|
167
|
-
* Atomic write: temp file + rename
|
|
168
|
-
* Returns true on success, false on failure (logged but not thrown).
|
|
160
|
+
* Atomic write: secure temp file + rename in the same directory.
|
|
161
|
+
* Returns true on success, false on failure (logged but not thrown). There is
|
|
162
|
+
* deliberately no copy fallback because replacing the target through a copy
|
|
163
|
+
* could expose a partially written config after a crash.
|
|
169
164
|
*/
|
|
170
165
|
function persistConfig(value: RuntimeConfig): boolean {
|
|
171
166
|
const dir = getDataDir();
|
|
@@ -181,13 +176,15 @@ function persistConfig(value: RuntimeConfig): boolean {
|
|
|
181
176
|
writeFileSync(tempPath, JSON.stringify(toPersistedConfig(value)), {
|
|
182
177
|
encoding: "utf-8",
|
|
183
178
|
mode: PRIVATE_FILE_MODE,
|
|
179
|
+
flush: true,
|
|
184
180
|
});
|
|
185
181
|
if (!securePrivateFileSync(tempPath)) {
|
|
186
|
-
|
|
182
|
+
removeConfigTempFile(tempPath);
|
|
187
183
|
logger.error(`[config] Failed to secure config temp file ${tempPath}`);
|
|
188
184
|
return false;
|
|
189
185
|
}
|
|
190
186
|
} catch (err) {
|
|
187
|
+
removeConfigTempFile(tempPath);
|
|
191
188
|
logger.error(`[config] Failed to write config temp file: ${String(err)}`);
|
|
192
189
|
return false;
|
|
193
190
|
}
|
|
@@ -196,19 +193,17 @@ function persistConfig(value: RuntimeConfig): boolean {
|
|
|
196
193
|
renameSync(tempPath, targetPath);
|
|
197
194
|
return true;
|
|
198
195
|
} catch (err) {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
return false;
|
|
211
|
-
}
|
|
196
|
+
removeConfigTempFile(tempPath);
|
|
197
|
+
logger.error(`[config] Failed to atomically replace config file: ${String(err)}`);
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function removeConfigTempFile(tempPath: string): void {
|
|
203
|
+
try {
|
|
204
|
+
unlinkSync(tempPath);
|
|
205
|
+
} catch {
|
|
206
|
+
// Best effort. A stale temp path is never read as runtime configuration.
|
|
212
207
|
}
|
|
213
208
|
}
|
|
214
209
|
|
package/src/proxy/dataDir.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { cpSync, existsSync, rmSync } from "node:fs";
|
|
1
|
+
import { cpSync, existsSync, readdirSync, renameSync, rmSync } from "node:fs";
|
|
2
2
|
import { isAbsolute, join } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ensurePrivateDirectorySync,
|
|
5
|
+
isPathTreeFreeOfIndirectionSync,
|
|
6
|
+
securePrivateTreeSync,
|
|
7
|
+
} from "./privateDataPath";
|
|
4
8
|
|
|
5
9
|
const CURRENT_DATA_DIR_NAME = ".agent-inspector";
|
|
6
10
|
const LEGACY_DATA_DIR_NAMES = [".llm-inspector", ".llm-agent"];
|
|
@@ -98,14 +102,46 @@ export function migrateLegacyDataDirs(): void {
|
|
|
98
102
|
const legacyDir = join(base, legacyName);
|
|
99
103
|
if (!existsSync(legacyDir)) continue;
|
|
100
104
|
|
|
105
|
+
const stagingDir = join(
|
|
106
|
+
base,
|
|
107
|
+
`${CURRENT_DATA_DIR_NAME}.migration-${String(process.pid)}-${String(Date.now())}`,
|
|
108
|
+
);
|
|
109
|
+
|
|
101
110
|
try {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
if (!
|
|
111
|
+
// cpSync may dereference junctions on some Windows runtimes. Reject the source tree before
|
|
112
|
+
// copying and recheck it afterwards so migration never imports through an indirection.
|
|
113
|
+
if (!isPathTreeFreeOfIndirectionSync(legacyDir)) return;
|
|
114
|
+
if (existsSync(currentDir)) {
|
|
115
|
+
// Never merge legacy state into an unknown or partially initialized destination. A caller
|
|
116
|
+
// can inspect it and retry after resolving the conflict; the authoritative legacy source
|
|
117
|
+
// remains untouched.
|
|
118
|
+
if (readdirSync(currentDir).length > 0) return;
|
|
119
|
+
rmSync(currentDir, { recursive: true, force: false });
|
|
120
|
+
}
|
|
121
|
+
if (!ensurePrivateDirectorySync(stagingDir)) return;
|
|
122
|
+
for (const entry of readdirSync(legacyDir)) {
|
|
123
|
+
cpSync(join(legacyDir, entry), join(stagingDir, entry), {
|
|
124
|
+
recursive: true,
|
|
125
|
+
force: false,
|
|
126
|
+
errorOnExist: true,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
if (!isPathTreeFreeOfIndirectionSync(legacyDir)) {
|
|
130
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (!securePrivateTreeSync(stagingDir)) {
|
|
134
|
+
rmSync(stagingDir, { recursive: true, force: true });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
renameSync(stagingDir, currentDir);
|
|
105
138
|
rmSync(legacyDir, { recursive: true, force: true });
|
|
139
|
+
return;
|
|
106
140
|
} catch {
|
|
107
|
-
//
|
|
108
|
-
//
|
|
141
|
+
// A failed staged migration never deletes the legacy source. Remove only this attempt's
|
|
142
|
+
// private sibling and retry on a later startup.
|
|
143
|
+
if (existsSync(stagingDir)) rmSync(stagingDir, { recursive: true, force: true });
|
|
144
|
+
return;
|
|
109
145
|
}
|
|
110
146
|
}
|
|
111
147
|
}
|