@tonyclaw/agent-inspector 2.0.0
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/cli.js +1611 -0
- package/.output/nitro.json +17 -0
- package/.output/public/assets/CompareDrawer-CU5ZrWcL.js +1 -0
- package/.output/public/assets/ProxyViewerContainer-pEBqVp1d.js +101 -0
- package/.output/public/assets/ReplayDialog-F58yNg5j.js +1 -0
- package/.output/public/assets/RequestAnatomy-C9lT0qE_.js +1 -0
- package/.output/public/assets/ResponseView-DHJq6bnz.js +1 -0
- package/.output/public/assets/StreamingChunkSequence-BTgfpFUT.js +1 -0
- package/.output/public/assets/_sessionId-DsNRbnNm.js +1 -0
- package/.output/public/assets/alibaba-TTwafVwX.svg +1 -0
- package/.output/public/assets/index-CpWG2hFn.css +1 -0
- package/.output/public/assets/index-DmBV8Gve.js +1 -0
- package/.output/public/assets/json-viewer-CZVYLR8j.js +14 -0
- package/.output/public/assets/main-DHs7FBK3.js +18 -0
- package/.output/public/assets/minimax-BPMzvuL-.jpeg +0 -0
- package/.output/public/assets/qwen-CONDcHqt.png +0 -0
- package/.output/public/assets/zhipuai-BPNAnxo-.svg +219 -0
- package/.output/server/_chunks/ssr-renderer.mjs +22 -0
- package/.output/server/_libs/@radix-ui/react-accessible-icon+[...].mjs +1 -0
- package/.output/server/_libs/@radix-ui/react-dismissable-layer+[...].mjs +210 -0
- package/.output/server/_libs/@radix-ui/react-navigation-menu+[...].mjs +2 -0
- package/.output/server/_libs/@radix-ui/react-one-time-password-field+[...].mjs +2 -0
- package/.output/server/_libs/@radix-ui/react-password-toggle-field+[...].mjs +2 -0
- package/.output/server/_libs/@radix-ui/react-use-callback-ref+[...].mjs +11 -0
- package/.output/server/_libs/@radix-ui/react-use-controllable-state+[...].mjs +69 -0
- package/.output/server/_libs/@radix-ui/react-use-effect-event+[...].mjs +1 -0
- package/.output/server/_libs/@radix-ui/react-use-escape-keydown+[...].mjs +17 -0
- package/.output/server/_libs/@radix-ui/react-use-is-hydrated+[...].mjs +1 -0
- package/.output/server/_libs/@radix-ui/react-use-layout-effect+[...].mjs +6 -0
- package/.output/server/_libs/@radix-ui/react-visually-hidden+[...].mjs +34 -0
- package/.output/server/_libs/ajv-formats.mjs +330 -0
- package/.output/server/_libs/ajv.mjs +11444 -0
- package/.output/server/_libs/aria-hidden.mjs +122 -0
- package/.output/server/_libs/atomically.mjs +152 -0
- package/.output/server/_libs/bail.mjs +8 -0
- package/.output/server/_libs/cfworker__json-schema.mjs +1 -0
- package/.output/server/_libs/character-entities.mjs +2130 -0
- package/.output/server/_libs/class-variance-authority.mjs +44 -0
- package/.output/server/_libs/clsx.mjs +16 -0
- package/.output/server/_libs/comma-separated-tokens.mjs +10 -0
- package/.output/server/_libs/conf.mjs +635 -0
- package/.output/server/_libs/cookie-es.mjs +58 -0
- package/.output/server/_libs/core-util-is.mjs +75 -0
- package/.output/server/_libs/croner.mjs +1 -0
- package/.output/server/_libs/crossws.mjs +1 -0
- package/.output/server/_libs/debounce-fn.mjs +69 -0
- package/.output/server/_libs/decode-named-character-reference+[...].mjs +8 -0
- package/.output/server/_libs/dequal.mjs +27 -0
- package/.output/server/_libs/detect-node-es.mjs +1 -0
- package/.output/server/_libs/devlop.mjs +8 -0
- package/.output/server/_libs/diff.mjs +320 -0
- package/.output/server/_libs/dot-prop.mjs +265 -0
- package/.output/server/_libs/env-paths.mjs +57 -0
- package/.output/server/_libs/estree-util-is-identifier-name.mjs +11 -0
- package/.output/server/_libs/extend.mjs +97 -0
- package/.output/server/_libs/fast-deep-equal.mjs +38 -0
- package/.output/server/_libs/fast-uri.mjs +812 -0
- package/.output/server/_libs/floating-ui__core.mjs +725 -0
- package/.output/server/_libs/floating-ui__dom.mjs +622 -0
- package/.output/server/_libs/floating-ui__react-dom.mjs +292 -0
- package/.output/server/_libs/floating-ui__utils.mjs +320 -0
- package/.output/server/_libs/get-nonce.mjs +9 -0
- package/.output/server/_libs/h3-v2.mjs +276 -0
- package/.output/server/_libs/h3.mjs +408 -0
- package/.output/server/_libs/hast-util-to-jsx-runtime.mjs +388 -0
- package/.output/server/_libs/hast-util-whitespace.mjs +10 -0
- package/.output/server/_libs/hookable.mjs +1 -0
- package/.output/server/_libs/html-url-attributes.mjs +26 -0
- package/.output/server/_libs/immediate.mjs +74 -0
- package/.output/server/_libs/inherits.mjs +50 -0
- package/.output/server/_libs/inline-style-parser.mjs +142 -0
- package/.output/server/_libs/is-plain-obj.mjs +10 -0
- package/.output/server/_libs/isarray.mjs +14 -0
- package/.output/server/_libs/isbot.mjs +20 -0
- package/.output/server/_libs/json-schema-traverse.mjs +180 -0
- package/.output/server/_libs/jszip.mjs +3051 -0
- package/.output/server/_libs/lie.mjs +273 -0
- package/.output/server/_libs/lucide-react.mjs +492 -0
- package/.output/server/_libs/mdast-util-from-markdown.mjs +717 -0
- package/.output/server/_libs/mdast-util-to-hast.mjs +710 -0
- package/.output/server/_libs/mdast-util-to-string.mjs +38 -0
- package/.output/server/_libs/micromark-core-commonmark.mjs +2259 -0
- package/.output/server/_libs/micromark-factory-destination.mjs +94 -0
- package/.output/server/_libs/micromark-factory-label.mjs +63 -0
- package/.output/server/_libs/micromark-factory-space.mjs +24 -0
- package/.output/server/_libs/micromark-factory-title.mjs +65 -0
- package/.output/server/_libs/micromark-factory-whitespace.mjs +22 -0
- package/.output/server/_libs/micromark-util-character.mjs +44 -0
- package/.output/server/_libs/micromark-util-chunked.mjs +36 -0
- package/.output/server/_libs/micromark-util-classify-character+[...].mjs +12 -0
- package/.output/server/_libs/micromark-util-combine-extensions+[...].mjs +41 -0
- package/.output/server/_libs/micromark-util-decode-numeric-character-reference+[...].mjs +19 -0
- package/.output/server/_libs/micromark-util-decode-string.mjs +21 -0
- package/.output/server/_libs/micromark-util-encode.mjs +1 -0
- package/.output/server/_libs/micromark-util-html-tag-name.mjs +69 -0
- package/.output/server/_libs/micromark-util-normalize-identifier+[...].mjs +6 -0
- package/.output/server/_libs/micromark-util-resolve-all.mjs +15 -0
- package/.output/server/_libs/micromark-util-sanitize-uri.mjs +41 -0
- package/.output/server/_libs/micromark-util-subtokenize.mjs +346 -0
- package/.output/server/_libs/micromark.mjs +906 -0
- package/.output/server/_libs/mimic-function.mjs +47 -0
- package/.output/server/_libs/modelcontextprotocol__server.mjs +9738 -0
- package/.output/server/_libs/ocache.mjs +1 -0
- package/.output/server/_libs/ohash.mjs +1 -0
- package/.output/server/_libs/pako.mjs +4223 -0
- package/.output/server/_libs/process-nextick-args.mjs +48 -0
- package/.output/server/_libs/property-information.mjs +1209 -0
- package/.output/server/_libs/radix-ui.mjs +1 -0
- package/.output/server/_libs/radix-ui__number.mjs +6 -0
- package/.output/server/_libs/radix-ui__primitive.mjs +11 -0
- package/.output/server/_libs/radix-ui__react-accordion.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-alert-dialog.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-arrow.mjs +23 -0
- package/.output/server/_libs/radix-ui__react-aspect-ratio.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-avatar.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-checkbox.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-collapsible.mjs +144 -0
- package/.output/server/_libs/radix-ui__react-collection.mjs +69 -0
- package/.output/server/_libs/radix-ui__react-compose-refs.mjs +39 -0
- package/.output/server/_libs/radix-ui__react-context-menu.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-context.mjs +78 -0
- package/.output/server/_libs/radix-ui__react-dialog.mjs +325 -0
- package/.output/server/_libs/radix-ui__react-direction.mjs +9 -0
- package/.output/server/_libs/radix-ui__react-dropdown-menu.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-focus-guards.mjs +29 -0
- package/.output/server/_libs/radix-ui__react-focus-scope.mjs +206 -0
- package/.output/server/_libs/radix-ui__react-form.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-hover-card.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-id.mjs +14 -0
- package/.output/server/_libs/radix-ui__react-label.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-menu.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-menubar.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-popover.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-popper.mjs +286 -0
- package/.output/server/_libs/radix-ui__react-portal.mjs +16 -0
- package/.output/server/_libs/radix-ui__react-presence.mjs +128 -0
- package/.output/server/_libs/radix-ui__react-primitive.mjs +42 -0
- package/.output/server/_libs/radix-ui__react-progress.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-radio-group.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-roving-focus.mjs +224 -0
- package/.output/server/_libs/radix-ui__react-scroll-area.mjs +721 -0
- package/.output/server/_libs/radix-ui__react-select.mjs +1163 -0
- package/.output/server/_libs/radix-ui__react-separator.mjs +28 -0
- package/.output/server/_libs/radix-ui__react-slider.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-slot.mjs +99 -0
- package/.output/server/_libs/radix-ui__react-switch.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-tabs.mjs +189 -0
- package/.output/server/_libs/radix-ui__react-toast.mjs +2 -0
- package/.output/server/_libs/radix-ui__react-toggle-group.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-toggle.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-toolbar.mjs +1 -0
- package/.output/server/_libs/radix-ui__react-tooltip.mjs +495 -0
- package/.output/server/_libs/radix-ui__react-use-previous.mjs +14 -0
- package/.output/server/_libs/radix-ui__react-use-size.mjs +39 -0
- package/.output/server/_libs/react-dom.mjs +10781 -0
- package/.output/server/_libs/react-markdown.mjs +147 -0
- package/.output/server/_libs/react-remove-scroll-bar.mjs +82 -0
- package/.output/server/_libs/react-remove-scroll.mjs +328 -0
- package/.output/server/_libs/react-style-singleton.mjs +69 -0
- package/.output/server/_libs/react.mjs +515 -0
- package/.output/server/_libs/readable-stream.mjs +1518 -0
- package/.output/server/_libs/remark-parse.mjs +19 -0
- package/.output/server/_libs/remark-rehype.mjs +21 -0
- package/.output/server/_libs/rou3.mjs +14 -0
- package/.output/server/_libs/safe-buffer.mjs +64 -0
- package/.output/server/_libs/semver.mjs +1938 -0
- package/.output/server/_libs/seroval-plugins.mjs +58 -0
- package/.output/server/_libs/seroval.mjs +1765 -0
- package/.output/server/_libs/setimmediate.mjs +152 -0
- package/.output/server/_libs/space-separated-tokens.mjs +6 -0
- package/.output/server/_libs/srvx.mjs +1029 -0
- package/.output/server/_libs/stubborn-fs.mjs +91 -0
- package/.output/server/_libs/stubborn-utils.mjs +66 -0
- package/.output/server/_libs/style-to-js.mjs +72 -0
- package/.output/server/_libs/style-to-object.mjs +38 -0
- package/.output/server/_libs/swr.mjs +939 -0
- package/.output/server/_libs/tailwind-merge.mjs +3010 -0
- package/.output/server/_libs/tanstack__history.mjs +217 -0
- package/.output/server/_libs/tanstack__react-router.mjs +1480 -0
- package/.output/server/_libs/tanstack__react-store.mjs +1 -0
- package/.output/server/_libs/tanstack__react-virtual.mjs +44 -0
- package/.output/server/_libs/tanstack__router-core.mjs +4827 -0
- package/.output/server/_libs/tanstack__store.mjs +1 -0
- package/.output/server/_libs/tanstack__virtual-core.mjs +1225 -0
- package/.output/server/_libs/tiny-invariant.mjs +12 -0
- package/.output/server/_libs/tiny-warning.mjs +5 -0
- package/.output/server/_libs/trim-lines.mjs +41 -0
- package/.output/server/_libs/trough.mjs +85 -0
- package/.output/server/_libs/tslib.mjs +1 -0
- package/.output/server/_libs/ufo.mjs +54 -0
- package/.output/server/_libs/uint8array-extras.mjs +69 -0
- package/.output/server/_libs/ungap__structured-clone.mjs +212 -0
- package/.output/server/_libs/unified.mjs +661 -0
- package/.output/server/_libs/unist-util-is.mjs +100 -0
- package/.output/server/_libs/unist-util-position.mjs +27 -0
- package/.output/server/_libs/unist-util-stringify-position.mjs +27 -0
- package/.output/server/_libs/unist-util-visit-parents.mjs +82 -0
- package/.output/server/_libs/unist-util-visit.mjs +24 -0
- package/.output/server/_libs/unstorage.mjs +1 -0
- package/.output/server/_libs/use-callback-ref.mjs +66 -0
- package/.output/server/_libs/use-sidecar.mjs +106 -0
- package/.output/server/_libs/use-sync-external-store.mjs +64 -0
- package/.output/server/_libs/util-deprecate.mjs +12 -0
- package/.output/server/_libs/vfile-message.mjs +138 -0
- package/.output/server/_libs/vfile.mjs +467 -0
- package/.output/server/_libs/when-exit.mjs +53 -0
- package/.output/server/_libs/zod.mjs +4524 -0
- package/.output/server/_sessionId-wMLPvC5g.mjs +123 -0
- package/.output/server/_ssr/CompareDrawer-BU4V0uVf.mjs +1041 -0
- package/.output/server/_ssr/ProxyViewerContainer-BnRwFEnn.mjs +5972 -0
- package/.output/server/_ssr/ReplayDialog-C7dn9pd_.mjs +322 -0
- package/.output/server/_ssr/RequestAnatomy-C1rWpe9-.mjs +353 -0
- package/.output/server/_ssr/ResponseView-hGpPaYsf.mjs +602 -0
- package/.output/server/_ssr/StreamingChunkSequence-BRWI1r_G.mjs +302 -0
- package/.output/server/_ssr/index-BKURLVPz.mjs +118 -0
- package/.output/server/_ssr/index.mjs +1184 -0
- package/.output/server/_ssr/json-viewer-BBd2DtQP.mjs +515 -0
- package/.output/server/_ssr/router-BcZ0D6AB.mjs +6317 -0
- package/.output/server/_ssr/start-HYkvq4Ni.mjs +4 -0
- package/.output/server/_tanstack-start-manifest_v-1y8ZVxRI.mjs +4 -0
- package/.output/server/index.mjs +436 -0
- package/.output/server/node_modules/tslib/modules/index.js +70 -0
- package/.output/server/node_modules/tslib/modules/package.json +3 -0
- package/.output/server/node_modules/tslib/package.json +47 -0
- package/.output/server/node_modules/tslib/tslib.js +484 -0
- package/.output/server/package.json +9 -0
- package/LICENSE +21 -0
- package/README.md +52 -0
- package/package.json +110 -0
- package/src/assets/favicon.svg +31 -0
- package/src/assets/logos/alibaba.svg +1 -0
- package/src/assets/logos/anthropic.svg +1 -0
- package/src/assets/logos/claude-code.svg +4 -0
- package/src/assets/logos/deepseek.svg +1 -0
- package/src/assets/logos/mcp.png +0 -0
- package/src/assets/logos/minimax.jpeg +0 -0
- package/src/assets/logos/openai.svg +1 -0
- package/src/assets/logos/opencode.svg +4 -0
- package/src/assets/logos/qwen.png +0 -0
- package/src/assets/logos/zhipuai.svg +219 -0
- package/src/cli/detect-tools.ts +147 -0
- package/src/cli/doctor.ts +521 -0
- package/src/cli/onboard.ts +224 -0
- package/src/cli/templates/command-onboard.ts +17 -0
- package/src/cli/templates/skill-onboard.ts +547 -0
- package/src/cli.ts +345 -0
- package/src/components/OnboardingBanner.tsx +67 -0
- package/src/components/ProxyViewer.tsx +545 -0
- package/src/components/ProxyViewerContainer.tsx +363 -0
- package/src/components/providers/ImportWizardDialog.tsx +349 -0
- package/src/components/providers/ProviderCard.tsx +474 -0
- package/src/components/providers/ProviderForm.tsx +494 -0
- package/src/components/providers/ProviderLogo.tsx +117 -0
- package/src/components/providers/ProvidersPanel.tsx +619 -0
- package/src/components/providers/SettingsDialog.tsx +202 -0
- package/src/components/proxy-viewer/CompareDrawer.tsx +893 -0
- package/src/components/proxy-viewer/ConversationGroup.tsx +107 -0
- package/src/components/proxy-viewer/ConversationHeader.tsx +300 -0
- package/src/components/proxy-viewer/LogEntry.tsx +543 -0
- package/src/components/proxy-viewer/LogEntryHeader.tsx +501 -0
- package/src/components/proxy-viewer/ReplayDialog.tsx +218 -0
- package/src/components/proxy-viewer/ResponseView.tsx +171 -0
- package/src/components/proxy-viewer/StreamingChunkSequence.tsx +188 -0
- package/src/components/proxy-viewer/ThreadConnector.tsx +136 -0
- package/src/components/proxy-viewer/TurnGroup.tsx +337 -0
- package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +98 -0
- package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +196 -0
- package/src/components/proxy-viewer/anatomy/tokenEstimate.ts +53 -0
- package/src/components/proxy-viewer/anatomy/types.ts +39 -0
- package/src/components/proxy-viewer/anatomy/useAnatomyJump.ts +114 -0
- package/src/components/proxy-viewer/cacheTrend.ts +50 -0
- package/src/components/proxy-viewer/diff/DiffView.tsx +321 -0
- package/src/components/proxy-viewer/diff/computeDiff.ts +178 -0
- package/src/components/proxy-viewer/diff/index.ts +3 -0
- package/src/components/proxy-viewer/formats/anthropic/ContentBlocks.tsx +157 -0
- package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +66 -0
- package/src/components/proxy-viewer/formats/anthropic/thinkingExtract.ts +21 -0
- package/src/components/proxy-viewer/formats/index.tsx +33 -0
- package/src/components/proxy-viewer/formats/openai/ResponseView.tsx +170 -0
- package/src/components/proxy-viewer/index.ts +9 -0
- package/src/components/proxy-viewer/lazy.ts +37 -0
- package/src/components/proxy-viewer/log-formats/anthropic.ts +194 -0
- package/src/components/proxy-viewer/log-formats/index.ts +23 -0
- package/src/components/proxy-viewer/log-formats/openai.ts +167 -0
- package/src/components/proxy-viewer/log-formats/types.ts +40 -0
- package/src/components/proxy-viewer/log-formats/unknown.ts +18 -0
- package/src/components/proxy-viewer/logEntryVisibility.ts +39 -0
- package/src/components/proxy-viewer/requestDiff.ts +277 -0
- package/src/components/proxy-viewer/useCopyFeedback.ts +36 -0
- package/src/components/proxy-viewer/useKeyboardNavigation.ts +190 -0
- package/src/components/proxy-viewer/viewerState.ts +66 -0
- package/src/components/ui/badge.tsx +47 -0
- package/src/components/ui/button.tsx +47 -0
- package/src/components/ui/collapsible.tsx +21 -0
- package/src/components/ui/confirm-dialog.tsx +51 -0
- package/src/components/ui/crab-logo.tsx +95 -0
- package/src/components/ui/crab-variants.tsx +467 -0
- package/src/components/ui/dialog.tsx +129 -0
- package/src/components/ui/json-expansion-button.tsx +56 -0
- package/src/components/ui/json-viewer-bulk.ts +97 -0
- package/src/components/ui/json-viewer.tsx +494 -0
- package/src/components/ui/mcp-logo.tsx +20 -0
- package/src/components/ui/scroll-area.tsx +54 -0
- package/src/components/ui/select.tsx +178 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/tabs.tsx +88 -0
- package/src/components/ui/tooltip.tsx +51 -0
- package/src/index.css +11 -0
- package/src/knowledge/candidateStore.ts +63 -0
- package/src/knowledge/distiller.ts +98 -0
- package/src/knowledge/openclawClient.ts +118 -0
- package/src/knowledge/redactor.ts +80 -0
- package/src/knowledge/types.ts +84 -0
- package/src/lib/apiClient.ts +49 -0
- package/src/lib/export-logs.ts +51 -0
- package/src/lib/mask.ts +4 -0
- package/src/lib/objectUtils.ts +22 -0
- package/src/lib/providerContract.ts +26 -0
- package/src/lib/providerTestContract.ts +107 -0
- package/src/lib/runtimeConfig.ts +25 -0
- package/src/lib/serverPort.ts +41 -0
- package/src/lib/sessionUrl.ts +44 -0
- package/src/lib/stopReason.ts +58 -0
- package/src/lib/useOnboarding.ts +80 -0
- package/src/lib/useProviders.ts +30 -0
- package/src/lib/useStripConfig.ts +108 -0
- package/src/lib/utils.ts +21 -0
- package/src/mcp/loopback.ts +76 -0
- package/src/mcp/previewExtractor.ts +166 -0
- package/src/mcp/server.ts +396 -0
- package/src/mcp/toolHandlers.ts +341 -0
- package/src/proxy/chunkStorage.ts +112 -0
- package/src/proxy/claudeCodeStrip.ts +99 -0
- package/src/proxy/config.ts +172 -0
- package/src/proxy/constants.ts +47 -0
- package/src/proxy/dataDir.ts +86 -0
- package/src/proxy/formats/anthropic/anthropicProvider.ts +75 -0
- package/src/proxy/formats/anthropic/handler.ts +71 -0
- package/src/proxy/formats/anthropic/index.ts +14 -0
- package/src/proxy/formats/anthropic/register.ts +4 -0
- package/src/proxy/formats/anthropic/schemas.ts +237 -0
- package/src/proxy/formats/anthropic/stream.ts +205 -0
- package/src/proxy/formats/handler.ts +46 -0
- package/src/proxy/formats/index.ts +12 -0
- package/src/proxy/formats/jsonSchema.ts +36 -0
- package/src/proxy/formats/openai/alibabaProvider.ts +38 -0
- package/src/proxy/formats/openai/handler.ts +96 -0
- package/src/proxy/formats/openai/index.ts +25 -0
- package/src/proxy/formats/openai/provider.ts +50 -0
- package/src/proxy/formats/openai/register.ts +4 -0
- package/src/proxy/formats/openai/schemas.ts +187 -0
- package/src/proxy/formats/openai/stream.ts +206 -0
- package/src/proxy/formats/protocol.ts +50 -0
- package/src/proxy/formats/providerRegistry.ts +51 -0
- package/src/proxy/formats/providers/index.ts +3 -0
- package/src/proxy/formats/registry.ts +66 -0
- package/src/proxy/handler.ts +334 -0
- package/src/proxy/logFinalizer.ts +305 -0
- package/src/proxy/logFinalizer.worker.ts +24 -0
- package/src/proxy/logIndex.ts +268 -0
- package/src/proxy/logger.ts +179 -0
- package/src/proxy/openaiOrphanToolStrip.ts +142 -0
- package/src/proxy/providerImporters.ts +491 -0
- package/src/proxy/providers.ts +613 -0
- package/src/proxy/schemas.ts +209 -0
- package/src/proxy/sessionProcess.ts +140 -0
- package/src/proxy/sessionRuntime.ts +85 -0
- package/src/proxy/sessionSupervisor.ts +283 -0
- package/src/proxy/sessionWorkerEntry.ts +26 -0
- package/src/proxy/socketTracker.ts +255 -0
- package/src/proxy/store.ts +412 -0
- package/src/proxy/upstream.ts +90 -0
- package/src/router.tsx +16 -0
- package/src/routes/__root.tsx +45 -0
- package/src/routes/api/config.paths.ts +14 -0
- package/src/routes/api/config.ts +53 -0
- package/src/routes/api/health.ts +15 -0
- package/src/routes/api/knowledge.candidates.$candidateId.promote.ts +32 -0
- package/src/routes/api/knowledge.candidates.ts +10 -0
- package/src/routes/api/knowledge.project-context.ts +18 -0
- package/src/routes/api/knowledge.search.ts +31 -0
- package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +16 -0
- package/src/routes/api/logs.$id.chunks.ts +36 -0
- package/src/routes/api/logs.$id.replay.ts +191 -0
- package/src/routes/api/logs.$id.ts +22 -0
- package/src/routes/api/logs.stream.ts +74 -0
- package/src/routes/api/logs.ts +59 -0
- package/src/routes/api/mcp.ts +25 -0
- package/src/routes/api/models.ts +10 -0
- package/src/routes/api/providers.$providerId.test.log.ts +293 -0
- package/src/routes/api/providers.$providerId.ts +50 -0
- package/src/routes/api/providers.export.ts +26 -0
- package/src/routes/api/providers.import.ts +47 -0
- package/src/routes/api/providers.scan.ts +23 -0
- package/src/routes/api/providers.ts +45 -0
- package/src/routes/api/sessions.ts +17 -0
- package/src/routes/index.tsx +6 -0
- package/src/routes/proxy/$.ts +15 -0
- package/src/routes/session/$sessionId.tsx +23 -0
- package/styles/globals.css +188 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { isAbsolute, join, resolve } from "node:path";
|
|
3
|
+
import { createConnection } from "node:net";
|
|
4
|
+
import { resolveDataDir } from "../proxy/dataDir";
|
|
5
|
+
|
|
6
|
+
const DEFAULT_PORT = 25947;
|
|
7
|
+
const PROBE_TIMEOUT_MS = 2000;
|
|
8
|
+
const EXTENSION_REQUIRED_FILES = [
|
|
9
|
+
"manifest.json",
|
|
10
|
+
"sidepanel.html",
|
|
11
|
+
"sidepanel.js",
|
|
12
|
+
"sidepanel.css",
|
|
13
|
+
"service-worker.js",
|
|
14
|
+
"icons/icon.svg",
|
|
15
|
+
"icons/icon-16.png",
|
|
16
|
+
"icons/icon-32.png",
|
|
17
|
+
"icons/icon-48.png",
|
|
18
|
+
"icons/icon-128.png",
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
export type DoctorSeverity = "pass" | "warn" | "fail";
|
|
22
|
+
|
|
23
|
+
export type DoctorCheck = {
|
|
24
|
+
name: string;
|
|
25
|
+
severity: DoctorSeverity;
|
|
26
|
+
message: string;
|
|
27
|
+
hint: string | null;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type DoctorOptions = {
|
|
31
|
+
port: number;
|
|
32
|
+
configDir: string | null;
|
|
33
|
+
providersJson: string | null;
|
|
34
|
+
help: boolean;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export type DoctorParseResult =
|
|
38
|
+
| { kind: "ok"; options: DoctorOptions }
|
|
39
|
+
| { kind: "error"; message: string };
|
|
40
|
+
|
|
41
|
+
export type HealthProbe = {
|
|
42
|
+
ok: boolean;
|
|
43
|
+
status: number | null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type DoctorDeps = {
|
|
47
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
48
|
+
platform: typeof process.platform;
|
|
49
|
+
cwd: string;
|
|
50
|
+
readText: (path: string) => string | null;
|
|
51
|
+
exists: (path: string) => boolean;
|
|
52
|
+
listDir: (path: string) => readonly string[] | null;
|
|
53
|
+
fetchHealth: (port: number) => Promise<HealthProbe>;
|
|
54
|
+
isPortOpen: (port: number) => Promise<boolean>;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export type DoctorReport = {
|
|
58
|
+
checks: readonly DoctorCheck[];
|
|
59
|
+
passCount: number;
|
|
60
|
+
warnCount: number;
|
|
61
|
+
failCount: number;
|
|
62
|
+
exitCode: number;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function check(name: string, severity: DoctorSeverity, message: string, hint = ""): DoctorCheck {
|
|
66
|
+
return {
|
|
67
|
+
name,
|
|
68
|
+
severity,
|
|
69
|
+
message,
|
|
70
|
+
hint: hint === "" ? null : hint,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function parsePort(raw: string | undefined): number | null {
|
|
75
|
+
if (raw === undefined || raw.trim() === "") return null;
|
|
76
|
+
const port = Number(raw);
|
|
77
|
+
if (!Number.isInteger(port) || port <= 0 || port > 65535) return null;
|
|
78
|
+
return port;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export function parseDoctorArgs(
|
|
82
|
+
argv: readonly string[],
|
|
83
|
+
env: Readonly<Record<string, string | undefined>> = process.env,
|
|
84
|
+
): DoctorParseResult {
|
|
85
|
+
const envPort = parsePort(env["PORT"]);
|
|
86
|
+
const options: DoctorOptions = {
|
|
87
|
+
port: envPort ?? DEFAULT_PORT,
|
|
88
|
+
configDir: null,
|
|
89
|
+
providersJson: null,
|
|
90
|
+
help: false,
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
for (let i = 0; i < argv.length; i++) {
|
|
94
|
+
const arg = argv[i];
|
|
95
|
+
switch (arg) {
|
|
96
|
+
case undefined:
|
|
97
|
+
continue;
|
|
98
|
+
case "--help":
|
|
99
|
+
case "-h":
|
|
100
|
+
options.help = true;
|
|
101
|
+
break;
|
|
102
|
+
case "--port":
|
|
103
|
+
case "-p": {
|
|
104
|
+
const parsed = parsePort(argv[i + 1]);
|
|
105
|
+
if (parsed === null) {
|
|
106
|
+
return { kind: "error", message: "doctor: --port must be an integer from 1 to 65535" };
|
|
107
|
+
}
|
|
108
|
+
options.port = parsed;
|
|
109
|
+
i++;
|
|
110
|
+
break;
|
|
111
|
+
}
|
|
112
|
+
case "--config-dir": {
|
|
113
|
+
const next = argv[i + 1];
|
|
114
|
+
if (next === undefined || next.trim() === "") {
|
|
115
|
+
return { kind: "error", message: "doctor: --config-dir requires a path argument" };
|
|
116
|
+
}
|
|
117
|
+
options.configDir = next;
|
|
118
|
+
i++;
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case "--providers": {
|
|
122
|
+
const next = argv[i + 1];
|
|
123
|
+
if (next === undefined || next.trim() === "") {
|
|
124
|
+
return { kind: "error", message: "doctor: --providers requires a JSON argument" };
|
|
125
|
+
}
|
|
126
|
+
options.providersJson = next;
|
|
127
|
+
i++;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
default:
|
|
131
|
+
return { kind: "error", message: `doctor: unknown option ${arg}` };
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return { kind: "ok", options };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function isObject(value: unknown): value is Record<string, unknown> {
|
|
139
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function providerCountFromParsed(value: unknown): number | null {
|
|
143
|
+
if (Array.isArray(value)) return value.length;
|
|
144
|
+
if (isObject(value)) {
|
|
145
|
+
const providers = value["providers"];
|
|
146
|
+
if (Array.isArray(providers)) return providers.length;
|
|
147
|
+
}
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function providerCountFromJson(raw: string): "invalid" | number | null {
|
|
152
|
+
try {
|
|
153
|
+
const parsed: unknown = JSON.parse(raw);
|
|
154
|
+
return providerCountFromParsed(parsed);
|
|
155
|
+
} catch {
|
|
156
|
+
return "invalid";
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function resolveMaybeRelative(base: string, value: string): string {
|
|
161
|
+
return isAbsolute(value) ? value : resolve(base, value);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function resolveDefaultDataDir(
|
|
165
|
+
env: Readonly<Record<string, string | undefined>>,
|
|
166
|
+
platform: typeof process.platform,
|
|
167
|
+
exists: (path: string) => boolean,
|
|
168
|
+
): string {
|
|
169
|
+
return resolveDataDir(exists, env, platform);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function providerConfigCandidates(options: DoctorOptions, deps: DoctorDeps): readonly string[] {
|
|
173
|
+
const explicitPath = deps.env["AGENT_INSPECTOR_CONFIG_PATH"];
|
|
174
|
+
if (explicitPath !== undefined && explicitPath !== "") {
|
|
175
|
+
return [resolveMaybeRelative(deps.cwd, explicitPath)];
|
|
176
|
+
}
|
|
177
|
+
if (options.configDir !== null) {
|
|
178
|
+
const dir = resolveMaybeRelative(deps.cwd, options.configDir);
|
|
179
|
+
return [join(dir, "providers.json"), join(dir, "config.json")];
|
|
180
|
+
}
|
|
181
|
+
const dataDir = resolveDefaultDataDir(deps.env, deps.platform, deps.exists);
|
|
182
|
+
return [join(dataDir, "providers.json"), join(dataDir, "config.json")];
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function checkProviderConfig(options: DoctorOptions, deps: DoctorDeps): DoctorCheck {
|
|
186
|
+
const providersJson = options.providersJson ?? deps.env["AGENT_INSPECTOR_PROVIDERS_JSON"] ?? null;
|
|
187
|
+
if (providersJson !== null) {
|
|
188
|
+
const count = providerCountFromJson(providersJson);
|
|
189
|
+
if (count === "invalid") {
|
|
190
|
+
return check(
|
|
191
|
+
"Provider config",
|
|
192
|
+
"fail",
|
|
193
|
+
"Provider JSON override is not valid JSON.",
|
|
194
|
+
"Fix --providers or AGENT_INSPECTOR_PROVIDERS_JSON; doctor never prints the raw value.",
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (count !== null) {
|
|
198
|
+
return check("Provider config", "pass", `${count} provider(s) found in JSON override.`);
|
|
199
|
+
}
|
|
200
|
+
return check(
|
|
201
|
+
"Provider config",
|
|
202
|
+
"fail",
|
|
203
|
+
"Provider JSON override does not look like a provider array or { providers } object.",
|
|
204
|
+
"Use an exported providers JSON payload or configure providers in the UI.",
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const candidates = providerConfigCandidates(options, deps);
|
|
209
|
+
for (const candidate of candidates) {
|
|
210
|
+
if (!deps.exists(candidate)) continue;
|
|
211
|
+
const text = deps.readText(candidate);
|
|
212
|
+
if (text === null) {
|
|
213
|
+
return check(
|
|
214
|
+
"Provider config",
|
|
215
|
+
"fail",
|
|
216
|
+
`Provider config exists but could not be read: ${candidate}`,
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const count = providerCountFromJson(text);
|
|
220
|
+
if (count === "invalid") {
|
|
221
|
+
return check("Provider config", "fail", `Provider config is invalid JSON: ${candidate}`);
|
|
222
|
+
}
|
|
223
|
+
if (count !== null && count > 0) {
|
|
224
|
+
return check("Provider config", "pass", `${count} provider(s) configured.`);
|
|
225
|
+
}
|
|
226
|
+
return check(
|
|
227
|
+
"Provider config",
|
|
228
|
+
"warn",
|
|
229
|
+
`Provider config exists but no providers were found: ${candidate}`,
|
|
230
|
+
"Add a provider in Settings or import provider settings.",
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return check(
|
|
235
|
+
"Provider config",
|
|
236
|
+
"warn",
|
|
237
|
+
"No provider config was found.",
|
|
238
|
+
"Add a provider in the web UI, import providers, or pass --providers for this check.",
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function checkProxyHealth(port: number, deps: DoctorDeps): Promise<DoctorCheck> {
|
|
243
|
+
const health = await deps.fetchHealth(port);
|
|
244
|
+
const url = `http://localhost:${port}`;
|
|
245
|
+
if (health.ok) {
|
|
246
|
+
return check(
|
|
247
|
+
"Proxy health",
|
|
248
|
+
"pass",
|
|
249
|
+
`agent-inspector is healthy at ${url}.`,
|
|
250
|
+
`Proxy URL: ${url}/proxy`,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
if (await deps.isPortOpen(port)) {
|
|
255
|
+
const suffix = health.status === null ? "" : ` (HTTP ${health.status})`;
|
|
256
|
+
return check(
|
|
257
|
+
"Proxy health",
|
|
258
|
+
"fail",
|
|
259
|
+
`Port ${port} is accepting connections, but /api/health is not healthy${suffix}.`,
|
|
260
|
+
"Stop that process, choose --port <n>, or start agent-inspector with --force-restart.",
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return check(
|
|
265
|
+
"Proxy health",
|
|
266
|
+
"warn",
|
|
267
|
+
`No process is listening on port ${port}.`,
|
|
268
|
+
"Start with `agent-inspector`, `agent-inspector --background`, or `bun run dev`.",
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
function findProjectRoot(startDir: string, deps: Pick<DoctorDeps, "exists">): string {
|
|
273
|
+
let current = resolve(startDir);
|
|
274
|
+
for (let i = 0; i < 6; i++) {
|
|
275
|
+
if (deps.exists(join(current, "package.json"))) return current;
|
|
276
|
+
const next = resolve(current, "..");
|
|
277
|
+
if (next === current) return startDir;
|
|
278
|
+
current = next;
|
|
279
|
+
}
|
|
280
|
+
return startDir;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function checkPackage(rootDir: string, deps: DoctorDeps): DoctorCheck {
|
|
284
|
+
const packagePath = join(rootDir, "package.json");
|
|
285
|
+
const text = deps.readText(packagePath);
|
|
286
|
+
if (text === null) {
|
|
287
|
+
return check("Package metadata", "warn", "package.json was not found near the CLI bundle.");
|
|
288
|
+
}
|
|
289
|
+
try {
|
|
290
|
+
const parsed: unknown = JSON.parse(text);
|
|
291
|
+
if (!isObject(parsed)) {
|
|
292
|
+
return check("Package metadata", "warn", "package.json is not an object.");
|
|
293
|
+
}
|
|
294
|
+
const name = parsed["name"];
|
|
295
|
+
const version = parsed["version"];
|
|
296
|
+
if (typeof name === "string" && typeof version === "string") {
|
|
297
|
+
return check("Package metadata", "pass", `${name}@${version}`);
|
|
298
|
+
}
|
|
299
|
+
return check("Package metadata", "warn", "package.json is missing name or version.");
|
|
300
|
+
} catch {
|
|
301
|
+
return check("Package metadata", "warn", "package.json is not valid JSON.");
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function checkExtensionSource(rootDir: string, deps: DoctorDeps): DoctorCheck {
|
|
306
|
+
const extensionDir = join(rootDir, "extensions", "chrome");
|
|
307
|
+
const missing = EXTENSION_REQUIRED_FILES.filter((file) => !deps.exists(join(extensionDir, file)));
|
|
308
|
+
if (missing.length === 0) {
|
|
309
|
+
return check(
|
|
310
|
+
"Chrome extension source",
|
|
311
|
+
"pass",
|
|
312
|
+
"Manifest, side panel, service worker, and icons are present.",
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
return check(
|
|
316
|
+
"Chrome extension source",
|
|
317
|
+
"fail",
|
|
318
|
+
`Missing ${missing.length} Chrome extension file(s): ${missing.join(", ")}`,
|
|
319
|
+
"Restore the extension files before packaging or loading unpacked.",
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function extensionManifestVersion(rootDir: string, deps: DoctorDeps): string | null {
|
|
324
|
+
const manifestText = deps.readText(join(rootDir, "extensions", "chrome", "manifest.json"));
|
|
325
|
+
if (manifestText === null) return null;
|
|
326
|
+
try {
|
|
327
|
+
const manifest: unknown = JSON.parse(manifestText);
|
|
328
|
+
if (!isObject(manifest)) return null;
|
|
329
|
+
const version = manifest["version"];
|
|
330
|
+
return typeof version === "string" && version !== "" ? version : null;
|
|
331
|
+
} catch {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function checkExtensionPackage(rootDir: string, deps: DoctorDeps): DoctorCheck {
|
|
337
|
+
const distDir = join(rootDir, "dist", "chrome-extension");
|
|
338
|
+
const files = deps.listDir(distDir);
|
|
339
|
+
if (files === null) {
|
|
340
|
+
return check(
|
|
341
|
+
"Chrome extension package",
|
|
342
|
+
"warn",
|
|
343
|
+
"No packaged Chrome extension artifact was found.",
|
|
344
|
+
"Run `npm run extension:zip` before Chrome Web Store upload.",
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const manifestVersion = extensionManifestVersion(rootDir, deps);
|
|
349
|
+
if (manifestVersion !== null) {
|
|
350
|
+
const zipName = `agent-inspector-companion-v${manifestVersion}.zip`;
|
|
351
|
+
const checksumName = `${zipName}.sha256`;
|
|
352
|
+
const hasZip = files.includes(zipName);
|
|
353
|
+
const hasChecksum = files.includes(checksumName);
|
|
354
|
+
if (hasZip && hasChecksum) {
|
|
355
|
+
return check("Chrome extension package", "pass", `${zipName} with checksum is present.`);
|
|
356
|
+
}
|
|
357
|
+
if (hasZip) {
|
|
358
|
+
return check(
|
|
359
|
+
"Chrome extension package",
|
|
360
|
+
"warn",
|
|
361
|
+
`${zipName} exists but no .sha256 checksum was found.`,
|
|
362
|
+
"Run `npm run extension:zip` to regenerate the zip and checksum.",
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
return check(
|
|
366
|
+
"Chrome extension package",
|
|
367
|
+
"warn",
|
|
368
|
+
`Current Chrome extension package was not found: ${zipName}`,
|
|
369
|
+
"Run `npm run extension:zip` before Chrome Web Store upload.",
|
|
370
|
+
);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const zip = files.find((file) => file.endsWith(".zip"));
|
|
374
|
+
const checksum = files.find((file) => file.endsWith(".zip.sha256"));
|
|
375
|
+
if (zip !== undefined && checksum !== undefined) {
|
|
376
|
+
return check("Chrome extension package", "pass", `${zip} with checksum is present.`);
|
|
377
|
+
}
|
|
378
|
+
if (zip !== undefined) {
|
|
379
|
+
return check(
|
|
380
|
+
"Chrome extension package",
|
|
381
|
+
"warn",
|
|
382
|
+
`${zip} exists but no .sha256 checksum was found.`,
|
|
383
|
+
"Run `npm run extension:zip` to regenerate the zip and checksum.",
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
return check(
|
|
387
|
+
"Chrome extension package",
|
|
388
|
+
"warn",
|
|
389
|
+
"No Chrome extension zip artifact was found.",
|
|
390
|
+
"Run `npm run extension:zip` before Chrome Web Store upload.",
|
|
391
|
+
);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
export async function buildDoctorReport(
|
|
395
|
+
options: DoctorOptions,
|
|
396
|
+
deps: DoctorDeps = createDoctorDeps(),
|
|
397
|
+
): Promise<DoctorReport> {
|
|
398
|
+
const rootDir = findProjectRoot(deps.cwd, deps);
|
|
399
|
+
const checks = [
|
|
400
|
+
await checkProxyHealth(options.port, deps),
|
|
401
|
+
checkProviderConfig(options, deps),
|
|
402
|
+
checkPackage(rootDir, deps),
|
|
403
|
+
checkExtensionSource(rootDir, deps),
|
|
404
|
+
checkExtensionPackage(rootDir, deps),
|
|
405
|
+
];
|
|
406
|
+
|
|
407
|
+
const passCount = checks.filter((item) => item.severity === "pass").length;
|
|
408
|
+
const warnCount = checks.filter((item) => item.severity === "warn").length;
|
|
409
|
+
const failCount = checks.filter((item) => item.severity === "fail").length;
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
checks,
|
|
413
|
+
passCount,
|
|
414
|
+
warnCount,
|
|
415
|
+
failCount,
|
|
416
|
+
exitCode: failCount > 0 ? 1 : 0,
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
export function formatDoctorReport(report: DoctorReport): string {
|
|
421
|
+
const lines = ["agent-inspector doctor", ""];
|
|
422
|
+
for (const item of report.checks) {
|
|
423
|
+
lines.push(`${item.severity.toUpperCase().padEnd(4)} ${item.name}: ${item.message}`);
|
|
424
|
+
if (item.hint !== null) {
|
|
425
|
+
lines.push(` ${item.hint}`);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
lines.push("");
|
|
429
|
+
lines.push(
|
|
430
|
+
`Summary: ${report.passCount} pass, ${report.warnCount} warn, ${report.failCount} fail`,
|
|
431
|
+
);
|
|
432
|
+
return `${lines.join("\n")}\n`;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
export function doctorHelp(): string {
|
|
436
|
+
return [
|
|
437
|
+
"agent-inspector doctor",
|
|
438
|
+
"",
|
|
439
|
+
"Usage:",
|
|
440
|
+
" agent-inspector doctor [--port <port>] [--config-dir <dir>] [--providers <json>]",
|
|
441
|
+
"",
|
|
442
|
+
"Checks local proxy health, provider config presence, package metadata, and Chrome companion readiness.",
|
|
443
|
+
"",
|
|
444
|
+
].join("\n");
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async function fetchHealth(port: number): Promise<HealthProbe> {
|
|
448
|
+
const controller = new AbortController();
|
|
449
|
+
const timeout = setTimeout(() => controller.abort(), PROBE_TIMEOUT_MS);
|
|
450
|
+
try {
|
|
451
|
+
const response = await fetch(`http://127.0.0.1:${port}/api/health`, {
|
|
452
|
+
cache: "no-store",
|
|
453
|
+
signal: controller.signal,
|
|
454
|
+
});
|
|
455
|
+
return { ok: response.ok, status: response.status };
|
|
456
|
+
} catch {
|
|
457
|
+
return { ok: false, status: null };
|
|
458
|
+
} finally {
|
|
459
|
+
clearTimeout(timeout);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function isPortOpen(port: number): Promise<boolean> {
|
|
464
|
+
return new Promise((resolveOpen) => {
|
|
465
|
+
const socket = createConnection({ host: "127.0.0.1", port });
|
|
466
|
+
const finish = (value: boolean): void => {
|
|
467
|
+
socket.removeAllListeners();
|
|
468
|
+
socket.destroy();
|
|
469
|
+
resolveOpen(value);
|
|
470
|
+
};
|
|
471
|
+
|
|
472
|
+
socket.setTimeout(PROBE_TIMEOUT_MS);
|
|
473
|
+
socket.once("connect", () => finish(true));
|
|
474
|
+
socket.once("timeout", () => finish(false));
|
|
475
|
+
socket.once("error", () => finish(false));
|
|
476
|
+
});
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function readText(path: string): string | null {
|
|
480
|
+
try {
|
|
481
|
+
return readFileSync(path, "utf8");
|
|
482
|
+
} catch {
|
|
483
|
+
return null;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
function listDir(path: string): readonly string[] | null {
|
|
488
|
+
try {
|
|
489
|
+
return readdirSync(path);
|
|
490
|
+
} catch {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
export function createDoctorDeps(): DoctorDeps {
|
|
496
|
+
return {
|
|
497
|
+
env: process.env,
|
|
498
|
+
platform: process.platform,
|
|
499
|
+
cwd: process.cwd(),
|
|
500
|
+
exists: existsSync,
|
|
501
|
+
readText,
|
|
502
|
+
listDir,
|
|
503
|
+
fetchHealth,
|
|
504
|
+
isPortOpen,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
export async function runDoctor(argv: readonly string[]): Promise<number> {
|
|
509
|
+
const parsed = parseDoctorArgs(argv);
|
|
510
|
+
if (parsed.kind === "error") {
|
|
511
|
+
process.stderr.write(`${parsed.message}\n`);
|
|
512
|
+
return 2;
|
|
513
|
+
}
|
|
514
|
+
if (parsed.options.help) {
|
|
515
|
+
process.stdout.write(doctorHelp());
|
|
516
|
+
return 0;
|
|
517
|
+
}
|
|
518
|
+
const report = await buildDoctorReport(parsed.options);
|
|
519
|
+
process.stdout.write(formatDoctorReport(report));
|
|
520
|
+
return report.exitCode;
|
|
521
|
+
}
|