codebase-onboarder 0.6.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 +174 -46
- 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 +321 -329
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +384 -313
- 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 +368 -302
- 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 +42 -44
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +90 -95
- 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 +143 -144
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +465 -482
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +28 -44
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +214 -161
- 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 +35 -44
- 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 +152 -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 +37 -38
- 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 -64
- 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 +41 -43
- 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/server/tunnel.js
CHANGED
|
@@ -6,92 +6,87 @@
|
|
|
6
6
|
// is installed, the exact command that would expose the current settings, and
|
|
7
7
|
// the install hint for when it isn't. The CLI (`onboarder tunnel`) is what
|
|
8
8
|
// actually spawns anything; the HTTP layer only ever reads this status.
|
|
9
|
-
|
|
10
9
|
import { spawnSync } from 'node:child_process';
|
|
11
|
-
|
|
12
10
|
import { isLoopbackHost, normalizeSettings } from './config.js';
|
|
13
|
-
|
|
14
11
|
// `spawnSync` on a missing binary resolves with an ENOENT error rather than
|
|
15
12
|
// throwing, which is exactly the signal we need. `--version` is a flag every
|
|
16
13
|
// CLI here answers; anything that doesn't is treated as absent.
|
|
17
14
|
export function findOnPath(name) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
try {
|
|
16
|
+
const res = spawnSync(name, ['--version'], { encoding: 'utf8', timeout: 5000 });
|
|
17
|
+
if (res.error)
|
|
18
|
+
return { installed: false };
|
|
19
|
+
const first = String(res.stdout || res.stderr || '').trim().split('\n')[0] || '';
|
|
20
|
+
return { installed: true, version: first.slice(0, 120) };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { installed: false };
|
|
24
|
+
}
|
|
26
25
|
}
|
|
27
|
-
|
|
28
26
|
// The one address a tunnel should forward to. Tunnels always dial loopback —
|
|
29
27
|
// that is what makes "loopback behind a tunnel" a safe self-hosted layout, so
|
|
30
28
|
// even a 0.0.0.0 bind is proxied from 127.0.0.1.
|
|
31
29
|
export function tunnelTarget(settings) {
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const s = normalizeSettings(settings);
|
|
31
|
+
return `http://127.0.0.1:${s.port}`;
|
|
34
32
|
}
|
|
35
|
-
|
|
36
33
|
export function cloudflareCommand(settings) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
34
|
+
// A "quick tunnel": no account, no DNS edit, a random trycloudflare.com name
|
|
35
|
+
// that lives as long as the process. The named-tunnel route (a fixed domain
|
|
36
|
+
// on the person's own Cloudflare account) is a `cloudflared tunnel` setup of
|
|
37
|
+
// its own; the wizard says so rather than pretending one command covers both.
|
|
38
|
+
return `cloudflared tunnel --url ${tunnelTarget(settings)}`;
|
|
42
39
|
}
|
|
43
|
-
|
|
44
40
|
export function tailscaleCommand(settings) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
41
|
+
const s = normalizeSettings(settings);
|
|
42
|
+
// serve puts the machine's tailnet name (https://host.tailnet.ts.net) in
|
|
43
|
+
// front of the port, visible only to the tailnet. funnel would go further
|
|
44
|
+
// and publish it to the internet — mentioned, never run for you.
|
|
45
|
+
return `tailscale serve --bg --https=443 ${tunnelTarget(s)}`;
|
|
50
46
|
}
|
|
51
|
-
|
|
52
47
|
export function installHint(name) {
|
|
53
|
-
|
|
48
|
+
if (name === 'caddy') {
|
|
49
|
+
return process.platform === 'darwin'
|
|
50
|
+
? 'brew install caddy'
|
|
51
|
+
: 'Install Caddy with: sudo apt install caddy';
|
|
52
|
+
}
|
|
53
|
+
if (name === 'cloudflared') {
|
|
54
|
+
return process.platform === 'darwin'
|
|
55
|
+
? 'brew install cloudflared (or see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)'
|
|
56
|
+
: 'See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/';
|
|
57
|
+
}
|
|
54
58
|
return process.platform === 'darwin'
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
if (name === 'cloudflared') {
|
|
59
|
-
return process.platform === 'darwin'
|
|
60
|
-
? 'brew install cloudflared (or see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)'
|
|
61
|
-
: 'See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/';
|
|
62
|
-
}
|
|
63
|
-
return process.platform === 'darwin'
|
|
64
|
-
? 'brew install --cask tailscale (or see https://tailscale.com/download)'
|
|
65
|
-
: 'See https://tailscale.com/download';
|
|
59
|
+
? 'brew install --cask tailscale (or see https://tailscale.com/download)'
|
|
60
|
+
: 'See https://tailscale.com/download';
|
|
66
61
|
}
|
|
67
|
-
|
|
68
62
|
// The settings drawer's tunnel section and `onboarder doctor` both render this:
|
|
69
63
|
// what is enabled, what is installed, and what to run. Never spawns anything.
|
|
70
64
|
export function tunnelStatus(settings) {
|
|
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
|
-
|
|
65
|
+
const s = normalizeSettings(settings);
|
|
66
|
+
const cf = findOnPath('cloudflared');
|
|
67
|
+
const ts = findOnPath('tailscale');
|
|
68
|
+
return {
|
|
69
|
+
target: tunnelTarget(s),
|
|
70
|
+
cloudflare: {
|
|
71
|
+
enabled: s.tunnel.cloudflare,
|
|
72
|
+
installed: cf.installed,
|
|
73
|
+
version: cf.version || '',
|
|
74
|
+
command: cloudflareCommand(s),
|
|
75
|
+
install: cf.installed ? '' : installHint('cloudflared'),
|
|
76
|
+
},
|
|
77
|
+
tailscale: {
|
|
78
|
+
enabled: s.tunnel.tailscale,
|
|
79
|
+
installed: ts.installed,
|
|
80
|
+
version: ts.version || '',
|
|
81
|
+
command: tailscaleCommand(s),
|
|
82
|
+
install: ts.installed ? '' : installHint('tailscale'),
|
|
83
|
+
},
|
|
84
|
+
// A tunnel answering a bind the server refused is the classic misread of
|
|
85
|
+
// "self-hosted": the tunnel terminates TLS and dials loopback, so the bind
|
|
86
|
+
// stays 127.0.0.1. Worth one explicit line everywhere the status is shown.
|
|
87
|
+
note: isLoopbackHost(s.host)
|
|
88
|
+
? 'Loopback bind — a tunnel is the right way to reach this server remotely.'
|
|
89
|
+
: 'Network bind — a tunnel is optional; the access key is not.',
|
|
90
|
+
};
|
|
97
91
|
}
|
|
92
|
+
//# sourceMappingURL=tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/server/tunnel.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;AAC7E,6EAA6E;AAC7E,8EAA8E;AAC9E,2EAA2E;AAC3E,wEAAwE;AAExE,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhE,4EAA4E;AAC5E,6EAA6E;AAC7E,gEAAgE;AAChE,MAAM,UAAU,UAAU,CAAC,IAAI;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,KAAK;YAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACjF,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;IAC3D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;IAC9B,CAAC;AACH,CAAC;AAED,6EAA6E;AAC7E,8EAA8E;AAC9E,iDAAiD;AACjD,MAAM,UAAU,YAAY,CAAC,QAAQ;IACnC,MAAM,CAAC,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,oBAAoB,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,QAAQ;IACxC,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,8EAA8E;IAC9E,OAAO,4BAA4B,YAAY,CAAC,QAAQ,CAAC,EAAE,CAAC;AAC9D,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAQ;IACvC,MAAM,CAAC,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtC,yEAAyE;IACzE,0EAA0E;IAC1E,iEAAiE;IACjE,OAAO,oCAAoC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,IAAI;IAC9B,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QACrB,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAClC,CAAC,CAAC,oBAAoB;YACtB,CAAC,CAAC,4CAA4C,CAAC;IACnD,CAAC;IACD,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;QAC3B,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;YAClC,CAAC,CAAC,6HAA6H;YAC/H,CAAC,CAAC,8FAA8F,CAAC;IACrG,CAAC;IACD,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAClC,CAAC,CAAC,wEAAwE;QAC1E,CAAC,CAAC,oCAAoC,CAAC;AAC3C,CAAC;AAED,gFAAgF;AAChF,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,QAAQ;IACnC,MAAM,CAAC,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtC,MAAM,EAAE,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACrC,MAAM,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACnC,OAAO;QACL,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;QACvB,UAAU,EAAE;YACV,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,UAAU;YAC5B,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,OAAO,EAAE,EAAE,CAAC,OAAO,IAAI,EAAE;YACzB,OAAO,EAAE,iBAAiB,CAAC,CAAC,CAAC;YAC7B,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC;SACxD;QACD,SAAS,EAAE;YACT,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,EAAE,CAAC,SAAS;YACvB,OAAO,EAAE,EAAE,CAAC,OAAO,IAAI,EAAE;YACzB,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;YAC5B,OAAO,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC;SACtD;QACD,yEAAyE;QACzE,2EAA2E;QAC3E,2EAA2E;QAC3E,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC;YAC1B,CAAC,CAAC,0EAA0E;YAC5E,CAAC,CAAC,6DAA6D;KAClE,CAAC;AACJ,CAAC","sourcesContent":["// The two tunnels this server knows how to sit behind, and nothing else.\n//\n// A tunnel here is not a feature of the server — it is another program the\n// person runs that forwards a public name to our port. What this module owns\n// is everything we can honestly say about that arrangement: whether the tool\n// is installed, the exact command that would expose the current settings, and\n// the install hint for when it isn't. The CLI (`onboarder tunnel`) is what\n// actually spawns anything; the HTTP layer only ever reads this status.\n\nimport { spawnSync } from 'node:child_process';\n\nimport { isLoopbackHost, normalizeSettings } from './config.js';\n\n// `spawnSync` on a missing binary resolves with an ENOENT error rather than\n// throwing, which is exactly the signal we need. `--version` is a flag every\n// CLI here answers; anything that doesn't is treated as absent.\nexport function findOnPath(name) {\n try {\n const res = spawnSync(name, ['--version'], { encoding: 'utf8', timeout: 5000 });\n if (res.error) return { installed: false };\n const first = String(res.stdout || res.stderr || '').trim().split('\\n')[0] || '';\n return { installed: true, version: first.slice(0, 120) };\n } catch {\n return { installed: false };\n }\n}\n\n// The one address a tunnel should forward to. Tunnels always dial loopback —\n// that is what makes \"loopback behind a tunnel\" a safe self-hosted layout, so\n// even a 0.0.0.0 bind is proxied from 127.0.0.1.\nexport function tunnelTarget(settings) {\n const s = normalizeSettings(settings);\n return `http://127.0.0.1:${s.port}`;\n}\n\nexport function cloudflareCommand(settings) {\n // A \"quick tunnel\": no account, no DNS edit, a random trycloudflare.com name\n // that lives as long as the process. The named-tunnel route (a fixed domain\n // on the person's own Cloudflare account) is a `cloudflared tunnel` setup of\n // its own; the wizard says so rather than pretending one command covers both.\n return `cloudflared tunnel --url ${tunnelTarget(settings)}`;\n}\n\nexport function tailscaleCommand(settings) {\n const s = normalizeSettings(settings);\n // serve puts the machine's tailnet name (https://host.tailnet.ts.net) in\n // front of the port, visible only to the tailnet. funnel would go further\n // and publish it to the internet — mentioned, never run for you.\n return `tailscale serve --bg --https=443 ${tunnelTarget(s)}`;\n}\n\nexport function installHint(name) {\n if (name === 'caddy') {\n return process.platform === 'darwin'\n ? 'brew install caddy'\n : 'Install Caddy with: sudo apt install caddy';\n }\n if (name === 'cloudflared') {\n return process.platform === 'darwin'\n ? 'brew install cloudflared (or see https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)'\n : 'See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/';\n }\n return process.platform === 'darwin'\n ? 'brew install --cask tailscale (or see https://tailscale.com/download)'\n : 'See https://tailscale.com/download';\n}\n\n// The settings drawer's tunnel section and `onboarder doctor` both render this:\n// what is enabled, what is installed, and what to run. Never spawns anything.\nexport function tunnelStatus(settings) {\n const s = normalizeSettings(settings);\n const cf = findOnPath('cloudflared');\n const ts = findOnPath('tailscale');\n return {\n target: tunnelTarget(s),\n cloudflare: {\n enabled: s.tunnel.cloudflare,\n installed: cf.installed,\n version: cf.version || '',\n command: cloudflareCommand(s),\n install: cf.installed ? '' : installHint('cloudflared'),\n },\n tailscale: {\n enabled: s.tunnel.tailscale,\n installed: ts.installed,\n version: ts.version || '',\n command: tailscaleCommand(s),\n install: ts.installed ? '' : installHint('tailscale'),\n },\n // A tunnel answering a bind the server refused is the classic misread of\n // \"self-hosted\": the tunnel terminates TLS and dials loopback, so the bind\n // stays 127.0.0.1. Worth one explicit line everywhere the status is shown.\n note: isLoopbackHost(s.host)\n ? 'Loopback bind — a tunnel is the right way to reach this server remotely.'\n : 'Network bind — a tunnel is optional; the access key is not.',\n };\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare function parseFolderDoc(text: any): {
|
|
2
|
+
folderBrief: string;
|
|
3
|
+
files: Map<any, any>;
|
|
4
|
+
};
|
|
5
|
+
export declare function fileFactsLine(path: any, scan: any, facts: any): string;
|
|
6
|
+
export declare function fileStaticDoc(path: any, scan: any, facts: any): any;
|
|
7
|
+
export declare function folderStaticDoc(folder: any, scan: any, facts: any, subfolderCount?: number): string;
|
|
8
|
+
export declare function docFileRow(path: any, scan: any, facts: any): {
|
|
9
|
+
path: any;
|
|
10
|
+
name: any;
|
|
11
|
+
parsed: boolean;
|
|
12
|
+
fanIn: any;
|
|
13
|
+
fanOut: any;
|
|
14
|
+
role: string;
|
|
15
|
+
functions: any;
|
|
16
|
+
};
|
package/shared/analyzer/docs.js
CHANGED
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
// docs page shows before anyone presses "Generate", and what it keeps showing if
|
|
7
7
|
// no endpoint is ever configured. It used to sit in app.js, where it could not
|
|
8
8
|
// be tested; it is pure text-from-facts, so it belongs next to `explainLocal`.
|
|
9
|
-
|
|
10
9
|
import { factIndex, scanIndex } from './graph.js';
|
|
11
|
-
|
|
12
10
|
// Parses the model's folder-brief answer, which we ask to be shaped like:
|
|
13
11
|
//
|
|
14
12
|
// FOLDER: two plain sentences about what lives here and why.
|
|
@@ -18,118 +16,126 @@ import { factIndex, scanIndex } from './graph.js';
|
|
|
18
16
|
// Deliberately forgiving: missing markers fall back to taking the first
|
|
19
17
|
// couple of non-empty lines as the folder brief.
|
|
20
18
|
export function parseFolderDoc(text) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
19
|
+
const out = { folderBrief: '', files: new Map() };
|
|
20
|
+
if (!text)
|
|
21
|
+
return out;
|
|
22
|
+
const fallback = [];
|
|
23
|
+
for (const raw of text.split('\n')) {
|
|
24
|
+
const line = raw.trim();
|
|
25
|
+
if (!line)
|
|
26
|
+
continue;
|
|
27
|
+
const folderMatch = line.match(/^FOLDER:\s*(.+)$/i);
|
|
28
|
+
if (folderMatch) {
|
|
29
|
+
out.folderBrief = (out.folderBrief ? out.folderBrief + ' ' : '') + folderMatch[1].trim();
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const fileMatch = line.match(/^FILE:\s*([^:]+?):\s+(.+)$/i);
|
|
33
|
+
if (fileMatch) {
|
|
34
|
+
out.files.set(fileMatch[1].trim(), fileMatch[2].trim());
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
fallback.push(line);
|
|
33
38
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
out.files.set(fileMatch[1].trim(), fileMatch[2].trim());
|
|
37
|
-
continue;
|
|
39
|
+
if (!out.folderBrief && fallback.length) {
|
|
40
|
+
out.folderBrief = fallback.slice(0, 2).join(' ');
|
|
38
41
|
}
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (!out.folderBrief && fallback.length) {
|
|
43
|
-
out.folderBrief = fallback.slice(0, 2).join(' ');
|
|
44
|
-
}
|
|
45
|
-
return out;
|
|
42
|
+
return out;
|
|
46
43
|
}
|
|
47
|
-
|
|
48
44
|
// ---- documentation from the graph, no model involved -----------------------
|
|
49
|
-
|
|
50
45
|
// The one-line facts strip under a file's name in the generated docs.
|
|
51
46
|
export function fileFactsLine(path, scan, facts) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
47
|
+
const f = scanIndex(scan).fileAt(path);
|
|
48
|
+
if (!f)
|
|
49
|
+
return 'not parsed';
|
|
50
|
+
const fx = factIndex(facts);
|
|
51
|
+
const fin = facts.fanIn[path] || 0;
|
|
52
|
+
const fout = facts.fanOut[path] || 0;
|
|
53
|
+
const bits = [];
|
|
54
|
+
if (fx.entries.has(path))
|
|
55
|
+
bits.push('entry');
|
|
56
|
+
if (fin >= 5)
|
|
57
|
+
bits.push('hub');
|
|
58
|
+
if (fx.inCycle.has(path))
|
|
59
|
+
bits.push('in a cycle');
|
|
60
|
+
bits.push(`${fin} dependents · pulls in ${fout}`);
|
|
61
|
+
if (f.functions.length)
|
|
62
|
+
bits.push(`${f.functions.length} functions`);
|
|
63
|
+
return bits.join(' · ');
|
|
64
64
|
}
|
|
65
|
-
|
|
66
65
|
// A paragraph about one file. The branches are ordered by how much they tell
|
|
67
66
|
// you: being an entry point is the most useful thing to say about a file, being
|
|
68
67
|
// load-bearing is next, and "pulls in N, answers to M" is the fallback that
|
|
69
68
|
// always holds.
|
|
70
69
|
export function fileStaticDoc(path, scan, facts) {
|
|
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
|
-
|
|
70
|
+
const f = scanIndex(scan).fileAt(path);
|
|
71
|
+
if (!f)
|
|
72
|
+
return 'Not parsed — kept as an asset or data file.';
|
|
73
|
+
const fin = facts.fanIn[path] || 0;
|
|
74
|
+
const fout = facts.fanOut[path] || 0;
|
|
75
|
+
const importers = (facts.importers[path] || []).map((p) => p.split('/').pop());
|
|
76
|
+
let s;
|
|
77
|
+
if (factIndex(facts).entries.has(path)) {
|
|
78
|
+
s = `${f.name} is one of the ways into the codebase — it pulls in ${fout} other ${fout === 1 ? 'file' : 'files'} and answers to nothing above it.`;
|
|
79
|
+
}
|
|
80
|
+
else if (fin >= 5) {
|
|
81
|
+
s = `${f.name} is load-bearing: ${fin} files import it directly${importers.length ? `, ${importers.slice(0, 2).join(', ')} among them` : ''}.`;
|
|
82
|
+
}
|
|
83
|
+
else if (!fin && !fout) {
|
|
84
|
+
s = `${f.name} stands alone — nothing imports it and it imports nothing we can see.`;
|
|
85
|
+
}
|
|
86
|
+
else if (!fout) {
|
|
87
|
+
s = `${f.name} sits at the end of a chain — it imports nothing and is leaned on by ${fin} ${fin === 1 ? 'file' : 'files'}.`;
|
|
88
|
+
}
|
|
89
|
+
else if (!fin) {
|
|
90
|
+
s = `${f.name} pulls in ${fout} ${fout === 1 ? 'file' : 'files'} but nothing imports it — a door we didn't recognize, or dead code.`;
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
s = `${f.name} pulls in ${fout} and answers to ${fin}.`;
|
|
94
|
+
}
|
|
95
|
+
if (f.functions.length) {
|
|
96
|
+
s += ` It defines ${f.functions.length} function${f.functions.length === 1 ? '' : 's'} — ${f.functions.slice(0, 4).map((fn) => fn.name).join(', ')}${f.functions.length > 4 ? `, and ${f.functions.length - 4} more` : ''}.`;
|
|
97
|
+
}
|
|
98
|
+
if (f.exports.length) {
|
|
99
|
+
s += ` Exports: ${f.exports.slice(0, 4).map((e) => e.name).join(', ')}${f.exports.length > 4 ? ', …' : ''}.`;
|
|
100
|
+
}
|
|
101
|
+
return s;
|
|
97
102
|
}
|
|
98
|
-
|
|
99
103
|
// A paragraph about one folder. `subfolderCount` is passed rather than read off
|
|
100
104
|
// a tree node, so nothing in the shared layer needs to know the view's tree
|
|
101
105
|
// shape.
|
|
102
106
|
export function folderStaticDoc(folder, scan, facts, subfolderCount = 0) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
107
|
+
const here = scanIndex(scan).filesIn(folder);
|
|
108
|
+
let s = `${here.length} parsed ${here.length === 1 ? 'file lives' : 'files live'} here`;
|
|
109
|
+
if (subfolderCount)
|
|
110
|
+
s += `, with ${subfolderCount} subfolder${subfolderCount === 1 ? '' : 's'} inside`;
|
|
111
|
+
s += '.';
|
|
112
|
+
const heaviest = here
|
|
113
|
+
.map((f) => ({ name: f.name, fanIn: facts.fanIn[f.path] || 0 }))
|
|
114
|
+
.sort((a, b) => b.fanIn - a.fanIn)[0];
|
|
115
|
+
if (heaviest && heaviest.fanIn >= 3) {
|
|
116
|
+
s += ` The one everything leans on is ${heaviest.name}, with ${heaviest.fanIn} dependents.`;
|
|
117
|
+
}
|
|
118
|
+
const entries = factIndex(facts).entries;
|
|
119
|
+
const entriesHere = here.filter((f) => entries.has(f.path));
|
|
120
|
+
if (entriesHere.length)
|
|
121
|
+
s += ` The way in: ${entriesHere.map((f) => f.name).join(', ')}.`;
|
|
122
|
+
return s;
|
|
117
123
|
}
|
|
118
|
-
|
|
119
124
|
// The facts about one file as the prompts want them. Two identical copies of
|
|
120
125
|
// this used to sit in app.js — one for a single doc tab, one for the
|
|
121
126
|
// folder-by-folder pass — and they had to agree for the two pages to describe
|
|
122
127
|
// the same file the same way.
|
|
123
128
|
export function docFileRow(path, scan, facts) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
129
|
+
const f = scanIndex(scan).fileAt(path);
|
|
130
|
+
const fanIn = facts.fanIn[path] || 0;
|
|
131
|
+
return {
|
|
132
|
+
path,
|
|
133
|
+
name: path.split('/').pop(),
|
|
134
|
+
parsed: Boolean(f),
|
|
135
|
+
fanIn,
|
|
136
|
+
fanOut: facts.fanOut[path] || 0,
|
|
137
|
+
role: factIndex(facts).entries.has(path) ? 'entry' : fanIn >= 5 ? 'hub' : 'module',
|
|
138
|
+
functions: f ? f.functions.map((fn) => fn.name) : [],
|
|
139
|
+
};
|
|
135
140
|
}
|
|
141
|
+
//# sourceMappingURL=docs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docs.js","sourceRoot":"","sources":["../../src/shared/analyzer/docs.ts"],"names":[],"mappings":"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","sourcesContent":["// Documentation written from the import graph alone.\n//\n// Two halves live here. The first parses the model's answer back into rows. The\n// second writes the documentation *without* a model — plain sentences about what\n// a file is and what leans on it. That half is the offline floor: it is what the\n// docs page shows before anyone presses \"Generate\", and what it keeps showing if\n// no endpoint is ever configured. It used to sit in app.js, where it could not\n// be tested; it is pure text-from-facts, so it belongs next to `explainLocal`.\n\nimport { factIndex, scanIndex } from './graph.js';\n\n// Parses the model's folder-brief answer, which we ask to be shaped like:\n//\n// FOLDER: two plain sentences about what lives here and why.\n// FILE: scan.js: one sentence about this file.\n// FILE: graph.js: one sentence about this file.\n//\n// Deliberately forgiving: missing markers fall back to taking the first\n// couple of non-empty lines as the folder brief.\nexport function parseFolderDoc(text) {\n const out = { folderBrief: '', files: new Map() };\n if (!text) return out;\n\n const fallback = [];\n for (const raw of text.split('\\n')) {\n const line = raw.trim();\n if (!line) continue;\n\n const folderMatch = line.match(/^FOLDER:\\s*(.+)$/i);\n if (folderMatch) {\n out.folderBrief = (out.folderBrief ? out.folderBrief + ' ' : '') + folderMatch[1].trim();\n continue;\n }\n const fileMatch = line.match(/^FILE:\\s*([^:]+?):\\s+(.+)$/i);\n if (fileMatch) {\n out.files.set(fileMatch[1].trim(), fileMatch[2].trim());\n continue;\n }\n fallback.push(line);\n }\n\n if (!out.folderBrief && fallback.length) {\n out.folderBrief = fallback.slice(0, 2).join(' ');\n }\n return out;\n}\n\n// ---- documentation from the graph, no model involved -----------------------\n\n// The one-line facts strip under a file's name in the generated docs.\nexport function fileFactsLine(path, scan, facts) {\n const f = scanIndex(scan).fileAt(path);\n if (!f) return 'not parsed';\n const fx = factIndex(facts);\n const fin = facts.fanIn[path] || 0;\n const fout = facts.fanOut[path] || 0;\n const bits = [];\n if (fx.entries.has(path)) bits.push('entry');\n if (fin >= 5) bits.push('hub');\n if (fx.inCycle.has(path)) bits.push('in a cycle');\n bits.push(`${fin} dependents · pulls in ${fout}`);\n if (f.functions.length) bits.push(`${f.functions.length} functions`);\n return bits.join(' · ');\n}\n\n// A paragraph about one file. The branches are ordered by how much they tell\n// you: being an entry point is the most useful thing to say about a file, being\n// load-bearing is next, and \"pulls in N, answers to M\" is the fallback that\n// always holds.\nexport function fileStaticDoc(path, scan, facts) {\n const f = scanIndex(scan).fileAt(path);\n if (!f) return 'Not parsed — kept as an asset or data file.';\n const fin = facts.fanIn[path] || 0;\n const fout = facts.fanOut[path] || 0;\n const importers = (facts.importers[path] || []).map((p) => p.split('/').pop());\n let s;\n if (factIndex(facts).entries.has(path)) {\n s = `${f.name} is one of the ways into the codebase — it pulls in ${fout} other ${fout === 1 ? 'file' : 'files'} and answers to nothing above it.`;\n } else if (fin >= 5) {\n s = `${f.name} is load-bearing: ${fin} files import it directly${importers.length ? `, ${importers.slice(0, 2).join(', ')} among them` : ''}.`;\n } else if (!fin && !fout) {\n s = `${f.name} stands alone — nothing imports it and it imports nothing we can see.`;\n } else if (!fout) {\n s = `${f.name} sits at the end of a chain — it imports nothing and is leaned on by ${fin} ${fin === 1 ? 'file' : 'files'}.`;\n } else if (!fin) {\n s = `${f.name} pulls in ${fout} ${fout === 1 ? 'file' : 'files'} but nothing imports it — a door we didn't recognize, or dead code.`;\n } else {\n s = `${f.name} pulls in ${fout} and answers to ${fin}.`;\n }\n if (f.functions.length) {\n s += ` It defines ${f.functions.length} function${f.functions.length === 1 ? '' : 's'} — ${f.functions.slice(0, 4).map((fn) => fn.name).join(', ')}${f.functions.length > 4 ? `, and ${f.functions.length - 4} more` : ''}.`;\n }\n if (f.exports.length) {\n s += ` Exports: ${f.exports.slice(0, 4).map((e) => e.name).join(', ')}${f.exports.length > 4 ? ', …' : ''}.`;\n }\n return s;\n}\n\n// A paragraph about one folder. `subfolderCount` is passed rather than read off\n// a tree node, so nothing in the shared layer needs to know the view's tree\n// shape.\nexport function folderStaticDoc(folder, scan, facts, subfolderCount = 0) {\n const here = scanIndex(scan).filesIn(folder);\n let s = `${here.length} parsed ${here.length === 1 ? 'file lives' : 'files live'} here`;\n if (subfolderCount) s += `, with ${subfolderCount} subfolder${subfolderCount === 1 ? '' : 's'} inside`;\n s += '.';\n const heaviest = here\n .map((f) => ({ name: f.name, fanIn: facts.fanIn[f.path] || 0 }))\n .sort((a, b) => b.fanIn - a.fanIn)[0];\n if (heaviest && heaviest.fanIn >= 3) {\n s += ` The one everything leans on is ${heaviest.name}, with ${heaviest.fanIn} dependents.`;\n }\n const entries = factIndex(facts).entries;\n const entriesHere = here.filter((f) => entries.has(f.path));\n if (entriesHere.length) s += ` The way in: ${entriesHere.map((f) => f.name).join(', ')}.`;\n return s;\n}\n\n// The facts about one file as the prompts want them. Two identical copies of\n// this used to sit in app.js — one for a single doc tab, one for the\n// folder-by-folder pass — and they had to agree for the two pages to describe\n// the same file the same way.\nexport function docFileRow(path, scan, facts) {\n const f = scanIndex(scan).fileAt(path);\n const fanIn = facts.fanIn[path] || 0;\n return {\n path,\n name: path.split('/').pop(),\n parsed: Boolean(f),\n fanIn,\n fanOut: facts.fanOut[path] || 0,\n role: factIndex(facts).entries.has(path) ? 'entry' : fanIn >= 5 ? 'hub' : 'module',\n functions: f ? f.functions.map((fn) => fn.name) : [],\n };\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function explainFile(path: any, file: any, facts: any): string;
|
|
2
|
+
export declare function explainFolder(path: any, scan: any, facts: any): string;
|
|
3
|
+
export declare function explainOverview(scan: any, facts: any, manifest: any): string;
|
|
4
|
+
export declare function scanCaveats(scan: any): any[];
|