codebase-onboarder 0.5.0 → 0.7.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/README.md +196 -47
- package/bin/build-if-source.js +23 -0
- package/cli/commands.d.ts +26 -0
- package/cli/commands.js +836 -811
- package/cli/commands.js.map +1 -0
- package/cli/explorer/advanced.d.ts +14 -0
- package/cli/explorer/advanced.js +449 -0
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +396 -229
- package/cli/explorer/app.js.map +1 -0
- package/cli/explorer/assistant.d.ts +9 -0
- package/cli/explorer/assistant.js +58 -0
- package/cli/explorer/assistant.js.map +1 -0
- package/cli/explorer/commands.d.ts +17 -0
- package/cli/explorer/commands.js +400 -162
- package/cli/explorer/commands.js.map +1 -0
- package/cli/explorer/featureViews.d.ts +124 -0
- package/cli/explorer/featureViews.js +179 -0
- package/cli/explorer/featureViews.js.map +1 -0
- package/cli/explorer/github.d.ts +21 -0
- package/cli/explorer/github.js +73 -0
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +173 -0
- package/cli/explorer/graphs.js.map +1 -0
- package/cli/explorer/picker.d.ts +22 -0
- package/cli/explorer/picker.js +150 -0
- package/cli/explorer/picker.js.map +1 -0
- package/cli/explorer/report.d.ts +85 -0
- package/cli/explorer/report.js +60 -0
- package/cli/explorer/report.js.map +1 -0
- package/cli/explorer/session.d.ts +449 -0
- package/cli/explorer/session.js +184 -95
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +496 -412
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +33 -0
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +235 -138
- package/cli/main.js.map +1 -0
- package/cli/prompt.d.ts +5 -0
- package/cli/prompt.js +84 -80
- package/cli/prompt.js.map +1 -0
- package/cli/scanOptions.d.ts +2 -0
- package/cli/scanOptions.js +11 -0
- package/cli/scanOptions.js.map +1 -0
- package/cli/ui.d.ts +33 -0
- package/cli/ui.js +55 -35
- package/cli/ui.js.map +1 -0
- package/cli/wizard.d.ts +187 -0
- package/cli/wizard.js +304 -284
- package/cli/wizard.js.map +1 -0
- package/package.json +15 -4
- package/public/app.d.ts +1 -0
- package/public/app.js +1057 -1009
- package/public/app.js.map +1 -0
- package/public/browser.d.ts +68 -0
- package/public/browser.js +2 -0
- package/public/browser.js.map +1 -0
- package/public/index.html +30 -13
- package/public/js/about.d.ts +6 -0
- package/public/js/about.js +165 -172
- package/public/js/about.js.map +1 -0
- package/public/js/aiDraft.d.ts +3 -0
- package/public/js/aiDraft.js +116 -124
- package/public/js/aiDraft.js.map +1 -0
- package/public/js/analysisPanel.d.ts +7 -0
- package/public/js/analysisPanel.js +166 -166
- package/public/js/analysisPanel.js.map +1 -0
- package/public/js/analysisReport.d.ts +38 -0
- package/public/js/analysisReport.js +105 -110
- package/public/js/analysisReport.js.map +1 -0
- package/public/js/api.d.ts +26 -0
- package/public/js/api.js +176 -167
- package/public/js/api.js.map +1 -0
- package/public/js/atlas.d.ts +6 -0
- package/public/js/atlas.js +50 -58
- package/public/js/atlas.js.map +1 -0
- package/public/js/blameView.d.ts +2 -0
- package/public/js/blameView.js +36 -37
- package/public/js/blameView.js.map +1 -0
- package/public/js/codeTab.d.ts +3 -0
- package/public/js/codeTab.js +175 -180
- package/public/js/codeTab.js.map +1 -0
- package/public/js/codeViewer.d.ts +5 -0
- package/public/js/codeViewer.js +162 -150
- package/public/js/codeViewer.js.map +1 -0
- package/public/js/components/FileChip.d.ts +9 -0
- package/public/js/components/FileChip.js +45 -49
- package/public/js/components/FileChip.js.map +1 -0
- package/public/js/components/MetricSparkline.d.ts +7 -0
- package/public/js/components/MetricSparkline.js +35 -44
- package/public/js/components/MetricSparkline.js.map +1 -0
- package/public/js/components/RiskBadge.d.ts +9 -0
- package/public/js/components/RiskBadge.js +55 -63
- package/public/js/components/RiskBadge.js.map +1 -0
- package/public/js/deepAnalysisView.d.ts +99 -0
- package/public/js/deepAnalysisView.js +282 -302
- package/public/js/deepAnalysisView.js.map +1 -0
- package/public/js/diagramPane.d.ts +8 -0
- package/public/js/diagramPane.js +133 -135
- package/public/js/diagramPane.js.map +1 -0
- package/public/js/diffView.d.ts +6 -0
- package/public/js/diffView.js +222 -209
- package/public/js/diffView.js.map +1 -0
- package/public/js/docsView.d.ts +2 -0
- package/public/js/docsView.js +441 -442
- package/public/js/docsView.js.map +1 -0
- package/public/js/dom.d.ts +189 -0
- package/public/js/dom.js +5 -0
- package/public/js/dom.js.map +1 -0
- package/public/js/fileSourceBrowser.d.ts +5 -0
- package/public/js/fileSourceBrowser.js +33 -41
- package/public/js/fileSourceBrowser.js.map +1 -0
- package/public/js/flameGraph.d.ts +5 -0
- package/public/js/flameGraph.js +62 -72
- package/public/js/flameGraph.js.map +1 -0
- package/public/js/forceGraph.d.ts +10 -0
- package/public/js/forceGraph.js +581 -556
- package/public/js/forceGraph.js.map +1 -0
- package/public/js/heatmap.d.ts +4 -0
- package/public/js/heatmap.js +142 -164
- package/public/js/heatmap.js.map +1 -0
- package/public/js/highlight.d.ts +2 -0
- package/public/js/highlight.js +116 -107
- package/public/js/highlight.js.map +1 -0
- package/public/js/html.d.ts +2 -0
- package/public/js/html.js +14 -44
- package/public/js/html.js.map +1 -0
- package/public/js/insightsView.d.ts +5 -0
- package/public/js/insightsView.js +93 -111
- package/public/js/insightsView.js.map +1 -0
- package/public/js/inspector.d.ts +37 -0
- package/public/js/inspector.js +416 -445
- package/public/js/inspector.js.map +1 -0
- package/public/js/llm.d.ts +113 -0
- package/public/js/llm.js +233 -272
- package/public/js/llm.js.map +1 -0
- package/public/js/mapView.d.ts +3 -0
- package/public/js/mapView.js +121 -120
- package/public/js/mapView.js.map +1 -0
- package/public/js/markdown.d.ts +3 -0
- package/public/js/markdown.js +84 -91
- package/public/js/markdown.js.map +1 -0
- package/public/js/mindmap.d.ts +32 -0
- package/public/js/mindmap.js +244 -259
- package/public/js/mindmap.js.map +1 -0
- package/public/js/mobilePanels.d.ts +5 -0
- package/public/js/mobilePanels.js +50 -0
- package/public/js/mobilePanels.js.map +1 -0
- package/public/js/repoFiles.d.ts +12 -0
- package/public/js/repoFiles.js +28 -27
- package/public/js/repoFiles.js.map +1 -0
- package/public/js/reviewView.d.ts +28 -0
- package/public/js/reviewView.js +256 -0
- package/public/js/reviewView.js.map +1 -0
- package/public/js/sbomView.d.ts +3 -0
- package/public/js/sbomView.js +59 -67
- package/public/js/sbomView.js.map +1 -0
- package/public/js/scanCache.d.ts +16 -0
- package/public/js/scanCache.js +67 -65
- package/public/js/scanCache.js.map +1 -0
- package/public/js/search.d.ts +7 -0
- package/public/js/search.js +868 -800
- package/public/js/search.js.map +1 -0
- package/public/js/searchLocal.d.ts +42 -0
- package/public/js/searchLocal.js +87 -0
- package/public/js/searchLocal.js.map +1 -0
- package/public/js/serverSettings.d.ts +5 -0
- package/public/js/serverSettings.js +153 -164
- package/public/js/serverSettings.js.map +1 -0
- package/public/js/state.d.ts +798 -0
- package/public/js/state.js +114 -122
- package/public/js/state.js.map +1 -0
- package/public/js/tour.d.ts +6 -0
- package/public/js/tour.js +5 -7
- package/public/js/tour.js.map +1 -0
- package/public/js/transitions.d.ts +2 -0
- package/public/js/transitions.js +9 -10
- package/public/js/transitions.js.map +1 -0
- package/public/js/tree.d.ts +12 -0
- package/public/js/tree.js +157 -154
- package/public/js/tree.js.map +1 -0
- package/public/js/workflowsView.d.ts +3 -0
- package/public/js/workflowsView.js +15 -22
- package/public/js/workflowsView.js.map +1 -0
- package/public/search.css +495 -0
- package/public/styles.css +163 -346
- package/public/workbench.css +166 -0
- package/server/apiAuth.d.ts +3 -0
- package/server/apiAuth.js +18 -20
- package/server/apiAuth.js.map +1 -0
- package/server/apiDiff.d.ts +2 -0
- package/server/apiDiff.js +20 -18
- package/server/apiDiff.js.map +1 -0
- package/server/apiDocs.d.ts +2 -0
- package/server/apiDocs.js +38 -40
- package/server/apiDocs.js.map +1 -0
- package/server/apiFile.d.ts +1 -0
- package/server/apiFile.js +14 -17
- package/server/apiFile.js.map +1 -0
- package/server/apiGitBlame.d.ts +2 -0
- package/server/apiGitBlame.js +50 -51
- package/server/apiGitBlame.js.map +1 -0
- package/server/apiMcp.d.ts +4 -0
- package/server/apiMcp.js +64 -66
- package/server/apiMcp.js.map +1 -0
- package/server/apiReview.d.ts +2 -0
- package/server/apiReview.js +45 -0
- package/server/apiReview.js.map +1 -0
- package/server/apiScan.d.ts +5 -0
- package/server/apiScan.js +90 -71
- package/server/apiScan.js.map +1 -0
- package/server/apiSearch.d.ts +33 -0
- package/server/apiSearch.js +184 -200
- package/server/apiSearch.js.map +1 -0
- package/server/apiSettings.d.ts +4 -0
- package/server/apiSettings.js +84 -85
- package/server/apiSettings.js.map +1 -0
- package/server/apiTools.d.ts +3 -0
- package/server/apiTools.js +55 -56
- package/server/apiTools.js.map +1 -0
- package/server/auth.d.ts +5 -0
- package/server/auth.js +54 -51
- package/server/auth.js.map +1 -0
- package/server/config.d.ts +42 -0
- package/server/config.js +189 -194
- package/server/config.js.map +1 -0
- package/server/daemon.d.ts +12 -0
- package/server/daemon.js +124 -114
- package/server/daemon.js.map +1 -0
- package/server/fileSourceNode.d.ts +2 -0
- package/server/fileSourceNode.js +34 -36
- package/server/fileSourceNode.js.map +1 -0
- package/server/gitClone.d.ts +9 -0
- package/server/gitClone.js +59 -61
- package/server/gitClone.js.map +1 -0
- package/server/gitDiff.d.ts +36 -0
- package/server/gitDiff.js +271 -169
- package/server/gitDiff.js.map +1 -0
- package/server/gitHistory.d.ts +12 -0
- package/server/gitHistory.js +80 -80
- package/server/gitHistory.js.map +1 -0
- package/server/gitRemote.d.ts +12 -0
- package/server/gitRemote.js +60 -0
- package/server/gitRemote.js.map +1 -0
- package/server/htmlText.d.ts +4 -0
- package/server/htmlText.js +16 -23
- package/server/htmlText.js.map +1 -0
- package/server/http.d.ts +5 -0
- package/server/http.js +27 -30
- package/server/http.js.map +1 -0
- package/server/httpGuards.d.ts +2 -0
- package/server/httpGuards.js +47 -43
- package/server/httpGuards.js.map +1 -0
- package/server/https.d.ts +34 -0
- package/server/https.js +121 -111
- package/server/https.js.map +1 -0
- package/server/index.d.ts +40 -0
- package/server/index.js +139 -147
- package/server/index.js.map +1 -0
- package/server/layout.d.ts +26 -0
- package/server/layout.js +59 -37
- package/server/layout.js.map +1 -0
- package/server/llmProxy.d.ts +3 -0
- package/server/llmProxy.js +137 -135
- package/server/llmProxy.js.map +1 -0
- package/server/logger.d.ts +38 -0
- package/server/logger.js +198 -211
- package/server/logger.js.map +1 -0
- package/server/mcp/analysis.d.ts +29 -0
- package/server/mcp/analysis.js +99 -120
- package/server/mcp/analysis.js.map +1 -0
- package/server/mcp/http.d.ts +9 -0
- package/server/mcp/http.js +128 -137
- package/server/mcp/http.js.map +1 -0
- package/server/mcp/runner.d.ts +68 -0
- package/server/mcp/runner.js +208 -218
- package/server/mcp/runner.js.map +1 -0
- package/server/mcp/server.d.ts +29 -0
- package/server/mcp/server.js +166 -179
- package/server/mcp/server.js.map +1 -0
- package/server/mcp/standalone.d.ts +1 -0
- package/server/mcp/standalone.js +8 -10
- package/server/mcp/standalone.js.map +1 -0
- package/server/mcp/tools.d.ts +2020 -0
- package/server/mcp/tools.js +523 -574
- package/server/mcp/tools.js.map +1 -0
- package/server/paths.d.ts +3 -0
- package/server/paths.js +17 -15
- package/server/paths.js.map +1 -0
- package/server/pidfile.d.ts +9 -0
- package/server/pidfile.js +43 -45
- package/server/pidfile.js.map +1 -0
- package/server/review.d.ts +5 -0
- package/server/review.js +35 -0
- package/server/review.js.map +1 -0
- package/server/router.d.ts +33 -0
- package/server/router.js +191 -197
- package/server/router.js.map +1 -0
- package/server/scanRequest.d.ts +3 -0
- package/server/scanRequest.js +36 -0
- package/server/scanRequest.js.map +1 -0
- package/server/searchIndex.d.ts +17 -0
- package/server/searchIndex.js +83 -80
- package/server/searchIndex.js.map +1 -0
- package/server/sessions.d.ts +14 -0
- package/server/sessions.js +62 -70
- package/server/sessions.js.map +1 -0
- package/server/startup.d.ts +118 -0
- package/server/startup.js +143 -148
- package/server/startup.js.map +1 -0
- package/server/static.d.ts +6 -0
- package/server/static.js +28 -31
- package/server/static.js.map +1 -0
- package/server/tools/install.d.ts +4 -0
- package/server/tools/install.js +176 -185
- package/server/tools/install.js.map +1 -0
- package/server/tools/parse.d.ts +8 -0
- package/server/tools/parse.js +112 -114
- package/server/tools/parse.js.map +1 -0
- package/server/tools/platform.d.ts +9 -0
- package/server/tools/platform.js +49 -47
- package/server/tools/platform.js.map +1 -0
- package/server/tools/registry.d.ts +137 -0
- package/server/tools/registry.js +173 -172
- package/server/tools/registry.js.map +1 -0
- package/server/tools/scan.d.ts +34 -0
- package/server/tools/scan.js +89 -98
- package/server/tools/scan.js.map +1 -0
- package/server/tools.d.ts +34 -0
- package/server/tools.js +94 -107
- package/server/tools.js.map +1 -0
- package/server/tunnel.d.ts +29 -0
- package/server/tunnel.js +61 -66
- package/server/tunnel.js.map +1 -0
- package/shared/analyzer/docs.d.ts +16 -0
- package/shared/analyzer/docs.js +99 -93
- package/shared/analyzer/docs.js.map +1 -0
- package/shared/analyzer/explainLocal.d.ts +4 -0
- package/shared/analyzer/explainLocal.js +122 -142
- package/shared/analyzer/explainLocal.js.map +1 -0
- package/shared/analyzer/github.d.ts +37 -0
- package/shared/analyzer/github.js +79 -0
- package/shared/analyzer/github.js.map +1 -0
- package/shared/analyzer/graph.d.ts +41 -0
- package/shared/analyzer/graph.js +393 -400
- package/shared/analyzer/graph.js.map +1 -0
- package/shared/analyzer/health.d.ts +33 -0
- package/shared/analyzer/health.js +197 -193
- package/shared/analyzer/health.js.map +1 -0
- package/shared/analyzer/history.d.ts +29 -0
- package/shared/analyzer/history.js +110 -111
- package/shared/analyzer/history.js.map +1 -0
- package/shared/analyzer/jsonConfig.d.ts +2 -0
- package/shared/analyzer/jsonConfig.js +61 -0
- package/shared/analyzer/jsonConfig.js.map +1 -0
- package/shared/analyzer/languages/csharp.d.ts +26 -0
- package/shared/analyzer/languages/csharp.js +83 -88
- package/shared/analyzer/languages/csharp.js.map +1 -0
- package/shared/analyzer/languages/generic.d.ts +23 -0
- package/shared/analyzer/languages/generic.js +94 -105
- package/shared/analyzer/languages/generic.js.map +1 -0
- package/shared/analyzer/languages/go.d.ts +24 -0
- package/shared/analyzer/languages/go.js +45 -54
- package/shared/analyzer/languages/go.js.map +1 -0
- package/shared/analyzer/languages/index.d.ts +6 -0
- package/shared/analyzer/languages/index.js +19 -20
- package/shared/analyzer/languages/index.js.map +1 -0
- package/shared/analyzer/languages/java.d.ts +20 -0
- package/shared/analyzer/languages/java.js +73 -78
- package/shared/analyzer/languages/java.js.map +1 -0
- package/shared/analyzer/languages/javascript.d.ts +12 -0
- package/shared/analyzer/languages/javascript.js +258 -209
- package/shared/analyzer/languages/javascript.js.map +1 -0
- package/shared/analyzer/languages/python.d.ts +23 -0
- package/shared/analyzer/languages/python.js +92 -100
- package/shared/analyzer/languages/python.js.map +1 -0
- package/shared/analyzer/languages/rust.d.ts +17 -0
- package/shared/analyzer/languages/rust.js +96 -98
- package/shared/analyzer/languages/rust.js.map +1 -0
- package/shared/analyzer/languages/typescript.d.ts +11 -0
- package/shared/analyzer/languages/typescript.js +117 -116
- package/shared/analyzer/languages/typescript.js.map +1 -0
- package/shared/analyzer/licenses.d.ts +18 -0
- package/shared/analyzer/licenses.js +130 -133
- package/shared/analyzer/licenses.js.map +1 -0
- package/shared/analyzer/metrics.d.ts +20 -0
- package/shared/analyzer/metrics.js +112 -104
- package/shared/analyzer/metrics.js.map +1 -0
- package/shared/analyzer/pathUtil.d.ts +10 -0
- package/shared/analyzer/pathUtil.js +29 -35
- package/shared/analyzer/pathUtil.js.map +1 -0
- package/shared/analyzer/patterns.d.ts +11 -0
- package/shared/analyzer/patterns.js +231 -253
- package/shared/analyzer/patterns.js.map +1 -0
- package/shared/analyzer/scan.d.ts +62 -0
- package/shared/analyzer/scan.js +451 -442
- package/shared/analyzer/scan.js.map +1 -0
- package/shared/analyzer/scanControl.d.ts +11 -0
- package/shared/analyzer/scanControl.js +62 -0
- package/shared/analyzer/scanControl.js.map +1 -0
- package/shared/analyzer/security.d.ts +18 -0
- package/shared/analyzer/security.js +159 -159
- package/shared/analyzer/security.js.map +1 -0
- package/shared/analyzer/services.d.ts +5 -0
- package/shared/analyzer/services.js +141 -138
- package/shared/analyzer/services.js.map +1 -0
- package/shared/analyzer/stack.d.ts +6 -0
- package/shared/analyzer/stack.js +134 -141
- package/shared/analyzer/stack.js.map +1 -0
- package/shared/analyzer/tour.d.ts +2 -0
- package/shared/analyzer/tour.js +45 -53
- package/shared/analyzer/tour.js.map +1 -0
- package/shared/analyzer/util.d.ts +8 -0
- package/shared/analyzer/util.js +130 -76
- package/shared/analyzer/util.js.map +1 -0
- package/shared/analyzer/workflows.d.ts +8 -0
- package/shared/analyzer/workflows.js +139 -134
- package/shared/analyzer/workflows.js.map +1 -0
- package/shared/contracts.d.ts +250 -0
- package/shared/contracts.js +2 -0
- package/shared/contracts.js.map +1 -0
- package/shared/diagram/aiFacts.d.ts +35 -0
- package/shared/diagram/aiFacts.js +102 -105
- package/shared/diagram/aiFacts.js.map +1 -0
- package/shared/diagram/aiMermaid.d.ts +5 -0
- package/shared/diagram/aiMermaid.js +46 -45
- package/shared/diagram/aiMermaid.js.map +1 -0
- package/shared/diagram/atlas.d.ts +16 -0
- package/shared/diagram/atlas.js +51 -60
- package/shared/diagram/atlas.js.map +1 -0
- package/shared/diagram/mermaid.d.ts +43 -0
- package/shared/diagram/mermaid.js +348 -370
- package/shared/diagram/mermaid.js.map +1 -0
- package/shared/review/contracts.d.ts +95 -0
- package/shared/review/contracts.js +2 -0
- package/shared/review/contracts.js.map +1 -0
- package/shared/review/review.d.ts +10 -0
- package/shared/review/review.js +184 -0
- package/shared/review/review.js.map +1 -0
- package/shared/search/query.d.ts +32 -0
- package/shared/search/query.js +395 -388
- package/shared/search/query.js.map +1 -0
|
@@ -20,234 +20,221 @@
|
|
|
20
20
|
//
|
|
21
21
|
// The filters (severity, engine, text) live on `state.analysis` so they survive
|
|
22
22
|
// switching tabs within a repo, and reset with the repo.
|
|
23
|
-
|
|
24
23
|
import { escapeHtml } from './html.js';
|
|
25
24
|
import { mdInline } from './markdown.js';
|
|
26
25
|
import { streamExplain } from './api.js';
|
|
27
26
|
import * as llm from './llm.js';
|
|
28
27
|
import { state } from './state.js';
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
SEV_ORDER, BUILTIN_TOOL,
|
|
32
|
-
} from './analysisReport.js';
|
|
33
|
-
import {
|
|
34
|
-
ensureToolsStatus, installEngine, runDeepAnalysis, runOutcomeMessage, subscribeAnalysis,
|
|
35
|
-
} from './analysisPanel.js';
|
|
36
|
-
|
|
28
|
+
import { filterFindings, findingsFromSecurity, tabulate, engineRows, engineSummary, SEV_ORDER, BUILTIN_TOOL, } from './analysisReport.js';
|
|
29
|
+
import { ensureToolsStatus, installEngine, runDeepAnalysis, runOutcomeMessage, subscribeAnalysis, } from './analysisPanel.js';
|
|
37
30
|
let host = null;
|
|
38
31
|
let hooks = {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
onToast: (..._args) => { },
|
|
33
|
+
onOpenFile: (..._args) => { },
|
|
34
|
+
onOpenSettings: (..._args) => { },
|
|
35
|
+
repoOverview: () => '',
|
|
43
36
|
};
|
|
44
|
-
|
|
45
37
|
export function initDeepAnalysis(options) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
38
|
+
host = options.host;
|
|
39
|
+
hooks = { ...hooks, ...options };
|
|
40
|
+
host.addEventListener('click', (event) => {
|
|
41
|
+
const kind = event.target.closest('[data-run-kind]');
|
|
42
|
+
if (kind)
|
|
43
|
+
return void doRun({ kinds: [kind.dataset.runKind] });
|
|
44
|
+
if (event.target.closest('[data-run-all]'))
|
|
45
|
+
return void doRun({});
|
|
46
|
+
const engineRun = event.target.closest('[data-engine-run]');
|
|
47
|
+
if (engineRun)
|
|
48
|
+
return void doRun({ tools: [engineRun.dataset.engineRun] });
|
|
49
|
+
const engineInstall = event.target.closest('[data-engine-install]');
|
|
50
|
+
if (engineInstall) {
|
|
51
|
+
const id = engineInstall.dataset.engineInstall;
|
|
52
|
+
return void installEngine(id).then((done) => {
|
|
53
|
+
if (done && done.ok)
|
|
54
|
+
hooks.onToast(`${id} installed — press Run to use it.`);
|
|
55
|
+
else if (done && done.error)
|
|
56
|
+
hooks.onToast(done.error);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
if (event.target.closest('[data-sev]')) {
|
|
60
|
+
state.analysis.severity = event.target.closest('[data-sev]').dataset.sev;
|
|
61
|
+
return renderDeepAnalysis(host, state);
|
|
62
|
+
}
|
|
63
|
+
if (event.target.closest('[data-tool-filter]')) {
|
|
64
|
+
state.analysis.tool = event.target.closest('[data-tool-filter]').dataset.toolFilter;
|
|
65
|
+
return renderDeepAnalysis(host, state);
|
|
66
|
+
}
|
|
67
|
+
if (event.target.closest('[data-open-settings]')) {
|
|
68
|
+
hooks.onOpenSettings();
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
if (event.target.closest('[data-ai-explain]'))
|
|
72
|
+
return void explainWithAI('');
|
|
73
|
+
const fileLink = event.target.closest('[data-goto]');
|
|
74
|
+
if (fileLink) {
|
|
75
|
+
hooks.onOpenFile(fileLink.dataset.goto, Number(fileLink.dataset.gotoLine) || 0);
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
});
|
|
79
|
+
host.addEventListener('input', (event) => {
|
|
80
|
+
if (event.target.matches('[data-finding-search]')) {
|
|
81
|
+
const caret = event.target.selectionStart;
|
|
82
|
+
state.analysis.q = event.target.value;
|
|
83
|
+
renderDeepAnalysis(host, state);
|
|
84
|
+
// Re-focus and restore the caret: a full repaint replaces the input, and
|
|
85
|
+
// typing into a box that loses focus on every keystroke is unusable.
|
|
86
|
+
const next = host.querySelector('[data-finding-search]');
|
|
87
|
+
if (next) {
|
|
88
|
+
next.focus();
|
|
89
|
+
next.setSelectionRange(caret, caret);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
if (event.target.matches('[data-ai-question]')) {
|
|
94
|
+
state.analysis.ai.question = event.target.value;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
host.addEventListener('keydown', (event) => {
|
|
98
|
+
if (event.key === 'Enter' && event.target.matches('[data-ai-question]')) {
|
|
99
|
+
event.preventDefault();
|
|
100
|
+
explainWithAI(event.target.value);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
// The Configure forms. `change` — not `input` — so a repaint never fights a
|
|
104
|
+
// half-typed number; the store keeps the values and the next run picks them
|
|
105
|
+
// up. No repaint on change either: the control itself already shows the new
|
|
106
|
+
// value, and redrawing would close the <details> the person just opened.
|
|
107
|
+
host.addEventListener('change', (event) => {
|
|
108
|
+
const control = event.target.closest('[data-opt]');
|
|
109
|
+
if (!control)
|
|
110
|
+
return;
|
|
111
|
+
const { engine, key } = control.dataset;
|
|
112
|
+
const slot = state.tools.options[engine] || (state.tools.options[engine] = {});
|
|
113
|
+
if (control.type === 'checkbox') {
|
|
114
|
+
if (control.dataset.optValue) {
|
|
115
|
+
// one value of a multi-select
|
|
116
|
+
const list = Array.isArray(slot[key]) ? [...slot[key]] : [];
|
|
117
|
+
const at = list.indexOf(control.dataset.optValue);
|
|
118
|
+
if (control.checked && at === -1)
|
|
119
|
+
list.push(control.dataset.optValue);
|
|
120
|
+
if (!control.checked && at !== -1)
|
|
121
|
+
list.splice(at, 1);
|
|
122
|
+
slot[key] = list;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
slot[key] = control.checked;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else if (control.type === 'number') {
|
|
129
|
+
slot[key] = control.value === '' ? undefined : Number(control.value);
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
slot[key] = control.value;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
// A run started from the inspector panel repaints this view too.
|
|
136
|
+
subscribeAnalysis(() => {
|
|
137
|
+
if (state.view === 'analysis')
|
|
138
|
+
renderDeepAnalysis(host, state);
|
|
139
|
+
});
|
|
145
140
|
}
|
|
146
|
-
|
|
147
141
|
async function doRun(options) {
|
|
148
|
-
|
|
149
|
-
|
|
142
|
+
const report = await runDeepAnalysis(options);
|
|
143
|
+
hooks.onToast(runOutcomeMessage(report));
|
|
150
144
|
}
|
|
151
|
-
|
|
152
145
|
// ---- the AI pass ------------------------------------------------------------
|
|
153
|
-
|
|
154
146
|
// Explains the report, or answers `question` about it. Streams into
|
|
155
147
|
// `state.analysis.ai.text` and repaints the note in place — a full page repaint
|
|
156
148
|
// mid-stream would throw away every character already received.
|
|
157
149
|
async function explainWithAI(question) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const rows = findingsFromSecurity(state.security);
|
|
168
|
-
const counts = tabulate(rows);
|
|
169
|
-
const engines = engineRows(state.tools.status, state.tools.report);
|
|
170
|
-
const messages = llm.analysisMessages({
|
|
171
|
-
repoName: state.scan.name,
|
|
172
|
-
grade: state.security?.grade,
|
|
173
|
-
score: state.security?.score,
|
|
174
|
-
counts,
|
|
175
|
-
engines,
|
|
176
|
-
findings: rows,
|
|
177
|
-
question: (question || '').trim(),
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
const settings = llm.getSettings();
|
|
181
|
-
ai.running = true;
|
|
182
|
-
ai.text = '';
|
|
183
|
-
ai.error = '';
|
|
184
|
-
paintAI();
|
|
185
|
-
|
|
186
|
-
try {
|
|
187
|
-
const providerOptions = llm.isAzureHost(settings.baseUrl) ? {} : { reasoning: { exclude: true } };
|
|
188
|
-
for await (const delta of streamExplain({ ...settings, messages, maxTokens: 900, providerOptions })) {
|
|
189
|
-
ai.text += delta;
|
|
190
|
-
paintAI();
|
|
150
|
+
const ai = state.analysis.ai;
|
|
151
|
+
if (ai.running)
|
|
152
|
+
return;
|
|
153
|
+
if (!llm.isConfigured()) {
|
|
154
|
+
hooks.onOpenSettings();
|
|
155
|
+
hooks.onToast('Add an endpoint and model first — the report is still readable without one.');
|
|
156
|
+
return;
|
|
191
157
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
158
|
+
const rows = findingsFromSecurity(state.security);
|
|
159
|
+
const counts = tabulate(rows);
|
|
160
|
+
const engines = engineRows(state.tools.status, state.tools.report);
|
|
161
|
+
const messages = llm.analysisMessages({
|
|
162
|
+
repoName: state.scan.name,
|
|
163
|
+
grade: state.security?.grade,
|
|
164
|
+
score: state.security?.score,
|
|
165
|
+
counts,
|
|
166
|
+
engines,
|
|
167
|
+
findings: rows,
|
|
168
|
+
question: (question || '').trim(),
|
|
169
|
+
});
|
|
170
|
+
const settings = llm.getSettings();
|
|
171
|
+
ai.running = true;
|
|
172
|
+
ai.text = '';
|
|
173
|
+
ai.error = '';
|
|
196
174
|
paintAI();
|
|
197
|
-
|
|
175
|
+
try {
|
|
176
|
+
const providerOptions = llm.isAzureHost(settings.baseUrl) ? {} : { reasoning: { exclude: true } };
|
|
177
|
+
for await (const delta of streamExplain({ ...settings, messages, maxTokens: 900, providerOptions })) {
|
|
178
|
+
ai.text += delta;
|
|
179
|
+
paintAI();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
ai.error = err.message;
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
ai.running = false;
|
|
187
|
+
paintAI();
|
|
188
|
+
}
|
|
198
189
|
}
|
|
199
|
-
|
|
200
190
|
// Repaint just the AI note, so streaming never fights the rest of the page.
|
|
201
191
|
function paintAI() {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
192
|
+
if (!host)
|
|
193
|
+
return;
|
|
194
|
+
const note = host.querySelector('[data-ai-note]');
|
|
195
|
+
if (!note)
|
|
196
|
+
return;
|
|
197
|
+
const ai = state.analysis.ai;
|
|
198
|
+
note.innerHTML = renderAINote(ai);
|
|
207
199
|
}
|
|
208
|
-
|
|
209
200
|
// ---- painting ---------------------------------------------------------------
|
|
210
|
-
|
|
211
201
|
export function renderDeepAnalysis(container, appState = state) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
202
|
+
if (!container)
|
|
203
|
+
return;
|
|
204
|
+
host = container;
|
|
205
|
+
const { analysis } = appState;
|
|
206
|
+
// A browser-picked folder has no server-side root, so there is nothing for an
|
|
207
|
+
// engine to read. Say that once, plainly, rather than showing an empty table
|
|
208
|
+
// that looks like a clean bill of health.
|
|
209
|
+
if (!appState.scanId) {
|
|
210
|
+
container.innerHTML = `<div class="analysis-layout">
|
|
221
211
|
<header class="analysis-head">
|
|
222
212
|
<h1 class="analysis-title">Deep analysis</h1>
|
|
223
213
|
<p class="analysis-sub">External engines — Semgrep, Gitleaks, Knip, Vulture, Depcheck.</p>
|
|
224
214
|
</header>
|
|
225
215
|
<div class="analysis-empty">This repo was picked in the browser, so its files never reached the server. An external engine needs a directory on the server to read, so deep analysis is available for folders scanned by path and for git clones. The built-in scan — every finding on the <b>Security</b> tab — still applies.</div>
|
|
226
216
|
</div>`;
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
container.innerHTML = `<div class="analysis-layout">
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const engines = engineRows(appState.tools.status, appState.tools.report);
|
|
220
|
+
const all = findingsFromSecurity(appState.security);
|
|
221
|
+
const counts = tabulate(all);
|
|
222
|
+
const visible = filterFindings(all, analysis);
|
|
223
|
+
const summary = engineSummary(appState.tools.report, engines);
|
|
224
|
+
const running = appState.tools.running;
|
|
225
|
+
container.innerHTML = `<div class="analysis-layout">
|
|
238
226
|
${renderHead(counts, running)}
|
|
239
227
|
${renderEngineBlock(engines, summary, running, appState.tools)}
|
|
240
228
|
${renderAIBlock()}
|
|
241
229
|
${renderFindingsBlock(visible, counts, analysis)}
|
|
242
230
|
</div>`;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
231
|
+
// The engines panel may still be loading; ask once and let the store notify.
|
|
232
|
+
if (!appState.tools.status && !appState.tools.loading)
|
|
233
|
+
void ensureToolsStatus();
|
|
246
234
|
}
|
|
247
|
-
|
|
248
235
|
function renderHead(counts, running) {
|
|
249
|
-
|
|
250
|
-
|
|
236
|
+
const chip = (label, value, cls = '') => `<span class="analysis-chip ${cls}"><b>${value}</b> ${label}</span>`;
|
|
237
|
+
return `<header class="analysis-head">
|
|
251
238
|
<div class="analysis-head-text">
|
|
252
239
|
<h1 class="analysis-title">Deep analysis</h1>
|
|
253
240
|
<p class="analysis-sub">Every engine this machine has, plus the built-in scanner — merged into one list. Click any file to open it at the line.</p>
|
|
@@ -266,42 +253,42 @@ function renderHead(counts, running) {
|
|
|
266
253
|
${chip('from built-in', counts.builtin)}
|
|
267
254
|
</div>`;
|
|
268
255
|
}
|
|
269
|
-
|
|
270
256
|
function renderEngineBlock(engines, summary, running, tools) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
return `<section class="analysis-block">
|
|
257
|
+
const rows = engines.length ? engines.map((e) => renderEngineRow(e, running)).join('') : '';
|
|
258
|
+
const empty = tools.loading
|
|
259
|
+
? '<div class="analysis-empty">Checking which engines are installed…</div>'
|
|
260
|
+
: (engines.length ? '' : '<div class="analysis-empty">No engine table — the server did not answer.</div>');
|
|
261
|
+
return `<section class="analysis-block">
|
|
277
262
|
<h2 class="analysis-h">Engines <span class="analysis-h-sub">what this machine can run</span></h2>
|
|
278
263
|
<div class="analysis-engines">${rows}${empty}</div>
|
|
279
264
|
<div class="analysis-verdict is-${escapeHtml(summary.tone)}">${escapeHtml(summary.text)}</div>
|
|
280
265
|
</section>`;
|
|
281
266
|
}
|
|
282
|
-
|
|
283
267
|
function renderEngineRow(engine, running) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
268
|
+
const installing = state.tools.install[engine.id];
|
|
269
|
+
let badge;
|
|
270
|
+
if (installing && installing.running)
|
|
271
|
+
badge = '<span class="tools-badge is-running">installing…</span>';
|
|
272
|
+
else if (!engine.available)
|
|
273
|
+
badge = '<span class="tools-badge is-missing">not installed</span>';
|
|
274
|
+
else if (running)
|
|
275
|
+
badge = '<span class="tools-badge is-running">running…</span>';
|
|
276
|
+
else if (engine.ran)
|
|
277
|
+
badge = `<span class="tools-badge is-ran">${engine.findings} · ${engine.ms}ms</span>`;
|
|
278
|
+
else if (engine.failed)
|
|
279
|
+
badge = '<span class="tools-badge is-failed">failed</span>';
|
|
280
|
+
else
|
|
281
|
+
badge = `<span class="tools-badge is-ready">ready${engine.how ? ' · ' + escapeHtml(engine.how) : ''}</span>`;
|
|
282
|
+
const note = !engine.available && engine.reason
|
|
283
|
+
? `<span class="tools-reason">${escapeHtml(engine.reason)}</span>`
|
|
284
|
+
: (engine.failure ? `<span class="tools-reason">${escapeHtml(engine.failure)}</span>` : '');
|
|
285
|
+
const runBtn = engine.available
|
|
286
|
+
? `<button class="btn btn-ghost btn-sm" data-engine-run="${escapeHtml(engine.id)}" ${running ? 'disabled' : ''}>Run</button>`
|
|
287
|
+
: '';
|
|
288
|
+
const installBtn = !engine.available && engine.installable
|
|
289
|
+
? `<button class="btn btn-ink btn-sm" data-engine-install="${escapeHtml(engine.id)}" ${installing && installing.running ? 'disabled' : ''}>${installing && installing.running ? 'Installing…' : 'Install'}</button>`
|
|
290
|
+
: '';
|
|
291
|
+
return `<div class="analysis-engine${engine.available ? '' : ' is-missing'}">
|
|
305
292
|
<div class="analysis-engine-top">
|
|
306
293
|
<span class="tools-name">${escapeHtml(engine.label)}</span>
|
|
307
294
|
${badge}
|
|
@@ -315,33 +302,33 @@ function renderEngineRow(engine, running) {
|
|
|
315
302
|
${renderInstallConsole(installing)}
|
|
316
303
|
</div>`;
|
|
317
304
|
}
|
|
318
|
-
|
|
319
305
|
// The Configure panel: a <details> with one control per schema entry, so the
|
|
320
306
|
// useful surface of each engine — semgrep's rule sets, gitleaks' history
|
|
321
307
|
// scan, vulture's confidence floor — is a form, not a command line. Values
|
|
322
308
|
// live in `state.tools.options` and ride along with the next run; the server
|
|
323
309
|
// validates them against the same schema before they touch an argv.
|
|
324
310
|
function renderEngineOptions(engine) {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
311
|
+
if (!engine.options.length)
|
|
312
|
+
return '';
|
|
313
|
+
const values = state.tools.options[engine.id] || {};
|
|
314
|
+
const field = (opt) => {
|
|
315
|
+
const current = values[opt.key] !== undefined ? values[opt.key] : engine.defaults[opt.key];
|
|
316
|
+
let control;
|
|
317
|
+
if (opt.type === 'boolean') {
|
|
318
|
+
control = `<label class="analysis-opt-check">
|
|
333
319
|
<input type="checkbox" data-opt data-engine="${escapeHtml(engine.id)}" data-key="${escapeHtml(opt.key)}" ${current ? 'checked' : ''}>
|
|
334
320
|
<span>${escapeHtml(opt.label)}</span>
|
|
335
321
|
</label>`;
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
322
|
+
}
|
|
323
|
+
else if (opt.type === 'enum') {
|
|
324
|
+
const options = opt.values.map((v) => `<option value="${escapeHtml(v)}" ${v === current ? 'selected' : ''}>${escapeHtml(v)}</option>`).join('');
|
|
325
|
+
control = `<label class="analysis-opt-field"><span>${escapeHtml(opt.label)}</span>
|
|
340
326
|
<select class="text-input" data-opt data-engine="${escapeHtml(engine.id)}" data-key="${escapeHtml(opt.key)}">${options}</select>
|
|
341
327
|
</label>`;
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
328
|
+
}
|
|
329
|
+
else if (opt.type === 'multi') {
|
|
330
|
+
const chosen = Array.isArray(current) ? current : [];
|
|
331
|
+
control = `<div class="analysis-opt-field"><span>${escapeHtml(opt.label)}</span>
|
|
345
332
|
<div class="analysis-opt-multi">${opt.values.map((v) => `
|
|
346
333
|
<label class="analysis-opt-check">
|
|
347
334
|
<input type="checkbox" data-opt data-engine="${escapeHtml(engine.id)}" data-key="${escapeHtml(opt.key)}"
|
|
@@ -350,45 +337,43 @@ function renderEngineOptions(engine) {
|
|
|
350
337
|
</label>`).join('')}
|
|
351
338
|
</div>
|
|
352
339
|
</div>`;
|
|
353
|
-
|
|
354
|
-
|
|
340
|
+
}
|
|
341
|
+
else { // number
|
|
342
|
+
control = `<label class="analysis-opt-field"><span>${escapeHtml(opt.label)}</span>
|
|
355
343
|
<input type="number" class="text-input" data-opt data-engine="${escapeHtml(engine.id)}" data-key="${escapeHtml(opt.key)}"
|
|
356
344
|
min="${opt.min}" max="${opt.max}" value="${escapeHtml(String(current ?? opt.default))}">
|
|
357
345
|
</label>`;
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
return `<details class="analysis-config">
|
|
346
|
+
}
|
|
347
|
+
const hint = opt.hint ? `<span class="analysis-opt-hint">${escapeHtml(opt.hint)}</span>` : '';
|
|
348
|
+
return `<div class="analysis-opt">${control}${hint}</div>`;
|
|
349
|
+
};
|
|
350
|
+
return `<details class="analysis-config">
|
|
364
351
|
<summary>Configure</summary>
|
|
365
352
|
<div class="analysis-config-body">${engine.options.map(field).join('')}</div>
|
|
366
353
|
</details>`;
|
|
367
354
|
}
|
|
368
|
-
|
|
369
355
|
// The install log, live while an install runs and kept afterwards so a failed
|
|
370
356
|
// install leaves its reason on screen instead of in a toast that faded.
|
|
371
357
|
function renderInstallConsole(installing) {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
358
|
+
if (!installing || (!installing.log.length && !installing.running && !installing.error))
|
|
359
|
+
return '';
|
|
360
|
+
const verdict = installing.running
|
|
361
|
+
? ''
|
|
362
|
+
: installing.ok
|
|
363
|
+
? '<div class="analysis-console-verdict is-ok">Installed — the engine is ready.</div>'
|
|
364
|
+
: `<div class="analysis-console-verdict is-err">${escapeHtml(installing.error || 'The install failed.')}</div>`;
|
|
365
|
+
return `<div class="analysis-console-wrap">
|
|
379
366
|
<pre class="analysis-console">${escapeHtml(installing.log.join('\n'))}${installing.running ? ' ▍' : ''}</pre>
|
|
380
367
|
${verdict}
|
|
381
368
|
</div>`;
|
|
382
369
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
370
|
function renderAIBlock() {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
371
|
+
const configured = llm.isConfigured();
|
|
372
|
+
const ask = escapeHtml(state.analysis.ai.question || '');
|
|
373
|
+
const settingsBtn = configured
|
|
374
|
+
? ''
|
|
375
|
+
: '<button class="btn btn-ghost btn-sm" data-open-settings>API key…</button>';
|
|
376
|
+
return `<section class="analysis-block">
|
|
392
377
|
<h2 class="analysis-h">What this means <span class="analysis-h-sub">ask the AI</span></h2>
|
|
393
378
|
<div class="analysis-ai">
|
|
394
379
|
<div class="analysis-ai-bar">
|
|
@@ -404,50 +389,47 @@ function renderAIBlock() {
|
|
|
404
389
|
</div>
|
|
405
390
|
</section>`;
|
|
406
391
|
}
|
|
407
|
-
|
|
408
392
|
// The note is plain text from the model. It goes through `mdInline`, the same
|
|
409
393
|
// boundary helper the inspector uses: escape first, then bold and inline code.
|
|
410
394
|
// The prompt asks for prose, but models reach for `**bold**` and backticks
|
|
411
395
|
// anyway, and half-rendered asterisks look like a bug.
|
|
412
396
|
export function renderAINote(ai) {
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
.
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
397
|
+
if (ai.running && !ai.text) {
|
|
398
|
+
return '<span class="analysis-ai-waiting"><span class="search-spinner"></span> Reading the report…</span>';
|
|
399
|
+
}
|
|
400
|
+
if (ai.error)
|
|
401
|
+
return `<span class="analysis-ai-error">${escapeHtml(ai.error)}</span>`;
|
|
402
|
+
if (!ai.text) {
|
|
403
|
+
return '<span class="analysis-ai-idle">Press <b>Explain this analysis</b> for a prioritised read of the findings above, or ask a question about any of them.</span>';
|
|
404
|
+
}
|
|
405
|
+
const html = ai.text
|
|
406
|
+
.split(/\n{2,}/)
|
|
407
|
+
.map((para) => `<p>${mdInline(para).replace(/\n/g, '<br>')}</p>`)
|
|
408
|
+
.join('');
|
|
409
|
+
const cursor = ai.running ? '<span class="analysis-ai-cursor">▍</span>' : '';
|
|
410
|
+
return html + cursor;
|
|
426
411
|
}
|
|
427
|
-
|
|
428
412
|
function renderFindingsBlock(visible, counts, analysis) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
return `<section class="analysis-block">
|
|
413
|
+
const sevChips = ['all', ...SEV_ORDER].map((sev) => {
|
|
414
|
+
const n = sev === 'all' ? counts.total : (counts.bySeverity[sev] || 0);
|
|
415
|
+
if (sev !== 'all' && !n)
|
|
416
|
+
return '';
|
|
417
|
+
const active = analysis.severity === sev ? ' is-active' : '';
|
|
418
|
+
return `<button class="btn btn-ghost btn-sm${active}" data-sev="${sev}">${sev} (${n})</button>`;
|
|
419
|
+
}).join('');
|
|
420
|
+
const tools = Object.keys(counts.byTool).sort((a, b) => counts.byTool[b] - counts.byTool[a]);
|
|
421
|
+
const toolChips = tools.length > 1
|
|
422
|
+
? ['all', ...tools].map((tool) => {
|
|
423
|
+
const n = tool === 'all' ? counts.total : counts.byTool[tool];
|
|
424
|
+
const label = tool === BUILTIN_TOOL ? 'built-in scanner' : tool;
|
|
425
|
+
const active = analysis.tool === tool ? ' is-active' : '';
|
|
426
|
+
return `<button class="btn btn-ghost btn-sm${active}" data-tool-filter="${escapeHtml(tool)}">${escapeHtml(label)} (${n})</button>`;
|
|
427
|
+
}).join('')
|
|
428
|
+
: '';
|
|
429
|
+
const body = visible.length
|
|
430
|
+
? visible.map(renderFindingRow).join('')
|
|
431
|
+
: `<tr><td colspan="5" class="analysis-no-rows">Nothing matches those filters.</td></tr>`;
|
|
432
|
+
return `<section class="analysis-block">
|
|
451
433
|
<h2 class="analysis-h">Findings <span class="analysis-h-sub">${visible.length} of ${counts.total} shown</span></h2>
|
|
452
434
|
<div class="analysis-filterbar">
|
|
453
435
|
<div class="analysis-filter-group">${sevChips}</div>
|
|
@@ -469,11 +451,10 @@ function renderFindingsBlock(visible, counts, analysis) {
|
|
|
469
451
|
</div>
|
|
470
452
|
</section>`;
|
|
471
453
|
}
|
|
472
|
-
|
|
473
454
|
// One finding. The file cell is the point of the whole view: it carries the
|
|
474
455
|
// path, the line, and the click that opens the Code tab there.
|
|
475
456
|
function renderFindingRow(row) {
|
|
476
|
-
|
|
457
|
+
return `<tr class="analysis-row is-${escapeHtml(row.severity)}">
|
|
477
458
|
<td class="col-sev"><span class="sev-pill is-${escapeHtml(row.severity)}">${escapeHtml(row.severity)}</span></td>
|
|
478
459
|
<td class="col-file">
|
|
479
460
|
<button class="analysis-file" data-goto="${escapeHtml(row.path)}" data-goto-line="${row.line}"
|
|
@@ -488,9 +469,8 @@ function renderFindingRow(row) {
|
|
|
488
469
|
<td class="analysis-msg">${escapeHtml(row.message)}</td>
|
|
489
470
|
</tr>`;
|
|
490
471
|
}
|
|
491
|
-
|
|
492
472
|
function dirOf(path) {
|
|
493
|
-
|
|
494
|
-
|
|
473
|
+
const at = String(path || '').lastIndexOf('/');
|
|
474
|
+
return at === -1 ? '' : path.slice(0, at);
|
|
495
475
|
}
|
|
496
|
-
|
|
476
|
+
//# sourceMappingURL=deepAnalysisView.js.map
|