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
package/public/js/api.js
CHANGED
|
@@ -1,228 +1,237 @@
|
|
|
1
1
|
// Server round-trips. Thin and honest: JSON in, JSON (or an SSE stream) out,
|
|
2
2
|
// server error messages surfaced untouched.
|
|
3
|
-
|
|
4
3
|
// Browser access is an HttpOnly session cookie set by the themed self-hosted
|
|
5
4
|
// login page. Same-origin fetches include it automatically, and JavaScript never
|
|
6
5
|
// reads or stores the access key. API clients can still use `Authorization:
|
|
7
6
|
// Bearer …`; local mode needs no credential at all.
|
|
8
|
-
|
|
9
7
|
// 0.3.0 briefly stored a raw self-hosted key here. Remove that legacy value on
|
|
10
8
|
// first load so upgrading also removes the old secret rather than merely ignoring it.
|
|
11
|
-
try {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
34
|
-
|
|
9
|
+
try {
|
|
10
|
+
localStorage.removeItem('onboarder.accessKey');
|
|
11
|
+
}
|
|
12
|
+
catch { /* storage may be unavailable */ }
|
|
13
|
+
async function postJSON(url, body, options = {}) {
|
|
14
|
+
const res = await fetch(url, {
|
|
15
|
+
method: 'POST',
|
|
16
|
+
signal: options.signal,
|
|
17
|
+
headers: { 'content-type': 'application/json' },
|
|
18
|
+
body: JSON.stringify(body),
|
|
19
|
+
});
|
|
20
|
+
let data = null;
|
|
21
|
+
try {
|
|
22
|
+
data = await res.json();
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
/* error path handled below with a generic message */
|
|
26
|
+
}
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
throw new Error(data?.error || `The server said ${res.status}.`);
|
|
29
|
+
}
|
|
30
|
+
return data;
|
|
31
|
+
}
|
|
32
|
+
export function scanOnServer(payload, options = {}) {
|
|
33
|
+
return postJSON('/api/scan', payload, options);
|
|
34
|
+
}
|
|
35
35
|
export async function cleanupClone(cloneId) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
try {
|
|
37
|
+
await fetch('/api/scan/' + encodeURIComponent(cloneId), { method: 'DELETE' });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
/* best-effort: the temp dir expires on its own eventually */
|
|
41
|
+
}
|
|
41
42
|
}
|
|
42
|
-
|
|
43
43
|
export async function fetchFileText(scanId, path) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const res = await fetch('/api/file?scan=' + encodeURIComponent(scanId) + '&path=' + encodeURIComponent(path));
|
|
45
|
+
if (!res.ok)
|
|
46
|
+
throw new Error('Could not read that file from the server.');
|
|
47
|
+
return res.text();
|
|
47
48
|
}
|
|
48
|
-
|
|
49
49
|
// Which deep analyzers this machine can run, and how. Server-side scans only —
|
|
50
50
|
// a browser-picked folder has no scan id and no server-visible root to point a
|
|
51
51
|
// tool at, and this returns that honestly instead of pretending.
|
|
52
52
|
export async function fetchToolsStatus() {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch('/api/tools');
|
|
55
|
+
if (!res.ok)
|
|
56
|
+
return null;
|
|
57
|
+
const data = await res.json();
|
|
58
|
+
return data && data.tools ? data.tools : null;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return null; // an unreachable server is just "no deep analysis here"
|
|
62
|
+
}
|
|
63
|
+
}
|
|
63
64
|
// Run the available analyzers against a live scan. `kinds`/`tools` narrow which
|
|
64
65
|
// engines run; `options` carries the per-engine GUI settings, validated against
|
|
65
66
|
// the registry schema on the server. The report normalizes every finding into
|
|
66
67
|
// the shape the security view already draws, plus a per-engine pass list so
|
|
67
68
|
// the UI can say which tool answered and which are missing.
|
|
68
69
|
export function runAnalysisTools(scanId, options = {}) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
70
|
+
return postJSON('/api/tools/run', {
|
|
71
|
+
scanId,
|
|
72
|
+
kinds: options.kinds || undefined,
|
|
73
|
+
tools: options.tools || undefined,
|
|
74
|
+
options: options.options || undefined,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
77
|
// Install a missing engine, streaming progress events. The server emits SSE
|
|
78
78
|
// frames shaped like the explain stream, minus the OpenAI envelope:
|
|
79
79
|
// { type: 'log', line } / { type: 'plan', label } / { type: 'done', ok, … }
|
|
80
80
|
// `onEvent` gets each one as it arrives; the promise resolves with the final
|
|
81
81
|
// `done` event (or throws if the request itself failed).
|
|
82
82
|
export async function streamToolInstall(tool, onEvent) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
try { detail = (await res.json()).error || ''; } catch { /* generic below */ }
|
|
92
|
-
throw new Error(detail || `The server said ${res.status}.`);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const reader = res.body.getReader();
|
|
96
|
-
const decoder = new TextDecoder();
|
|
97
|
-
let buffer = '';
|
|
98
|
-
let done = null;
|
|
99
|
-
while (true) {
|
|
100
|
-
const { done: ended, value } = await reader.read();
|
|
101
|
-
if (ended) break;
|
|
102
|
-
buffer += decoder.decode(value, { stream: true });
|
|
103
|
-
const frames = buffer.split('\n\n');
|
|
104
|
-
buffer = frames.pop();
|
|
105
|
-
for (const frame of frames) {
|
|
106
|
-
for (const line of frame.split('\n')) {
|
|
107
|
-
if (!line.startsWith('data:')) continue;
|
|
83
|
+
const emit = typeof onEvent === 'function' ? onEvent : (..._args) => { };
|
|
84
|
+
const res = await fetch('/api/tools/install', {
|
|
85
|
+
method: 'POST',
|
|
86
|
+
headers: { 'content-type': 'application/json' },
|
|
87
|
+
body: JSON.stringify({ tool }),
|
|
88
|
+
});
|
|
89
|
+
if (!res.ok || !res.body) {
|
|
90
|
+
let detail = '';
|
|
108
91
|
try {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
92
|
+
detail = (await res.json()).error || '';
|
|
93
|
+
}
|
|
94
|
+
catch { /* generic below */ }
|
|
95
|
+
throw new Error(detail || `The server said ${res.status}.`);
|
|
114
96
|
}
|
|
115
|
-
|
|
116
|
-
|
|
97
|
+
const reader = res.body.getReader();
|
|
98
|
+
const decoder = new TextDecoder();
|
|
99
|
+
let buffer = '';
|
|
100
|
+
let done = null;
|
|
101
|
+
while (true) {
|
|
102
|
+
const { done: ended, value } = await reader.read();
|
|
103
|
+
if (ended)
|
|
104
|
+
break;
|
|
105
|
+
buffer += decoder.decode(value, { stream: true });
|
|
106
|
+
const frames = buffer.split('\n\n');
|
|
107
|
+
buffer = frames.pop();
|
|
108
|
+
for (const frame of frames) {
|
|
109
|
+
for (const line of frame.split('\n')) {
|
|
110
|
+
if (!line.startsWith('data:'))
|
|
111
|
+
continue;
|
|
112
|
+
try {
|
|
113
|
+
const event = JSON.parse(line.slice(5).trim());
|
|
114
|
+
emit(event);
|
|
115
|
+
if (event.type === 'done')
|
|
116
|
+
done = event;
|
|
117
|
+
}
|
|
118
|
+
catch { /* a partial frame — the next chunk completes it */ }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return done || { type: 'done', ok: false, error: 'The install stream ended without a verdict.' };
|
|
117
123
|
}
|
|
118
|
-
|
|
119
124
|
// The MCP button's three round-trips. The status one is a plain GET like
|
|
120
125
|
// `/api/tools`; start and stop are POSTs because each one changes a process on
|
|
121
126
|
// this machine, which is exactly the side effect `postJSON` is here for.
|
|
122
127
|
export async function fetchMcpStatus() {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
try {
|
|
129
|
+
const res = await fetch('/api/mcp');
|
|
130
|
+
if (!res.ok)
|
|
131
|
+
return null;
|
|
132
|
+
return await res.json();
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return null; // no server means no button state, not an error to shout about
|
|
136
|
+
}
|
|
137
|
+
}
|
|
132
138
|
export function startMcpServer() {
|
|
133
|
-
|
|
139
|
+
return postJSON('/api/mcp/start', {});
|
|
134
140
|
}
|
|
135
|
-
|
|
136
141
|
export function stopMcpServer() {
|
|
137
|
-
|
|
142
|
+
return postJSON('/api/mcp/stop', {});
|
|
138
143
|
}
|
|
139
|
-
|
|
140
144
|
// The command an agent harness is configured with. Kept separate from the status
|
|
141
145
|
// fetch because it never changes, so it is read once when the panel opens rather
|
|
142
146
|
// than on every poll.
|
|
143
147
|
export async function fetchMcpCommand() {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
try {
|
|
149
|
+
const res = await fetch('/api/mcp/command');
|
|
150
|
+
if (!res.ok)
|
|
151
|
+
return null;
|
|
152
|
+
return await res.json();
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
153
158
|
// Streams an OpenAI-compatible chat completion through the local proxy.
|
|
154
159
|
// Yields text deltas as they arrive; throws with the provider's message on
|
|
155
160
|
// a non-200 from upstream.
|
|
156
|
-
export async function* streamExplain({ baseUrl, apiKey, model, messages, maxTokens = 1200, providerOptions = {} }) {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
try {
|
|
166
|
-
const data = await res.json();
|
|
167
|
-
detail = data.detail || data.error || '';
|
|
168
|
-
} catch {
|
|
169
|
-
/* keep the generic line */
|
|
170
|
-
}
|
|
171
|
-
throw new Error(detail || `The provider said ${res.status}.`);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const reader = res.body.getReader();
|
|
175
|
-
const decoder = new TextDecoder();
|
|
176
|
-
let buffer = '';
|
|
177
|
-
while (true) {
|
|
178
|
-
const { done, value } = await reader.read();
|
|
179
|
-
if (done) break;
|
|
180
|
-
buffer += decoder.decode(value, { stream: true });
|
|
181
|
-
const frames = buffer.split('\n\n');
|
|
182
|
-
buffer = frames.pop();
|
|
183
|
-
for (const frame of frames) {
|
|
184
|
-
for (const line of frame.split('\n')) {
|
|
185
|
-
if (!line.startsWith('data:')) continue;
|
|
186
|
-
const payload = line.slice(5).trim();
|
|
187
|
-
if (payload === '[DONE]') return;
|
|
161
|
+
export async function* streamExplain({ baseUrl, apiKey, model, messages, maxTokens = 1200, providerOptions = {}, signal = undefined }) {
|
|
162
|
+
const res = await fetch('/api/explain', {
|
|
163
|
+
signal,
|
|
164
|
+
method: 'POST',
|
|
165
|
+
headers: { 'content-type': 'application/json' },
|
|
166
|
+
body: JSON.stringify({ baseUrl, apiKey, model, messages, stream: true, max_tokens: maxTokens, ...providerOptions }),
|
|
167
|
+
});
|
|
168
|
+
if (!res.ok) {
|
|
169
|
+
let detail = '';
|
|
188
170
|
try {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
171
|
+
const data = await res.json();
|
|
172
|
+
detail = data.detail || data.error || '';
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
/* keep the generic line */
|
|
176
|
+
}
|
|
177
|
+
throw new Error(detail || `The provider said ${res.status}.`);
|
|
178
|
+
}
|
|
179
|
+
const reader = res.body.getReader();
|
|
180
|
+
const decoder = new TextDecoder();
|
|
181
|
+
let buffer = '';
|
|
182
|
+
while (true) {
|
|
183
|
+
const { done, value } = await reader.read();
|
|
184
|
+
if (done)
|
|
185
|
+
break;
|
|
186
|
+
buffer += decoder.decode(value, { stream: true });
|
|
187
|
+
const frames = buffer.split('\n\n');
|
|
188
|
+
buffer = frames.pop();
|
|
189
|
+
for (const frame of frames) {
|
|
190
|
+
for (const line of frame.split('\n')) {
|
|
191
|
+
if (!line.startsWith('data:'))
|
|
192
|
+
continue;
|
|
193
|
+
const payload = line.slice(5).trim();
|
|
194
|
+
if (payload === '[DONE]')
|
|
195
|
+
return;
|
|
196
|
+
try {
|
|
197
|
+
const json = JSON.parse(payload);
|
|
198
|
+
const delta = json.choices?.[0]?.delta?.content;
|
|
199
|
+
if (delta)
|
|
200
|
+
yield delta;
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
/* a partial JSON frame — the next chunk completes it */
|
|
204
|
+
}
|
|
205
|
+
}
|
|
194
206
|
}
|
|
195
|
-
}
|
|
196
207
|
}
|
|
197
|
-
}
|
|
198
208
|
}
|
|
199
|
-
|
|
200
209
|
// The Server drawer's three round-trips. The read is a GET that comes back
|
|
201
210
|
// with the secret masked; writes go through PUT with only the changed keys;
|
|
202
211
|
// rotation is a POST because it mints a new key on the server — the one and
|
|
203
212
|
// only time a key ever crosses the wire in the clear.
|
|
204
213
|
export async function fetchServerSettings() {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
214
|
+
const res = await fetch('/api/settings');
|
|
215
|
+
const data = await res.json().catch(() => null);
|
|
216
|
+
if (!res.ok)
|
|
217
|
+
throw new Error(data?.error || `The server said ${res.status}.`);
|
|
218
|
+
return data;
|
|
209
219
|
}
|
|
210
|
-
|
|
211
220
|
export async function updateServerSettings(patch) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
const res = await fetch('/api/settings', {
|
|
222
|
+
method: 'PUT',
|
|
223
|
+
headers: { 'content-type': 'application/json' },
|
|
224
|
+
body: JSON.stringify(patch),
|
|
225
|
+
});
|
|
226
|
+
const data = await res.json().catch(() => null);
|
|
227
|
+
if (!res.ok)
|
|
228
|
+
throw new Error(data?.error || `The server said ${res.status}.`);
|
|
229
|
+
return data;
|
|
230
|
+
}
|
|
222
231
|
export function rotateServerAccessKey() {
|
|
223
|
-
|
|
232
|
+
return postJSON('/api/settings/access-key', {});
|
|
224
233
|
}
|
|
225
|
-
|
|
226
234
|
export function logoutRemoteSession() {
|
|
227
|
-
|
|
235
|
+
return postJSON('/api/auth/logout', {});
|
|
228
236
|
}
|
|
237
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/public/js/api.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ScanRequest } from '../../shared/contracts.js';\n// Server round-trips. Thin and honest: JSON in, JSON (or an SSE stream) out,\n// server error messages surfaced untouched.\n\n// Browser access is an HttpOnly session cookie set by the themed self-hosted\n// login page. Same-origin fetches include it automatically, and JavaScript never\n// reads or stores the access key. API clients can still use `Authorization:\n// Bearer …`; local mode needs no credential at all.\n\n// 0.3.0 briefly stored a raw self-hosted key here. Remove that legacy value on\n// first load so upgrading also removes the old secret rather than merely ignoring it.\ntry { localStorage.removeItem('onboarder.accessKey'); } catch { /* storage may be unavailable */ }\n\nasync function postJSON(url: string, body: unknown, options: { signal?: AbortSignal } = {}) {\n const res = await fetch(url, {\n method: 'POST',\n signal: options.signal,\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n });\n let data = null;\n try {\n data = await res.json();\n } catch {\n /* error path handled below with a generic message */\n }\n if (!res.ok) {\n throw new Error(data?.error || `The server said ${res.status}.`);\n }\n return data;\n}\n\nexport function scanOnServer(payload: ScanRequest, options: { signal?: AbortSignal } = {}) {\n return postJSON('/api/scan', payload, options);\n}\n\nexport async function cleanupClone(cloneId) {\n try {\n await fetch('/api/scan/' + encodeURIComponent(cloneId), { method: 'DELETE' });\n } catch {\n /* best-effort: the temp dir expires on its own eventually */\n }\n}\n\nexport async function fetchFileText(scanId, path) {\n const res = await fetch('/api/file?scan=' + encodeURIComponent(scanId) + '&path=' + encodeURIComponent(path));\n if (!res.ok) throw new Error('Could not read that file from the server.');\n return res.text();\n}\n\n// Which deep analyzers this machine can run, and how. Server-side scans only —\n// a browser-picked folder has no scan id and no server-visible root to point a\n// tool at, and this returns that honestly instead of pretending.\nexport async function fetchToolsStatus() {\n try {\n const res = await fetch('/api/tools');\n if (!res.ok) return null;\n const data = await res.json();\n return data && data.tools ? data.tools : null;\n } catch {\n return null; // an unreachable server is just \"no deep analysis here\"\n }\n}\n\n// Run the available analyzers against a live scan. `kinds`/`tools` narrow which\n// engines run; `options` carries the per-engine GUI settings, validated against\n// the registry schema on the server. The report normalizes every finding into\n// the shape the security view already draws, plus a per-engine pass list so\n// the UI can say which tool answered and which are missing.\nexport function runAnalysisTools(scanId, options: Record<string, any> = {}) {\n return postJSON('/api/tools/run', {\n scanId,\n kinds: options.kinds || undefined,\n tools: options.tools || undefined,\n options: options.options || undefined,\n });\n}\n\n// Install a missing engine, streaming progress events. The server emits SSE\n// frames shaped like the explain stream, minus the OpenAI envelope:\n// { type: 'log', line } / { type: 'plan', label } / { type: 'done', ok, … }\n// `onEvent` gets each one as it arrives; the promise resolves with the final\n// `done` event (or throws if the request itself failed).\nexport async function streamToolInstall(tool, onEvent) {\n const emit = typeof onEvent === 'function' ? onEvent : (..._args: unknown[]) => {};\n const res = await fetch('/api/tools/install', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ tool }),\n });\n if (!res.ok || !res.body) {\n let detail = '';\n try { detail = (await res.json()).error || ''; } catch { /* generic below */ }\n throw new Error(detail || `The server said ${res.status}.`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n let done = null;\n while (true) {\n const { done: ended, value } = await reader.read();\n if (ended) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop();\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n if (!line.startsWith('data:')) continue;\n try {\n const event = JSON.parse(line.slice(5).trim());\n emit(event);\n if (event.type === 'done') done = event;\n } catch { /* a partial frame — the next chunk completes it */ }\n }\n }\n }\n return done || { type: 'done', ok: false, error: 'The install stream ended without a verdict.' };\n}\n\n// The MCP button's three round-trips. The status one is a plain GET like\n// `/api/tools`; start and stop are POSTs because each one changes a process on\n// this machine, which is exactly the side effect `postJSON` is here for.\nexport async function fetchMcpStatus() {\n try {\n const res = await fetch('/api/mcp');\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null; // no server means no button state, not an error to shout about\n }\n}\n\nexport function startMcpServer() {\n return postJSON('/api/mcp/start', {});\n}\n\nexport function stopMcpServer() {\n return postJSON('/api/mcp/stop', {});\n}\n\n// The command an agent harness is configured with. Kept separate from the status\n// fetch because it never changes, so it is read once when the panel opens rather\n// than on every poll.\nexport async function fetchMcpCommand() {\n try {\n const res = await fetch('/api/mcp/command');\n if (!res.ok) return null;\n return await res.json();\n } catch {\n return null;\n }\n}\n\n// Streams an OpenAI-compatible chat completion through the local proxy.\n// Yields text deltas as they arrive; throws with the provider's message on\n// a non-200 from upstream.\nexport async function* streamExplain({ baseUrl, apiKey, model, messages, maxTokens = 1200, providerOptions = {}, signal = undefined as AbortSignal | undefined }) {\n const res = await fetch('/api/explain', {\n signal,\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ baseUrl, apiKey, model, messages, stream: true, max_tokens: maxTokens, ...providerOptions }),\n });\n\n if (!res.ok) {\n let detail = '';\n try {\n const data = await res.json();\n detail = data.detail || data.error || '';\n } catch {\n /* keep the generic line */\n }\n throw new Error(detail || `The provider said ${res.status}.`);\n }\n\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n buffer += decoder.decode(value, { stream: true });\n const frames = buffer.split('\\n\\n');\n buffer = frames.pop();\n for (const frame of frames) {\n for (const line of frame.split('\\n')) {\n if (!line.startsWith('data:')) continue;\n const payload = line.slice(5).trim();\n if (payload === '[DONE]') return;\n try {\n const json = JSON.parse(payload);\n const delta = json.choices?.[0]?.delta?.content;\n if (delta) yield delta;\n } catch {\n /* a partial JSON frame — the next chunk completes it */\n }\n }\n }\n }\n}\n\n// The Server drawer's three round-trips. The read is a GET that comes back\n// with the secret masked; writes go through PUT with only the changed keys;\n// rotation is a POST because it mints a new key on the server — the one and\n// only time a key ever crosses the wire in the clear.\nexport async function fetchServerSettings() {\n const res = await fetch('/api/settings');\n const data = await res.json().catch(() => null);\n if (!res.ok) throw new Error(data?.error || `The server said ${res.status}.`);\n return data;\n}\n\nexport async function updateServerSettings(patch) {\n const res = await fetch('/api/settings', {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(patch),\n });\n const data = await res.json().catch(() => null);\n if (!res.ok) throw new Error(data?.error || `The server said ${res.status}.`);\n return data;\n}\n\nexport function rotateServerAccessKey() {\n return postJSON('/api/settings/access-key', {});\n}\n\nexport function logoutRemoteSession() {\n return postJSON('/api/auth/logout', {});\n}\n"]}
|
package/public/js/atlas.js
CHANGED
|
@@ -9,90 +9,82 @@
|
|
|
9
9
|
//
|
|
10
10
|
// Deciding what is in the list and drawing one card are both pure, and live in
|
|
11
11
|
// shared/diagram/atlas.js with tests. What is left here is the DOM.
|
|
12
|
-
|
|
13
12
|
import { atlasSpecs, atlasDiagram, filterAtlasItems } from '/shared/diagram/atlas.js';
|
|
14
13
|
import { escapeHtml } from './html.js';
|
|
15
14
|
import { state, focusFile, focusFolder, clearFocus } from './state.js';
|
|
16
|
-
|
|
17
|
-
let
|
|
18
|
-
let canvas = null; // #canvas — the viewport, which is what fixes the list's size
|
|
15
|
+
let host = null; // #canvasContent — the pannable layer inside the canvas
|
|
16
|
+
let canvas = null; // #canvas — the viewport, which is what fixes the list's size
|
|
19
17
|
let hooks = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
onSyncInspector: (..._args) => { },
|
|
19
|
+
onRender: (..._args) => { },
|
|
20
|
+
onHome: (..._args) => { },
|
|
23
21
|
};
|
|
24
|
-
|
|
25
22
|
export function initAtlas(options) {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
host = options.host;
|
|
24
|
+
canvas = options.canvas;
|
|
25
|
+
hooks = { ...hooks, ...options };
|
|
29
26
|
}
|
|
30
|
-
|
|
31
27
|
// Built once per repo and kept: the catalogue is a function of the scan, and the
|
|
32
28
|
// scan does not change while it is loaded. `unloadRepo` resets the flag.
|
|
33
29
|
function specs() {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
if (!state.atlas.built) {
|
|
31
|
+
const { scan, facts, manifest, patterns } = state;
|
|
32
|
+
state.atlas = { built: true, items: atlasSpecs(scan, facts, manifest, patterns) };
|
|
33
|
+
}
|
|
34
|
+
return state.atlas.items;
|
|
39
35
|
}
|
|
40
|
-
|
|
41
36
|
export function renderAtlasList() {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const card = document.createElement('div');
|
|
62
|
-
card.className = 'atlas-card';
|
|
63
|
-
card.innerHTML = `
|
|
37
|
+
const items = filterAtlasItems(specs(), state.filters);
|
|
38
|
+
host.classList.add('atlas-mode');
|
|
39
|
+
hooks.onHome(); // the list is a document — never inherit a diagram's zoom
|
|
40
|
+
const list = document.createElement('div');
|
|
41
|
+
list.className = 'atlas-list';
|
|
42
|
+
// Exact viewport fit, because the list scrolls itself rather than being panned.
|
|
43
|
+
list.style.width = canvas.clientWidth + 'px';
|
|
44
|
+
list.style.height = canvas.clientHeight + 'px';
|
|
45
|
+
const head = document.createElement('p');
|
|
46
|
+
head.className = 'atlas-head';
|
|
47
|
+
head.textContent = `${items.length} maps, drawn from the import graph — no AI involved. `
|
|
48
|
+
+ `Open one; if it doesn't satisfy you, the AI draft button redraws it.`;
|
|
49
|
+
list.appendChild(head);
|
|
50
|
+
const grid = document.createElement('div');
|
|
51
|
+
grid.className = 'atlas-grid';
|
|
52
|
+
for (const it of items) {
|
|
53
|
+
const card = document.createElement('div');
|
|
54
|
+
card.className = 'atlas-card';
|
|
55
|
+
card.innerHTML = `
|
|
64
56
|
<div class="atlas-card-top">
|
|
65
57
|
<span class="atlas-kind is-${escapeHtml(it.kind)}">${escapeHtml(it.kind)}</span>
|
|
66
58
|
<span class="atlas-title" title="${escapeHtml(it.path || it.title)}">${escapeHtml(it.title)}</span>
|
|
67
59
|
</div>
|
|
68
60
|
<div class="atlas-sub">${escapeHtml(it.sub)}</div>
|
|
69
61
|
`;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
host.appendChild(list);
|
|
62
|
+
card.addEventListener('click', () => openAtlasItem(it));
|
|
63
|
+
grid.appendChild(card);
|
|
64
|
+
}
|
|
65
|
+
list.appendChild(grid);
|
|
66
|
+
host.innerHTML = '';
|
|
67
|
+
host.appendChild(list);
|
|
77
68
|
}
|
|
78
|
-
|
|
79
69
|
// Opening a card points the rest of the app at the same subject, so the sidebar,
|
|
80
70
|
// the inspector and the breadcrumbs agree with the picture on the canvas.
|
|
81
71
|
function openAtlasItem(item) {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
state.atlasOpen = item;
|
|
73
|
+
if (item.kind === 'file')
|
|
74
|
+
focusFile(item.path);
|
|
75
|
+
else if (item.kind === 'folder')
|
|
76
|
+
focusFolder(item.path);
|
|
77
|
+
else
|
|
78
|
+
clearFocus();
|
|
79
|
+
hooks.onSyncInspector();
|
|
80
|
+
hooks.onRender();
|
|
89
81
|
}
|
|
90
|
-
|
|
91
82
|
// The diagram for whichever card is open, drawn fresh on each canvas render.
|
|
92
83
|
// Fresh matters: a Mermaid source carries its own palette, so a cached one keeps
|
|
93
84
|
// the theme it was born under. The old atlas stored the source on the item and
|
|
94
85
|
// an opened card stayed light after switching to dark.
|
|
95
86
|
export function openCardDiagram() {
|
|
96
|
-
|
|
97
|
-
|
|
87
|
+
const { scan, facts, manifest, patterns } = state;
|
|
88
|
+
return atlasDiagram(state.atlasOpen, { scan, facts, manifest, patterns });
|
|
98
89
|
}
|
|
90
|
+
//# sourceMappingURL=atlas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"atlas.js","sourceRoot":"","sources":["../../src/public/js/atlas.ts"],"names":[],"mappings":"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","sourcesContent":["// The atlas view: a scrollable catalogue of every map, and the card that opens.\n//\n// Two things make this view unlike the others. It is a document rather than a\n// diagram, so it opts out of the canvas's pan and zoom (`atlas-mode`, which\n// diagramPane.js checks before it swallows a drag or a wheel). And a card, once\n// opened, *becomes* another view: the canvas draws the card's diagram and the AI\n// draft button borrows that view's fact sheet. Which is why `atlasOpen` holds\n// the whole item and not just an index.\n//\n// Deciding what is in the list and drawing one card are both pure, and live in\n// shared/diagram/atlas.js with tests. What is left here is the DOM.\n\nimport { atlasSpecs, atlasDiagram, filterAtlasItems } from '/shared/diagram/atlas.js';\nimport { escapeHtml } from './html.js';\nimport { state, focusFile, focusFolder, clearFocus } from './state.js';\n\nlet host = null; // #canvasContent — the pannable layer inside the canvas\nlet canvas = null; // #canvas — the viewport, which is what fixes the list's size\nlet hooks = {\n onSyncInspector: (..._args: unknown[]) => {},\n onRender: (..._args: unknown[]) => {},\n onHome: (..._args: unknown[]) => {},\n};\n\nexport function initAtlas(options) {\n host = options.host;\n canvas = options.canvas;\n hooks = { ...hooks, ...options };\n}\n\n// Built once per repo and kept: the catalogue is a function of the scan, and the\n// scan does not change while it is loaded. `unloadRepo` resets the flag.\nfunction specs() {\n if (!state.atlas.built) {\n const { scan, facts, manifest, patterns } = state;\n state.atlas = { built: true, items: atlasSpecs(scan, facts, manifest, patterns) };\n }\n return state.atlas.items;\n}\n\nexport function renderAtlasList() {\n const items = filterAtlasItems(specs(), state.filters);\n host.classList.add('atlas-mode');\n hooks.onHome(); // the list is a document — never inherit a diagram's zoom\n\n const list = document.createElement('div');\n list.className = 'atlas-list';\n // Exact viewport fit, because the list scrolls itself rather than being panned.\n list.style.width = canvas.clientWidth + 'px';\n list.style.height = canvas.clientHeight + 'px';\n\n const head = document.createElement('p');\n head.className = 'atlas-head';\n head.textContent = `${items.length} maps, drawn from the import graph — no AI involved. `\n + `Open one; if it doesn't satisfy you, the AI draft button redraws it.`;\n list.appendChild(head);\n\n const grid = document.createElement('div');\n grid.className = 'atlas-grid';\n for (const it of items) {\n const card = document.createElement('div');\n card.className = 'atlas-card';\n card.innerHTML = `\n <div class=\"atlas-card-top\">\n <span class=\"atlas-kind is-${escapeHtml(it.kind)}\">${escapeHtml(it.kind)}</span>\n <span class=\"atlas-title\" title=\"${escapeHtml(it.path || it.title)}\">${escapeHtml(it.title)}</span>\n </div>\n <div class=\"atlas-sub\">${escapeHtml(it.sub)}</div>\n `;\n card.addEventListener('click', () => openAtlasItem(it));\n grid.appendChild(card);\n }\n list.appendChild(grid);\n\n host.innerHTML = '';\n host.appendChild(list);\n}\n\n// Opening a card points the rest of the app at the same subject, so the sidebar,\n// the inspector and the breadcrumbs agree with the picture on the canvas.\nfunction openAtlasItem(item) {\n state.atlasOpen = item;\n if (item.kind === 'file') focusFile(item.path);\n else if (item.kind === 'folder') focusFolder(item.path);\n else clearFocus();\n\n hooks.onSyncInspector();\n hooks.onRender();\n}\n\n// The diagram for whichever card is open, drawn fresh on each canvas render.\n// Fresh matters: a Mermaid source carries its own palette, so a cached one keeps\n// the theme it was born under. The old atlas stored the source on the item and\n// an opened card stayed light after switching to dark.\nexport function openCardDiagram() {\n const { scan, facts, manifest, patterns } = state;\n return atlasDiagram(state.atlasOpen, { scan, facts, manifest, patterns });\n}\n"]}
|