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
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { GitDiff, ReviewMode } from '../shared/review/contracts.js';
|
|
2
|
+
export interface DiffOptions {
|
|
3
|
+
base?: string;
|
|
4
|
+
head?: string;
|
|
5
|
+
file?: string;
|
|
6
|
+
mode?: ReviewMode;
|
|
7
|
+
includeUntracked?: boolean;
|
|
8
|
+
signal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
export declare class GitDiffError extends Error {
|
|
11
|
+
status: number;
|
|
12
|
+
constructor(message: string, status?: number);
|
|
13
|
+
}
|
|
14
|
+
export declare function getGitRefs(root: string): Promise<{
|
|
15
|
+
reason?: undefined;
|
|
16
|
+
available: boolean;
|
|
17
|
+
branches: string[];
|
|
18
|
+
tags: string[];
|
|
19
|
+
current: string;
|
|
20
|
+
commits: {
|
|
21
|
+
hash: string;
|
|
22
|
+
short: string;
|
|
23
|
+
message: string;
|
|
24
|
+
author: string;
|
|
25
|
+
date: string;
|
|
26
|
+
}[];
|
|
27
|
+
} | {
|
|
28
|
+
branches?: undefined;
|
|
29
|
+
tags?: undefined;
|
|
30
|
+
current?: undefined;
|
|
31
|
+
commits?: undefined;
|
|
32
|
+
available: boolean;
|
|
33
|
+
reason: string;
|
|
34
|
+
}>;
|
|
35
|
+
export declare function getGitDiff(root: string, options?: DiffOptions): Promise<GitDiff>;
|
|
36
|
+
export declare function parseUnifiedDiff(diffText: string): GitDiff;
|
package/server/gitDiff.js
CHANGED
|
@@ -1,184 +1,286 @@
|
|
|
1
|
-
// Git
|
|
2
|
-
// Executes git subcommands safely via child_process and parses patch hunks.
|
|
3
|
-
|
|
1
|
+
// Bounded, shell-free Git comparisons. A failed range must never become another diff.
|
|
4
2
|
import { execFile } from 'node:child_process';
|
|
5
3
|
import { promisify } from 'node:util';
|
|
6
|
-
|
|
4
|
+
import { lstat, readFile, realpath } from 'node:fs/promises';
|
|
5
|
+
import { isInside, resolveInside } from './paths.js';
|
|
7
6
|
const execFileAsync = promisify(execFile);
|
|
8
|
-
const MAX_DIFF_BYTES = 5 * 1024 * 1024;
|
|
9
|
-
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
]);
|
|
18
|
-
|
|
19
|
-
const branches = branchRes.stdout.split('\n').map((b) => b.trim()).filter(Boolean);
|
|
20
|
-
const tags = tagRes.stdout.split('\n').map((t) => t.trim()).filter(Boolean);
|
|
21
|
-
const current = headRes.stdout.trim() || 'HEAD';
|
|
22
|
-
|
|
23
|
-
const commits = logRes.stdout.split('\n').filter(Boolean).map((line) => {
|
|
24
|
-
const [hash, short, message, author, date] = line.split('|');
|
|
25
|
-
return { hash, short, message, author, date };
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
available: true,
|
|
30
|
-
branches: [...new Set(branches)],
|
|
31
|
-
tags,
|
|
32
|
-
current,
|
|
33
|
-
commits,
|
|
34
|
-
};
|
|
35
|
-
} catch (err) {
|
|
36
|
-
return { available: false, reason: err.message };
|
|
37
|
-
}
|
|
7
|
+
const MAX_DIFF_BYTES = 5 * 1024 * 1024;
|
|
8
|
+
const EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
|
|
9
|
+
export class GitDiffError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
constructor(message, status = 422) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.status = status;
|
|
14
|
+
this.name = 'GitDiffError';
|
|
15
|
+
}
|
|
38
16
|
}
|
|
39
|
-
|
|
40
|
-
export async function getGitDiff(root, options = {}) {
|
|
41
|
-
const { base, head, file } = options;
|
|
42
|
-
const args = ['diff', '--no-color', '-U3'];
|
|
43
|
-
|
|
44
|
-
if (base && head) {
|
|
45
|
-
args.push(`${base}...${head}`);
|
|
46
|
-
} else if (base) {
|
|
47
|
-
args.push(base);
|
|
48
|
-
} else {
|
|
49
|
-
args.push('HEAD');
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (file) {
|
|
53
|
-
args.push('--', file);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
try {
|
|
57
|
-
const { stdout } = await execFileAsync('git', args, {
|
|
58
|
-
cwd: root,
|
|
59
|
-
maxBuffer: MAX_DIFF_BYTES,
|
|
60
|
-
});
|
|
61
|
-
return parseUnifiedDiff(stdout);
|
|
62
|
-
} catch (err) {
|
|
63
|
-
// If git diff exited with empty or specific error, fallback to HEAD~1..HEAD or working tree
|
|
17
|
+
async function git(root, args, signal) {
|
|
64
18
|
try {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
19
|
+
const { stdout } = await execFileAsync('git', ['--literal-pathspecs', '-c', 'core.quotePath=false', ...args], {
|
|
20
|
+
cwd: root, maxBuffer: MAX_DIFF_BYTES, timeout: 15000, killSignal: 'SIGKILL', signal,
|
|
21
|
+
env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' },
|
|
22
|
+
});
|
|
23
|
+
return stdout;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (signal?.aborted)
|
|
27
|
+
throw error;
|
|
28
|
+
const e = error;
|
|
29
|
+
if (e.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER')
|
|
30
|
+
throw new GitDiffError('This diff exceeds the 5 MB review limit. Choose a smaller range.', 413);
|
|
31
|
+
if (e.killed)
|
|
32
|
+
throw new GitDiffError('Git took too long. Choose a smaller comparison and try again.', 408);
|
|
33
|
+
throw new GitDiffError('Git could not read this comparison. Check the repository and its available history.');
|
|
72
34
|
}
|
|
73
|
-
}
|
|
74
35
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
newPath,
|
|
99
|
-
status: 'modified',
|
|
100
|
-
additions: 0,
|
|
101
|
-
deletions: 0,
|
|
102
|
-
hunks: [],
|
|
103
|
-
};
|
|
104
|
-
files.push(currentFile);
|
|
105
|
-
currentHunk = null;
|
|
106
|
-
continue;
|
|
36
|
+
async function resolveRef(root, ref, signal) {
|
|
37
|
+
if (!ref || ref.length > 200 || ref.startsWith('-') || !/^[a-zA-Z0-9_./~^@{}-]+$/.test(ref))
|
|
38
|
+
throw new GitDiffError('Use a valid branch, tag, or commit reference.', 400);
|
|
39
|
+
try {
|
|
40
|
+
return (await git(root, ['rev-parse', '--verify', '--end-of-options', ref + '^{commit}'], signal)).trim();
|
|
41
|
+
}
|
|
42
|
+
catch (e) {
|
|
43
|
+
if (signal?.aborted || (e instanceof GitDiffError && e.status !== 422))
|
|
44
|
+
throw e;
|
|
45
|
+
throw new GitDiffError(`Reference "${ref}" is unavailable. Shallow clones may not contain older commits.`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
export async function getGitRefs(root) {
|
|
49
|
+
try {
|
|
50
|
+
await git(root, ['rev-parse', '--is-inside-work-tree']);
|
|
51
|
+
const [branches, tags, current, log] = await Promise.all([
|
|
52
|
+
git(root, ['branch', '-a', '--format=%(refname:short)']),
|
|
53
|
+
git(root, ['tag', '--sort=-creatordate']),
|
|
54
|
+
git(root, ['symbolic-ref', '--short', 'HEAD']).catch(() => 'HEAD'),
|
|
55
|
+
git(root, ['log', '-n', '40', '--format=%H%x00%h%x00%s%x00%an%x00%aI']).catch(() => ''),
|
|
56
|
+
]);
|
|
57
|
+
return { available: true, branches: branches.trim().split('\n').filter(Boolean), tags: tags.trim().split('\n').filter(Boolean), current: current.trim(),
|
|
58
|
+
commits: log.trim().split('\n').filter(Boolean).map(line => { const [hash, short, message, author, date] = line.split('\0'); return { hash, short, message, author, date }; }) };
|
|
107
59
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
if (line.startsWith('new file mode ')) {
|
|
112
|
-
currentFile.status = 'added';
|
|
113
|
-
continue;
|
|
60
|
+
catch (err) {
|
|
61
|
+
return { available: false, reason: err instanceof Error ? err.message : 'Git unavailable.' };
|
|
114
62
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
63
|
+
}
|
|
64
|
+
export async function getGitDiff(root, options = {}) {
|
|
65
|
+
const { base = 'HEAD', head = '', file = '', includeUntracked = false, signal } = options;
|
|
66
|
+
const mode = options.mode || (head ? 'range' : 'working');
|
|
67
|
+
if (!['working', 'staged', 'range'].includes(mode))
|
|
68
|
+
throw new GitDiffError('Choose working, staged, or range review.', 400);
|
|
69
|
+
if (mode === 'range' && !head)
|
|
70
|
+
throw new GitDiffError('A branch comparison needs a head reference.', 400);
|
|
71
|
+
await git(root, ['rev-parse', '--is-inside-work-tree'], signal);
|
|
72
|
+
const repoRoot = (await git(root, ['rev-parse', '--show-toplevel'], signal)).trim();
|
|
73
|
+
if (await realpath(root) !== await realpath(repoRoot))
|
|
74
|
+
throw new GitDiffError('Open the Git repository root to review changes. A subfolder scan cannot read changes outside its scan root.', 400);
|
|
75
|
+
let baseHash;
|
|
76
|
+
try {
|
|
77
|
+
baseHash = await resolveRef(root, base || 'HEAD', signal);
|
|
118
78
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
79
|
+
catch (error) {
|
|
80
|
+
// An unborn repository has no HEAD. Only that explicit default is allowed.
|
|
81
|
+
if ((base || 'HEAD') !== 'HEAD' || mode === 'range' || signal?.aborted)
|
|
82
|
+
throw error;
|
|
83
|
+
const count = (await git(root, ['rev-list', '--all', '--count'], signal)).trim();
|
|
84
|
+
if (count !== '0')
|
|
85
|
+
throw error;
|
|
86
|
+
baseHash = EMPTY_TREE;
|
|
123
87
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
88
|
+
const headHash = mode === 'range' ? await resolveRef(root, head, signal) : '';
|
|
89
|
+
const args = ['diff', '--no-color', '--no-ext-diff', '--no-textconv', '-U3'];
|
|
90
|
+
if (mode === 'staged')
|
|
91
|
+
args.push('--cached');
|
|
92
|
+
args.push(headHash ? `${baseHash}...${headHash}` : baseHash, '--');
|
|
93
|
+
if (file)
|
|
94
|
+
args.push(file);
|
|
95
|
+
let raw = await git(root, args, signal);
|
|
96
|
+
let untracked = 0;
|
|
97
|
+
if (includeUntracked && mode === 'working' && !file) {
|
|
98
|
+
const names = (await git(root, ['ls-files', '--others', '--exclude-standard', '-z'], signal)).split('\0').filter(Boolean);
|
|
99
|
+
if (names.length > 200)
|
|
100
|
+
throw new GitDiffError('More than 200 untracked files. Stage selected files or narrow the repository before reviewing.', 413);
|
|
101
|
+
const canonicalRoot = await realpath(root);
|
|
102
|
+
for (const name of names) {
|
|
103
|
+
signal?.throwIfAborted();
|
|
104
|
+
const abs = resolveInside(root, name);
|
|
105
|
+
if (!abs)
|
|
106
|
+
throw new GitDiffError('An untracked path is outside this repository.');
|
|
107
|
+
const st = await lstat(abs);
|
|
108
|
+
if (st.isSymbolicLink()) {
|
|
109
|
+
raw += `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\nnew file mode 120000\nonboarder skipped symlink\n`;
|
|
110
|
+
untracked++;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (!st.isFile())
|
|
114
|
+
continue;
|
|
115
|
+
if (!isInside(canonicalRoot, await realpath(abs)))
|
|
116
|
+
throw new GitDiffError('An untracked path resolves outside this repository.');
|
|
117
|
+
if (st.size > 1024 * 1024)
|
|
118
|
+
throw new GitDiffError(`Untracked file "${name}" exceeds the 1 MB limit. Stage it to review its Git diff.`, 413);
|
|
119
|
+
const buffer = await readFile(abs);
|
|
120
|
+
if (buffer.byteLength > 1024 * 1024)
|
|
121
|
+
throw new GitDiffError('An untracked file grew beyond the review limit.', 413);
|
|
122
|
+
const header = `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\nnew file mode 100644\n`;
|
|
123
|
+
if (buffer.includes(0))
|
|
124
|
+
raw += header + `Binary files /dev/null and ${name} differ\n`;
|
|
125
|
+
else {
|
|
126
|
+
const source = buffer.toString('utf8');
|
|
127
|
+
const lines = source === '' ? [] : source.replace(/\n$/, '').split('\n');
|
|
128
|
+
raw += header + `--- /dev/null\n+++ ${JSON.stringify('b/' + name)}\n@@ -0,0 +1,${lines.length} @@\n` + lines.map(l => '+' + l + '\n').join('');
|
|
129
|
+
}
|
|
130
|
+
untracked++;
|
|
131
|
+
if (Buffer.byteLength(raw) > MAX_DIFF_BYTES)
|
|
132
|
+
throw new GitDiffError('This diff exceeds the 5 MB review limit.', 413);
|
|
133
|
+
}
|
|
127
134
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
135
|
+
return { ...parseUnifiedDiff(raw), base: baseHash, head: headHash, mode, untracked };
|
|
136
|
+
}
|
|
137
|
+
function decodeGitPath(value) {
|
|
138
|
+
if (!value.startsWith('"'))
|
|
139
|
+
return value;
|
|
140
|
+
// Git quotes control characters and sometimes octal UTF-8 bytes.
|
|
141
|
+
const bytes = [];
|
|
142
|
+
for (let i = 1; i < value.length - 1; i++) {
|
|
143
|
+
if (value[i] === '\\') {
|
|
144
|
+
const octal = value.slice(i + 1).match(/^[0-7]{1,3}/)?.[0];
|
|
145
|
+
if (octal) {
|
|
146
|
+
bytes.push(parseInt(octal, 8));
|
|
147
|
+
i += octal.length;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
const escaped = { n: '\n', t: '\t', r: '\r', b: '\b', f: '\f', v: '\v', a: '\x07' };
|
|
151
|
+
bytes.push(...Buffer.from(escaped[value[++i]] ?? value[i]));
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const cp = value.codePointAt(i);
|
|
155
|
+
bytes.push(...Buffer.from(String.fromCodePoint(cp)));
|
|
156
|
+
if (cp > 0xffff)
|
|
157
|
+
i++;
|
|
158
|
+
}
|
|
149
159
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
160
|
+
return Buffer.from(bytes).toString('utf8');
|
|
161
|
+
}
|
|
162
|
+
export function parseUnifiedDiff(diffText) {
|
|
163
|
+
if (!diffText || typeof diffText !== 'string') {
|
|
164
|
+
return { files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 }, raw: '' };
|
|
165
|
+
}
|
|
166
|
+
const files = [];
|
|
167
|
+
const lines = diffText.split('\n');
|
|
168
|
+
let currentFile = null;
|
|
169
|
+
let currentHunk = null;
|
|
170
|
+
let totalAdditions = 0;
|
|
171
|
+
let totalDeletions = 0;
|
|
172
|
+
for (let i = 0; i < lines.length; i++) {
|
|
173
|
+
const line = lines[i];
|
|
174
|
+
// File header: diff --git a/path b/path
|
|
175
|
+
if (line.startsWith('diff --git ')) {
|
|
176
|
+
const m = line.match(/^diff --git (\"(?:[^\"\\]|\\.)*\"|a\/.*?) (\"(?:[^\"\\]|\\.)*\"|b\/.*)$/);
|
|
177
|
+
const oldPath = m ? decodeGitPath(m[1]).slice(2) : '';
|
|
178
|
+
const newPath = m ? decodeGitPath(m[2]).slice(2) : '';
|
|
179
|
+
currentFile = {
|
|
180
|
+
oldPath,
|
|
181
|
+
newPath,
|
|
182
|
+
status: 'modified',
|
|
183
|
+
additions: 0,
|
|
184
|
+
deletions: 0,
|
|
185
|
+
hunks: [],
|
|
186
|
+
};
|
|
187
|
+
files.push(currentFile);
|
|
188
|
+
currentHunk = null;
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
if (!currentFile)
|
|
192
|
+
continue;
|
|
193
|
+
// File markers disambiguate unquoted paths containing " b/" in the header.
|
|
194
|
+
if (!currentHunk && (line.startsWith('--- ') || line.startsWith('+++ '))) {
|
|
195
|
+
const value = line.slice(4);
|
|
196
|
+
const markerPath = decodeGitPath(value.startsWith('"') ? value : value.split('\t')[0]);
|
|
197
|
+
if (markerPath !== '/dev/null') {
|
|
198
|
+
if (line.startsWith('--- '))
|
|
199
|
+
currentFile.oldPath = markerPath.slice(2);
|
|
200
|
+
else
|
|
201
|
+
currentFile.newPath = markerPath.slice(2);
|
|
202
|
+
}
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (line === 'onboarder skipped symlink') {
|
|
206
|
+
currentFile.skipReason = 'Untracked symlink: target not read';
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (line.startsWith('Binary files ') || line === 'GIT binary patch') {
|
|
210
|
+
currentFile.binary = true;
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (line.startsWith('new file mode ')) {
|
|
214
|
+
currentFile.status = 'added';
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (line.startsWith('deleted file mode ')) {
|
|
218
|
+
currentFile.status = 'deleted';
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (line.startsWith('rename from ')) {
|
|
222
|
+
currentFile.status = 'renamed';
|
|
223
|
+
currentFile.oldPath = decodeGitPath(line.slice(12));
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
if (line.startsWith('rename to ')) {
|
|
227
|
+
currentFile.newPath = decodeGitPath(line.slice(10));
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
// Hunk header: @@ -1,5 +1,6 @@ optional context
|
|
231
|
+
if (line.startsWith('@@ ')) {
|
|
232
|
+
const match = line.match(/^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@(.*)$/);
|
|
233
|
+
if (match) {
|
|
234
|
+
const oldStart = parseInt(match[1], 10);
|
|
235
|
+
const oldLines = match[2] !== undefined ? parseInt(match[2], 10) : 1;
|
|
236
|
+
const newStart = parseInt(match[3], 10);
|
|
237
|
+
const newLines = match[4] !== undefined ? parseInt(match[4], 10) : 1;
|
|
238
|
+
currentHunk = {
|
|
239
|
+
header: line,
|
|
240
|
+
oldStart,
|
|
241
|
+
oldLines,
|
|
242
|
+
newStart,
|
|
243
|
+
newLines,
|
|
244
|
+
heading: match[5]?.trim() || '',
|
|
245
|
+
lines: [],
|
|
246
|
+
};
|
|
247
|
+
currentFile.hunks.push(currentHunk);
|
|
248
|
+
}
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
if (!currentHunk)
|
|
252
|
+
continue;
|
|
253
|
+
if (line.startsWith('+')) {
|
|
254
|
+
currentFile.additions++;
|
|
255
|
+
totalAdditions++;
|
|
256
|
+
currentHunk.lines.push({
|
|
257
|
+
type: 'add',
|
|
258
|
+
text: line.slice(1),
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
else if (line.startsWith('-')) {
|
|
262
|
+
currentFile.deletions++;
|
|
263
|
+
totalDeletions++;
|
|
264
|
+
currentHunk.lines.push({
|
|
265
|
+
type: 'del',
|
|
266
|
+
text: line.slice(1),
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
else if (line.startsWith(' ')) {
|
|
270
|
+
currentHunk.lines.push({
|
|
271
|
+
type: 'context',
|
|
272
|
+
text: line.slice(1),
|
|
273
|
+
});
|
|
274
|
+
}
|
|
172
275
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
}
|
|
182
|
-
raw: diffText,
|
|
183
|
-
};
|
|
276
|
+
return {
|
|
277
|
+
files,
|
|
278
|
+
stats: {
|
|
279
|
+
filesChanged: files.length,
|
|
280
|
+
additions: totalAdditions,
|
|
281
|
+
deletions: totalDeletions,
|
|
282
|
+
},
|
|
283
|
+
raw: diffText,
|
|
284
|
+
};
|
|
184
285
|
}
|
|
286
|
+
//# sourceMappingURL=gitDiff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitDiff.js","sourceRoot":"","sources":["../src/server/gitDiff.ts"],"names":[],"mappings":"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","sourcesContent":["// Bounded, shell-free Git comparisons. A failed range must never become another diff.\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { lstat, readFile, realpath } from 'node:fs/promises';\nimport { isInside, resolveInside } from './paths.js';\nimport type { GitDiff, PatchFile, PatchHunk, ReviewMode } from '../shared/review/contracts.js';\nconst execFileAsync = promisify(execFile);\nconst MAX_DIFF_BYTES = 5 * 1024 * 1024;\nconst EMPTY_TREE = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';\nexport interface DiffOptions { base?: string; head?: string; file?: string; mode?: ReviewMode; includeUntracked?: boolean; signal?: AbortSignal }\n\nexport class GitDiffError extends Error {\n constructor(message: string, public status = 422) { super(message); this.name = 'GitDiffError'; }\n}\nasync function git(root: string, args: string[], signal?: AbortSignal): Promise<string> {\n try {\n const { stdout } = await execFileAsync('git', ['--literal-pathspecs', '-c', 'core.quotePath=false', ...args], {\n cwd: root, maxBuffer: MAX_DIFF_BYTES, timeout: 15000, killSignal: 'SIGKILL', signal,\n env: { ...process.env, GIT_OPTIONAL_LOCKS: '0' },\n });\n return stdout;\n } catch (error) {\n if (signal?.aborted) throw error;\n const e = error as { code?: string; killed?: boolean };\n if (e.code === 'ERR_CHILD_PROCESS_STDIO_MAXBUFFER') throw new GitDiffError('This diff exceeds the 5 MB review limit. Choose a smaller range.', 413);\n if (e.killed) throw new GitDiffError('Git took too long. Choose a smaller comparison and try again.', 408);\n throw new GitDiffError('Git could not read this comparison. Check the repository and its available history.');\n }\n}\nasync function resolveRef(root: string, ref: string, signal?: AbortSignal): Promise<string> {\n if (!ref || ref.length > 200 || ref.startsWith('-') || !/^[a-zA-Z0-9_./~^@{}-]+$/.test(ref)) throw new GitDiffError('Use a valid branch, tag, or commit reference.', 400);\n try { return (await git(root, ['rev-parse', '--verify', '--end-of-options', ref + '^{commit}'], signal)).trim(); }\n catch (e) { if (signal?.aborted || (e instanceof GitDiffError && e.status !== 422)) throw e; throw new GitDiffError(`Reference \"${ref}\" is unavailable. Shallow clones may not contain older commits.`); }\n}\nexport async function getGitRefs(root: string) {\n try {\n await git(root, ['rev-parse', '--is-inside-work-tree']);\n const [branches, tags, current, log] = await Promise.all([\n git(root, ['branch', '-a', '--format=%(refname:short)']),\n git(root, ['tag', '--sort=-creatordate']),\n git(root, ['symbolic-ref', '--short', 'HEAD']).catch(() => 'HEAD'),\n git(root, ['log', '-n', '40', '--format=%H%x00%h%x00%s%x00%an%x00%aI']).catch(() => ''),\n ]);\n return { available: true, branches: branches.trim().split('\\n').filter(Boolean), tags: tags.trim().split('\\n').filter(Boolean), current: current.trim(),\n commits: log.trim().split('\\n').filter(Boolean).map(line => { const [hash, short, message, author, date] = line.split('\\0'); return { hash, short, message, author, date }; }) };\n } catch (err) { return { available: false, reason: err instanceof Error ? err.message : 'Git unavailable.' }; }\n}\nexport async function getGitDiff(root: string, options: DiffOptions = {}): Promise<GitDiff> {\n const { base = 'HEAD', head = '', file = '', includeUntracked = false, signal } = options;\n const mode = options.mode || (head ? 'range' : 'working');\n if (!['working', 'staged', 'range'].includes(mode)) throw new GitDiffError('Choose working, staged, or range review.', 400);\n if (mode === 'range' && !head) throw new GitDiffError('A branch comparison needs a head reference.', 400);\n await git(root, ['rev-parse', '--is-inside-work-tree'], signal);\n const repoRoot = (await git(root, ['rev-parse', '--show-toplevel'], signal)).trim();\n if (await realpath(root) !== await realpath(repoRoot)) throw new GitDiffError('Open the Git repository root to review changes. A subfolder scan cannot read changes outside its scan root.', 400);\n let baseHash: string;\n try { baseHash = await resolveRef(root, base || 'HEAD', signal); }\n catch (error) {\n // An unborn repository has no HEAD. Only that explicit default is allowed.\n if ((base || 'HEAD') !== 'HEAD' || mode === 'range' || signal?.aborted) throw error;\n const count = (await git(root, ['rev-list', '--all', '--count'], signal)).trim();\n if (count !== '0') throw error;\n baseHash = EMPTY_TREE;\n }\n const headHash = mode === 'range' ? await resolveRef(root, head, signal) : '';\n const args = ['diff', '--no-color', '--no-ext-diff', '--no-textconv', '-U3'];\n if (mode === 'staged') args.push('--cached');\n args.push(headHash ? `${baseHash}...${headHash}` : baseHash, '--');\n if (file) args.push(file);\n let raw = await git(root, args, signal);\n let untracked = 0;\n if (includeUntracked && mode === 'working' && !file) {\n const names = (await git(root, ['ls-files', '--others', '--exclude-standard', '-z'], signal)).split('\\0').filter(Boolean);\n if (names.length > 200) throw new GitDiffError('More than 200 untracked files. Stage selected files or narrow the repository before reviewing.', 413);\n const canonicalRoot = await realpath(root);\n for (const name of names) {\n signal?.throwIfAborted();\n const abs = resolveInside(root, name);\n if (!abs) throw new GitDiffError('An untracked path is outside this repository.');\n const st = await lstat(abs);\n if (st.isSymbolicLink()) {\n raw += `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\\nnew file mode 120000\\nonboarder skipped symlink\\n`; untracked++; continue;\n }\n if (!st.isFile()) continue;\n if (!isInside(canonicalRoot, await realpath(abs))) throw new GitDiffError('An untracked path resolves outside this repository.');\n if (st.size > 1024 * 1024) throw new GitDiffError(`Untracked file \"${name}\" exceeds the 1 MB limit. Stage it to review its Git diff.`, 413);\n const buffer = await readFile(abs);\n if (buffer.byteLength > 1024 * 1024) throw new GitDiffError('An untracked file grew beyond the review limit.', 413);\n const header = `diff --git ${JSON.stringify('a/' + name)} ${JSON.stringify('b/' + name)}\\nnew file mode 100644\\n`;\n if (buffer.includes(0)) raw += header + `Binary files /dev/null and ${name} differ\\n`;\n else {\n const source = buffer.toString('utf8');\n const lines = source === '' ? [] : source.replace(/\\n$/, '').split('\\n');\n raw += header + `--- /dev/null\\n+++ ${JSON.stringify('b/' + name)}\\n@@ -0,0 +1,${lines.length} @@\\n` + lines.map(l => '+' + l + '\\n').join('');\n }\n untracked++;\n if (Buffer.byteLength(raw) > MAX_DIFF_BYTES) throw new GitDiffError('This diff exceeds the 5 MB review limit.', 413);\n }\n }\n return { ...parseUnifiedDiff(raw), base: baseHash, head: headHash, mode, untracked };\n}\nfunction decodeGitPath(value: string): string {\n if (!value.startsWith('\"')) return value;\n // Git quotes control characters and sometimes octal UTF-8 bytes.\n const bytes: number[] = [];\n for (let i = 1; i < value.length - 1; i++) {\n if (value[i] === '\\\\') {\n const octal = value.slice(i + 1).match(/^[0-7]{1,3}/)?.[0];\n if (octal) { bytes.push(parseInt(octal, 8)); i += octal.length; continue; }\n const escaped: Record<string, string> = { n: '\\n', t: '\\t', r: '\\r', b: '\\b', f: '\\f', v: '\\v', a: '\\x07' };\n bytes.push(...Buffer.from(escaped[value[++i]] ?? value[i]));\n } else { const cp = value.codePointAt(i)!; bytes.push(...Buffer.from(String.fromCodePoint(cp))); if (cp > 0xffff) i++; }\n }\n return Buffer.from(bytes).toString('utf8');\n}\n\nexport function parseUnifiedDiff(diffText: string): GitDiff {\n if (!diffText || typeof diffText !== 'string') {\n return { files: [], stats: { filesChanged: 0, additions: 0, deletions: 0 }, raw: '' };\n }\n\n const files: PatchFile[] = [];\n const lines = diffText.split('\\n');\n let currentFile: PatchFile | null = null;\n let currentHunk: PatchHunk | null = null;\n let totalAdditions = 0;\n let totalDeletions = 0;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n\n // File header: diff --git a/path b/path\n if (line.startsWith('diff --git ')) {\n const m = line.match(/^diff --git (\\\"(?:[^\\\"\\\\]|\\\\.)*\\\"|a\\/.*?) (\\\"(?:[^\\\"\\\\]|\\\\.)*\\\"|b\\/.*)$/);\n const oldPath = m ? decodeGitPath(m[1]).slice(2) : '';\n const newPath = m ? decodeGitPath(m[2]).slice(2) : '';\n currentFile = {\n oldPath,\n newPath,\n status: 'modified',\n additions: 0,\n deletions: 0,\n hunks: [],\n };\n files.push(currentFile);\n currentHunk = null;\n continue;\n }\n\n if (!currentFile) continue;\n // File markers disambiguate unquoted paths containing \" b/\" in the header.\n if (!currentHunk && (line.startsWith('--- ') || line.startsWith('+++ '))) {\n const value = line.slice(4);\n const markerPath = decodeGitPath(value.startsWith('\"') ? value : value.split('\\t')[0]);\n if (markerPath !== '/dev/null') {\n if (line.startsWith('--- ')) currentFile.oldPath = markerPath.slice(2);\n else currentFile.newPath = markerPath.slice(2);\n }\n continue;\n }\n if (line === 'onboarder skipped symlink') { currentFile.skipReason = 'Untracked symlink: target not read'; continue; }\n if (line.startsWith('Binary files ') || line === 'GIT binary patch') { currentFile.binary = true; continue; }\n\n if (line.startsWith('new file mode ')) {\n currentFile.status = 'added';\n continue;\n }\n if (line.startsWith('deleted file mode ')) {\n currentFile.status = 'deleted';\n continue;\n }\n if (line.startsWith('rename from ')) {\n currentFile.status = 'renamed';\n currentFile.oldPath = decodeGitPath(line.slice(12));\n continue;\n }\n if (line.startsWith('rename to ')) {\n currentFile.newPath = decodeGitPath(line.slice(10));\n continue;\n }\n\n // Hunk header: @@ -1,5 +1,6 @@ optional context\n if (line.startsWith('@@ ')) {\n const match = line.match(/^@@ -(\\d+)(?:,(\\d+))? \\+(\\d+)(?:,(\\d+))? @@(.*)$/);\n if (match) {\n const oldStart = parseInt(match[1], 10);\n const oldLines = match[2] !== undefined ? parseInt(match[2], 10) : 1;\n const newStart = parseInt(match[3], 10);\n const newLines = match[4] !== undefined ? parseInt(match[4], 10) : 1;\n currentHunk = {\n header: line,\n oldStart,\n oldLines,\n newStart,\n newLines,\n heading: match[5]?.trim() || '',\n lines: [],\n };\n currentFile.hunks.push(currentHunk);\n }\n continue;\n }\n\n if (!currentHunk) continue;\n\n if (line.startsWith('+')) {\n currentFile.additions++;\n totalAdditions++;\n currentHunk.lines.push({\n type: 'add',\n text: line.slice(1),\n });\n } else if (line.startsWith('-')) {\n currentFile.deletions++;\n totalDeletions++;\n currentHunk.lines.push({\n type: 'del',\n text: line.slice(1),\n });\n } else if (line.startsWith(' ')) {\n currentHunk.lines.push({\n type: 'context',\n text: line.slice(1),\n });\n }\n }\n\n return {\n files,\n stats: {\n filesChanged: files.length,\n additions: totalAdditions,\n deletions: totalDeletions,\n },\n raw: diffText,\n };\n}\n"]}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare function gitLog(root: any): Promise<{
|
|
2
|
+
ok: boolean;
|
|
3
|
+
reason: string;
|
|
4
|
+
text?: undefined;
|
|
5
|
+
totalCommits?: undefined;
|
|
6
|
+
} | {
|
|
7
|
+
reason?: undefined;
|
|
8
|
+
ok: boolean;
|
|
9
|
+
text: any;
|
|
10
|
+
totalCommits: number;
|
|
11
|
+
}>;
|
|
12
|
+
export declare function parseGitLog(text: any): any[];
|