@mohantn/gate-keeper 2.1.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/.github/instructions/dotnet-api-integration.instructions.md +416 -0
- package/.github/instructions/dotnet-development.instructions.md +353 -0
- package/.github/instructions/dotnet-testing.instructions.md +406 -0
- package/.github/instructions/gate-keeper.instructions.md +91 -0
- package/.github/instructions/react-development.instructions.md +315 -0
- package/.github/instructions/react-testing-optimization.instructions.md +373 -0
- package/.github/instructions/uiux.instructions.md +261 -0
- package/LICENSE +21 -0
- package/README.md +181 -0
- package/dist/analyzer/coverage-analyzer.d.ts +126 -0
- package/dist/analyzer/coverage-analyzer.d.ts.map +1 -0
- package/dist/analyzer/coverage-analyzer.js +633 -0
- package/dist/analyzer/coverage-analyzer.js.map +1 -0
- package/dist/analyzer/csharp-analyzer.d.ts +28 -0
- package/dist/analyzer/csharp-analyzer.d.ts.map +1 -0
- package/dist/analyzer/csharp-analyzer.js +437 -0
- package/dist/analyzer/csharp-analyzer.js.map +1 -0
- package/dist/analyzer/pattern-detector.d.ts +5 -0
- package/dist/analyzer/pattern-detector.d.ts.map +1 -0
- package/dist/analyzer/pattern-detector.js +74 -0
- package/dist/analyzer/pattern-detector.js.map +1 -0
- package/dist/analyzer/refactoring-advisor.d.ts +7 -0
- package/dist/analyzer/refactoring-advisor.d.ts.map +1 -0
- package/dist/analyzer/refactoring-advisor.js +280 -0
- package/dist/analyzer/refactoring-advisor.js.map +1 -0
- package/dist/analyzer/sonar-eslint-runner.d.ts +3 -0
- package/dist/analyzer/sonar-eslint-runner.d.ts.map +1 -0
- package/dist/analyzer/sonar-eslint-runner.js +136 -0
- package/dist/analyzer/sonar-eslint-runner.js.map +1 -0
- package/dist/analyzer/sonar-rule-map.d.ts +19 -0
- package/dist/analyzer/sonar-rule-map.d.ts.map +1 -0
- package/dist/analyzer/sonar-rule-map.js +67 -0
- package/dist/analyzer/sonar-rule-map.js.map +1 -0
- package/dist/analyzer/string-analyzer.d.ts +27 -0
- package/dist/analyzer/string-analyzer.d.ts.map +1 -0
- package/dist/analyzer/string-analyzer.js +274 -0
- package/dist/analyzer/string-analyzer.js.map +1 -0
- package/dist/analyzer/typescript-analyzer.d.ts +27 -0
- package/dist/analyzer/typescript-analyzer.d.ts.map +1 -0
- package/dist/analyzer/typescript-analyzer.js +437 -0
- package/dist/analyzer/typescript-analyzer.js.map +1 -0
- package/dist/analyzer/universal-analyzer.d.ts +10 -0
- package/dist/analyzer/universal-analyzer.d.ts.map +1 -0
- package/dist/analyzer/universal-analyzer.js +155 -0
- package/dist/analyzer/universal-analyzer.js.map +1 -0
- package/dist/cache/quality-cache.d.ts +119 -0
- package/dist/cache/quality-cache.d.ts.map +1 -0
- package/dist/cache/quality-cache.js +130 -0
- package/dist/cache/quality-cache.js.map +1 -0
- package/dist/cache/sqlite-cache.d.ts +43 -0
- package/dist/cache/sqlite-cache.d.ts.map +1 -0
- package/dist/cache/sqlite-cache.js +346 -0
- package/dist/cache/sqlite-cache.js.map +1 -0
- package/dist/cli/query-repl.d.ts +37 -0
- package/dist/cli/query-repl.d.ts.map +1 -0
- package/dist/cli/query-repl.js +298 -0
- package/dist/cli/query-repl.js.map +1 -0
- package/dist/cli/repl-algorithms.d.ts +49 -0
- package/dist/cli/repl-algorithms.d.ts.map +1 -0
- package/dist/cli/repl-algorithms.js +147 -0
- package/dist/cli/repl-algorithms.js.map +1 -0
- package/dist/cli/setup-core.d.ts +38 -0
- package/dist/cli/setup-core.d.ts.map +1 -0
- package/dist/cli/setup-core.js +427 -0
- package/dist/cli/setup-core.js.map +1 -0
- package/dist/cli/setup.d.ts +25 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +159 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli-entry.d.ts +19 -0
- package/dist/cli-entry.d.ts.map +1 -0
- package/dist/cli-entry.js +178 -0
- package/dist/cli-entry.js.map +1 -0
- package/dist/daemon/watch-mode.d.ts +41 -0
- package/dist/daemon/watch-mode.d.ts.map +1 -0
- package/dist/daemon/watch-mode.js +163 -0
- package/dist/daemon/watch-mode.js.map +1 -0
- package/dist/daemon.d.ts +24 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +357 -0
- package/dist/daemon.js.map +1 -0
- package/dist/github/app.d.ts +34 -0
- package/dist/github/app.d.ts.map +1 -0
- package/dist/github/app.js +261 -0
- package/dist/github/app.js.map +1 -0
- package/dist/github/commenter.d.ts +67 -0
- package/dist/github/commenter.d.ts.map +1 -0
- package/dist/github/commenter.js +155 -0
- package/dist/github/commenter.js.map +1 -0
- package/dist/graph/dependency-graph.d.ts +28 -0
- package/dist/graph/dependency-graph.d.ts.map +1 -0
- package/dist/graph/dependency-graph.js +198 -0
- package/dist/graph/dependency-graph.js.map +1 -0
- package/dist/graph/global-graph.d.ts +65 -0
- package/dist/graph/global-graph.d.ts.map +1 -0
- package/dist/graph/global-graph.js +153 -0
- package/dist/graph/global-graph.js.map +1 -0
- package/dist/graph/graph-algorithms.d.ts +90 -0
- package/dist/graph/graph-algorithms.d.ts.map +1 -0
- package/dist/graph/graph-algorithms.js +180 -0
- package/dist/graph/graph-algorithms.js.map +1 -0
- package/dist/graph/graph-export.d.ts +68 -0
- package/dist/graph/graph-export.d.ts.map +1 -0
- package/dist/graph/graph-export.js +264 -0
- package/dist/graph/graph-export.js.map +1 -0
- package/dist/graph/graph-report.d.ts +34 -0
- package/dist/graph/graph-report.d.ts.map +1 -0
- package/dist/graph/graph-report.js +136 -0
- package/dist/graph/graph-report.js.map +1 -0
- package/dist/graph/graph-summary.d.ts +68 -0
- package/dist/graph/graph-summary.d.ts.map +1 -0
- package/dist/graph/graph-summary.js +213 -0
- package/dist/graph/graph-summary.js.map +1 -0
- package/dist/graph/graphify-ignore.d.ts +32 -0
- package/dist/graph/graphify-ignore.d.ts.map +1 -0
- package/dist/graph/graphify-ignore.js +124 -0
- package/dist/graph/graphify-ignore.js.map +1 -0
- package/dist/graph/question-suggester.d.ts +30 -0
- package/dist/graph/question-suggester.d.ts.map +1 -0
- package/dist/graph/question-suggester.js +113 -0
- package/dist/graph/question-suggester.js.map +1 -0
- package/dist/graph/relationship-extractor.d.ts +40 -0
- package/dist/graph/relationship-extractor.d.ts.map +1 -0
- package/dist/graph/relationship-extractor.js +254 -0
- package/dist/graph/relationship-extractor.js.map +1 -0
- package/dist/graph/relationship-types.d.ts +24 -0
- package/dist/graph/relationship-types.d.ts.map +1 -0
- package/dist/graph/relationship-types.js +21 -0
- package/dist/graph/relationship-types.js.map +1 -0
- package/dist/graph/surprising-connections.d.ts +39 -0
- package/dist/graph/surprising-connections.d.ts.map +1 -0
- package/dist/graph/surprising-connections.js +127 -0
- package/dist/graph/surprising-connections.js.map +1 -0
- package/dist/hook-pre-tool-use.d.ts +14 -0
- package/dist/hook-pre-tool-use.d.ts.map +1 -0
- package/dist/hook-pre-tool-use.js +167 -0
- package/dist/hook-pre-tool-use.js.map +1 -0
- package/dist/hook-receiver.d.ts +29 -0
- package/dist/hook-receiver.d.ts.map +1 -0
- package/dist/hook-receiver.js +327 -0
- package/dist/hook-receiver.js.map +1 -0
- package/dist/hooks/git-hooks.d.ts +30 -0
- package/dist/hooks/git-hooks.d.ts.map +1 -0
- package/dist/hooks/git-hooks.js +179 -0
- package/dist/hooks/git-hooks.js.map +1 -0
- package/dist/mcp/cache-preload.d.ts +29 -0
- package/dist/mcp/cache-preload.d.ts.map +1 -0
- package/dist/mcp/cache-preload.js +103 -0
- package/dist/mcp/cache-preload.js.map +1 -0
- package/dist/mcp/handlers/analysis.d.ts +4 -0
- package/dist/mcp/handlers/analysis.d.ts.map +1 -0
- package/dist/mcp/handlers/analysis.js +196 -0
- package/dist/mcp/handlers/analysis.js.map +1 -0
- package/dist/mcp/handlers/context.d.ts +25 -0
- package/dist/mcp/handlers/context.d.ts.map +1 -0
- package/dist/mcp/handlers/context.js +382 -0
- package/dist/mcp/handlers/context.js.map +1 -0
- package/dist/mcp/handlers/graph-intelligence.d.ts +26 -0
- package/dist/mcp/handlers/graph-intelligence.d.ts.map +1 -0
- package/dist/mcp/handlers/graph-intelligence.js +371 -0
- package/dist/mcp/handlers/graph-intelligence.js.map +1 -0
- package/dist/mcp/handlers/graph-query.d.ts +25 -0
- package/dist/mcp/handlers/graph-query.d.ts.map +1 -0
- package/dist/mcp/handlers/graph-query.js +410 -0
- package/dist/mcp/handlers/graph-query.js.map +1 -0
- package/dist/mcp/handlers/graph.d.ts +5 -0
- package/dist/mcp/handlers/graph.d.ts.map +1 -0
- package/dist/mcp/handlers/graph.js +283 -0
- package/dist/mcp/handlers/graph.js.map +1 -0
- package/dist/mcp/handlers/impact-format.d.ts +9 -0
- package/dist/mcp/handlers/impact-format.d.ts.map +1 -0
- package/dist/mcp/handlers/impact-format.js +189 -0
- package/dist/mcp/handlers/impact-format.js.map +1 -0
- package/dist/mcp/handlers/impact.d.ts +4 -0
- package/dist/mcp/handlers/impact.d.ts.map +1 -0
- package/dist/mcp/handlers/impact.js +139 -0
- package/dist/mcp/handlers/impact.js.map +1 -0
- package/dist/mcp/handlers/improvement.d.ts +4 -0
- package/dist/mcp/handlers/improvement.d.ts.map +1 -0
- package/dist/mcp/handlers/improvement.js +136 -0
- package/dist/mcp/handlers/improvement.js.map +1 -0
- package/dist/mcp/handlers/index.d.ts +14 -0
- package/dist/mcp/handlers/index.d.ts.map +1 -0
- package/dist/mcp/handlers/index.js +36 -0
- package/dist/mcp/handlers/index.js.map +1 -0
- package/dist/mcp/handlers/platform-installer.d.ts +10 -0
- package/dist/mcp/handlers/platform-installer.d.ts.map +1 -0
- package/dist/mcp/handlers/platform-installer.js +168 -0
- package/dist/mcp/handlers/platform-installer.js.map +1 -0
- package/dist/mcp/handlers/pr-review.d.ts +33 -0
- package/dist/mcp/handlers/pr-review.d.ts.map +1 -0
- package/dist/mcp/handlers/pr-review.js +170 -0
- package/dist/mcp/handlers/pr-review.js.map +1 -0
- package/dist/mcp/handlers/shared.d.ts +20 -0
- package/dist/mcp/handlers/shared.d.ts.map +1 -0
- package/dist/mcp/handlers/shared.js +27 -0
- package/dist/mcp/handlers/shared.js.map +1 -0
- package/dist/mcp/handlers/types.d.ts +46 -0
- package/dist/mcp/handlers/types.d.ts.map +1 -0
- package/dist/mcp/handlers/types.js +3 -0
- package/dist/mcp/handlers/types.js.map +1 -0
- package/dist/mcp/helpers.d.ts +36 -0
- package/dist/mcp/helpers.d.ts.map +1 -0
- package/dist/mcp/helpers.js +199 -0
- package/dist/mcp/helpers.js.map +1 -0
- package/dist/mcp/installer.d.ts +22 -0
- package/dist/mcp/installer.d.ts.map +1 -0
- package/dist/mcp/installer.js +341 -0
- package/dist/mcp/installer.js.map +1 -0
- package/dist/mcp/server.d.ts +111 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +216 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/token-tracker.d.ts +47 -0
- package/dist/mcp/token-tracker.d.ts.map +1 -0
- package/dist/mcp/token-tracker.js +93 -0
- package/dist/mcp/token-tracker.js.map +1 -0
- package/dist/quality-loop/file-lock.d.ts +12 -0
- package/dist/quality-loop/file-lock.d.ts.map +1 -0
- package/dist/quality-loop/file-lock.js +38 -0
- package/dist/quality-loop/file-lock.js.map +1 -0
- package/dist/quality-loop/fix-worker.d.ts +44 -0
- package/dist/quality-loop/fix-worker.d.ts.map +1 -0
- package/dist/quality-loop/fix-worker.js +414 -0
- package/dist/quality-loop/fix-worker.js.map +1 -0
- package/dist/quality-loop/orchestrator.d.ts +137 -0
- package/dist/quality-loop/orchestrator.d.ts.map +1 -0
- package/dist/quality-loop/orchestrator.js +894 -0
- package/dist/quality-loop/orchestrator.js.map +1 -0
- package/dist/quality-loop/queue-manager.d.ts +45 -0
- package/dist/quality-loop/queue-manager.d.ts.map +1 -0
- package/dist/quality-loop/queue-manager.js +173 -0
- package/dist/quality-loop/queue-manager.js.map +1 -0
- package/dist/rating/rating-calculator.d.ts +15 -0
- package/dist/rating/rating-calculator.d.ts.map +1 -0
- package/dist/rating/rating-calculator.js +136 -0
- package/dist/rating/rating-calculator.js.map +1 -0
- package/dist/types/agent.d.ts +49 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/agent.js +7 -0
- package/dist/types/agent.js.map +1 -0
- package/dist/types.d.ts +156 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/util/fix-text.d.ts +7 -0
- package/dist/util/fix-text.d.ts.map +1 -0
- package/dist/util/fix-text.js +13 -0
- package/dist/util/fix-text.js.map +1 -0
- package/dist/viz/graph-viz.d.ts +40 -0
- package/dist/viz/graph-viz.d.ts.map +1 -0
- package/dist/viz/graph-viz.js +332 -0
- package/dist/viz/graph-viz.js.map +1 -0
- package/dist/viz/viz-helpers.d.ts +13 -0
- package/dist/viz/viz-helpers.d.ts.map +1 -0
- package/dist/viz/viz-helpers.js +134 -0
- package/dist/viz/viz-helpers.js.map +1 -0
- package/dist/viz/viz-routes.d.ts +28 -0
- package/dist/viz/viz-routes.d.ts.map +1 -0
- package/dist/viz/viz-routes.js +333 -0
- package/dist/viz/viz-routes.js.map +1 -0
- package/dist/viz/viz-scanner.d.ts +20 -0
- package/dist/viz/viz-scanner.d.ts.map +1 -0
- package/dist/viz/viz-scanner.js +241 -0
- package/dist/viz/viz-scanner.js.map +1 -0
- package/dist/viz/viz-server.d.ts +38 -0
- package/dist/viz/viz-server.d.ts.map +1 -0
- package/dist/viz/viz-server.js +240 -0
- package/dist/viz/viz-server.js.map +1 -0
- package/package.json +89 -0
- package/scripts/postinstall.js +28 -0
- package/scripts/setup.sh +113 -0
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* gate-keeper daemon
|
|
4
|
+
*
|
|
5
|
+
* Listens on port 5379 for file paths from the hook-receiver, runs analysis,
|
|
6
|
+
* updates the SQLite cache, and broadcasts results to the dashboard (port 5378).
|
|
7
|
+
*
|
|
8
|
+
* Start with: node dist/daemon.js
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
44
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.DEFAULT_CONFIG = exports.CONFIG_FILE = exports.PID_FILE = exports.GK_DIR = exports.IPC_PORT = void 0;
|
|
48
|
+
exports.findGitRoot = findGitRoot;
|
|
49
|
+
exports.main = main;
|
|
50
|
+
const express_1 = __importDefault(require("express"));
|
|
51
|
+
const fs = __importStar(require("fs"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const crypto = __importStar(require("crypto"));
|
|
54
|
+
const child_process_1 = require("child_process");
|
|
55
|
+
const universal_analyzer_1 = require("./analyzer/universal-analyzer");
|
|
56
|
+
const sqlite_cache_1 = require("./cache/sqlite-cache");
|
|
57
|
+
const viz_server_1 = require("./viz/viz-server");
|
|
58
|
+
const watch_mode_1 = require("./daemon/watch-mode");
|
|
59
|
+
exports.IPC_PORT = 5379;
|
|
60
|
+
exports.GK_DIR = path.join(process.env.HOME ?? '/tmp', '.gate-keeper');
|
|
61
|
+
exports.PID_FILE = path.join(exports.GK_DIR, 'daemon.pid');
|
|
62
|
+
exports.CONFIG_FILE = path.join(exports.GK_DIR, 'config.json');
|
|
63
|
+
exports.DEFAULT_CONFIG = {
|
|
64
|
+
minRating: 6.5,
|
|
65
|
+
scanExcludePatterns: {
|
|
66
|
+
// Any path containing "test" (case-insensitive): *.test.ts, *.test.tsx,
|
|
67
|
+
// *Tests.cs, *Test.cs, __tests__/, Tests/, etc.
|
|
68
|
+
global: [
|
|
69
|
+
'**test**',
|
|
70
|
+
// Config files (React / TypeScript / JavaScript)
|
|
71
|
+
'jest.config.*',
|
|
72
|
+
'jest.setup.*',
|
|
73
|
+
'vite.config.*',
|
|
74
|
+
'postcss.config.*',
|
|
75
|
+
'tailwind.config.*',
|
|
76
|
+
'tsconfig*.json',
|
|
77
|
+
'babel.config.*',
|
|
78
|
+
'webpack.config.*',
|
|
79
|
+
'rollup.config.*',
|
|
80
|
+
'next.config.*',
|
|
81
|
+
'eslint.config.*',
|
|
82
|
+
'.eslintrc*',
|
|
83
|
+
'.prettierrc*',
|
|
84
|
+
'.editorconfig',
|
|
85
|
+
// Config files (.NET / C#)
|
|
86
|
+
'*.csproj',
|
|
87
|
+
'appsettings*.json',
|
|
88
|
+
'launchSettings.json',
|
|
89
|
+
'NuGet.config',
|
|
90
|
+
'global.json',
|
|
91
|
+
'Directory.Build.*',
|
|
92
|
+
],
|
|
93
|
+
csharp: [
|
|
94
|
+
'**/Migrations/*.cs',
|
|
95
|
+
'**/Migrations/**/*.cs',
|
|
96
|
+
'*.Designer.cs',
|
|
97
|
+
'*.g.cs',
|
|
98
|
+
'*.generated.cs',
|
|
99
|
+
'**/AssemblyInfo.cs',
|
|
100
|
+
'**/GlobalUsings.cs',
|
|
101
|
+
],
|
|
102
|
+
typescript: [
|
|
103
|
+
'*.d.ts',
|
|
104
|
+
'*.min.js',
|
|
105
|
+
'*.bundle.js',
|
|
106
|
+
'**/generated/**',
|
|
107
|
+
],
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
function loadConfig() {
|
|
111
|
+
try {
|
|
112
|
+
if (fs.existsSync(exports.CONFIG_FILE)) {
|
|
113
|
+
const raw = fs.readFileSync(exports.CONFIG_FILE, 'utf8');
|
|
114
|
+
const user = JSON.parse(raw);
|
|
115
|
+
// Deep-merge scanExcludePatterns: user arrays replace defaults per-key
|
|
116
|
+
const merged = { ...exports.DEFAULT_CONFIG, ...user };
|
|
117
|
+
if (user.scanExcludePatterns || exports.DEFAULT_CONFIG.scanExcludePatterns) {
|
|
118
|
+
merged.scanExcludePatterns = {
|
|
119
|
+
global: user.scanExcludePatterns?.global ?? exports.DEFAULT_CONFIG.scanExcludePatterns?.global ?? [],
|
|
120
|
+
csharp: user.scanExcludePatterns?.csharp ?? exports.DEFAULT_CONFIG.scanExcludePatterns?.csharp ?? [],
|
|
121
|
+
typescript: user.scanExcludePatterns?.typescript ?? exports.DEFAULT_CONFIG.scanExcludePatterns?.typescript ?? [],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
return merged;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch { }
|
|
128
|
+
return { ...exports.DEFAULT_CONFIG };
|
|
129
|
+
}
|
|
130
|
+
function ensureConfigFile() {
|
|
131
|
+
if (!fs.existsSync(exports.CONFIG_FILE)) {
|
|
132
|
+
fs.writeFileSync(exports.CONFIG_FILE, JSON.stringify(exports.DEFAULT_CONFIG, null, 2));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function findGitRoot(dir) {
|
|
136
|
+
const result = (0, child_process_1.spawnSync)('git', ['rev-parse', '--show-toplevel'], {
|
|
137
|
+
cwd: dir, encoding: 'utf8', timeout: 3000
|
|
138
|
+
});
|
|
139
|
+
return (result.status === 0 && result.stdout.trim()) ? result.stdout.trim() : dir;
|
|
140
|
+
}
|
|
141
|
+
// ── LCOV coverage watcher ──────────────────────────────────────────────────
|
|
142
|
+
// Tracks every lcov path we are already polling to prevent duplicate watchers.
|
|
143
|
+
const watchedLcovPaths = new Set();
|
|
144
|
+
// Per-repo debounce timers so rapid LCOV writes don't flood the scan pipeline.
|
|
145
|
+
const lcovDebounceTimers = new Map();
|
|
146
|
+
// Mirrors CoverageAnalyzer.findLcovFile() so the watcher covers the same search space.
|
|
147
|
+
function coverageLcovCandidates(repoRoot) {
|
|
148
|
+
return [
|
|
149
|
+
path.join(repoRoot, 'coverage', 'lcov.info'),
|
|
150
|
+
path.join(repoRoot, 'coverage', 'lcov-report', 'lcov.info'),
|
|
151
|
+
path.join(repoRoot, 'lcov.info'),
|
|
152
|
+
path.join(repoRoot, '.coverage', 'lcov.info'),
|
|
153
|
+
];
|
|
154
|
+
}
|
|
155
|
+
// Uses fs.watchFile (stat-polling) instead of fs.watch (inotify) because inotify
|
|
156
|
+
// silently drops events on WSL DrvFs/NFS mounts, while polling works everywhere.
|
|
157
|
+
function startLcovWatcher(repoRoot, vizServer) {
|
|
158
|
+
for (const lcovPath of coverageLcovCandidates(repoRoot)) {
|
|
159
|
+
if (watchedLcovPaths.has(lcovPath))
|
|
160
|
+
continue;
|
|
161
|
+
watchedLcovPaths.add(lcovPath);
|
|
162
|
+
fs.watchFile(lcovPath, { persistent: false, interval: 5_000 }, (curr, prev) => {
|
|
163
|
+
if (curr.mtimeMs === prev.mtimeMs)
|
|
164
|
+
return;
|
|
165
|
+
const existing = lcovDebounceTimers.get(repoRoot);
|
|
166
|
+
if (existing)
|
|
167
|
+
clearTimeout(existing);
|
|
168
|
+
lcovDebounceTimers.set(repoRoot, setTimeout(() => {
|
|
169
|
+
lcovDebounceTimers.delete(repoRoot);
|
|
170
|
+
console.error(`[gate-keeper] Coverage changed for ${path.basename(repoRoot)} — re-analyzing...`);
|
|
171
|
+
vizServer.scanRepo(repoRoot, true).catch(err => {
|
|
172
|
+
console.error(`[gate-keeper] Coverage re-analysis error: ${err instanceof Error ? err.message : String(err)}`);
|
|
173
|
+
});
|
|
174
|
+
}, 2_000));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async function main() {
|
|
179
|
+
const args = process.argv.slice(2);
|
|
180
|
+
const noScan = args.includes('--no-scan');
|
|
181
|
+
const watchMode = args.includes('--watch');
|
|
182
|
+
ensurePidFile();
|
|
183
|
+
ensureConfigFile();
|
|
184
|
+
const config = loadConfig();
|
|
185
|
+
const workDir = process.cwd();
|
|
186
|
+
const repoRoot = findGitRoot(workDir);
|
|
187
|
+
const cache = new sqlite_cache_1.SqliteCache();
|
|
188
|
+
const analyzer = new universal_analyzer_1.UniversalAnalyzer();
|
|
189
|
+
const vizServer = new viz_server_1.VizServer(cache, analyzer, workDir, repoRoot, config);
|
|
190
|
+
await vizServer.start();
|
|
191
|
+
// Start LCOV watchers for all repos already in the cache so that running
|
|
192
|
+
// `npm test --coverage` automatically refreshes dashboard ratings.
|
|
193
|
+
for (const { path: r } of cache.getAllRepositories()) {
|
|
194
|
+
startLcovWatcher(r, vizServer);
|
|
195
|
+
}
|
|
196
|
+
if (!noScan) {
|
|
197
|
+
// Initial workspace scan — runs in the background, non-blocking
|
|
198
|
+
vizServer.scan(false).catch(err => {
|
|
199
|
+
console.error('[gate-keeper] Initial scan failed:', err);
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
console.error('[gate-keeper] Started with --no-scan, skipping initial scan');
|
|
204
|
+
}
|
|
205
|
+
// Graph watch mode — polls source files for mtime changes and re-analyzes
|
|
206
|
+
if (watchMode) {
|
|
207
|
+
const watcher = new watch_mode_1.WatchMode();
|
|
208
|
+
const POLL_MS = parseInt(process.env['GK_WATCH_INTERVAL'] ?? '5000', 10);
|
|
209
|
+
watcher.start(repoRoot, (changedFiles) => {
|
|
210
|
+
console.error(`[gate-keeper] Watch: ${changedFiles.length} changed file(s) — re-analyzing`);
|
|
211
|
+
for (const fp of changedFiles) {
|
|
212
|
+
// Same logic as the /analyze IPC endpoint — inline it for watch mode
|
|
213
|
+
(async () => {
|
|
214
|
+
try {
|
|
215
|
+
const analysis = await analyzer.analyze(fp);
|
|
216
|
+
if (!analysis)
|
|
217
|
+
return;
|
|
218
|
+
analysis.repoRoot = repoRoot;
|
|
219
|
+
cache.save(analysis);
|
|
220
|
+
vizServer.pushAnalysis(analysis);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
console.error(`[gate-keeper] Watch re-analysis error: ${err instanceof Error ? err.message : String(err)}`);
|
|
224
|
+
}
|
|
225
|
+
})();
|
|
226
|
+
}
|
|
227
|
+
}, POLL_MS);
|
|
228
|
+
console.error(`[gate-keeper] Watch mode active (polling every ${POLL_MS}ms) for ${repoRoot}`);
|
|
229
|
+
process.on('exit', () => watcher.stop());
|
|
230
|
+
}
|
|
231
|
+
// IPC HTTP server — only binds to localhost
|
|
232
|
+
const ipc = (0, express_1.default)();
|
|
233
|
+
ipc.use(express_1.default.json());
|
|
234
|
+
ipc.use((_req, res, next) => {
|
|
235
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
236
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
|
|
237
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
238
|
+
if (_req.method === 'OPTIONS') {
|
|
239
|
+
res.sendStatus(204);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
next();
|
|
243
|
+
});
|
|
244
|
+
ipc.get('/health', (_req, res) => {
|
|
245
|
+
res.json({ ok: true, pid: process.pid });
|
|
246
|
+
});
|
|
247
|
+
// Register a new repository from session_create hook
|
|
248
|
+
ipc.post('/repo-register', async (req, res) => {
|
|
249
|
+
const { action, repo } = req.body;
|
|
250
|
+
if (action !== 'register_repo' || !repo?.path) {
|
|
251
|
+
res.status(400).json({ error: 'Invalid request' });
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
const repoId = crypto.createHash('md5').update(repo.path).digest('hex');
|
|
256
|
+
const isNew = !cache.getRepository(repoId);
|
|
257
|
+
const metadata = {
|
|
258
|
+
id: repoId,
|
|
259
|
+
path: repo.path,
|
|
260
|
+
name: repo.name || path.basename(repo.path) || repo.path,
|
|
261
|
+
sessionId: repo.sessionId,
|
|
262
|
+
sessionType: repo.sessionType || 'unknown',
|
|
263
|
+
createdAt: repo.createdAt || Date.now(),
|
|
264
|
+
isActive: true
|
|
265
|
+
};
|
|
266
|
+
cache.saveRepository(metadata);
|
|
267
|
+
vizServer.broadcastRepoCreated(metadata);
|
|
268
|
+
startLcovWatcher(metadata.path, vizServer);
|
|
269
|
+
console.error(`[gate-keeper] Repository ${isNew ? 'registered' : 'updated'}: ${metadata.name} (${metadata.id})`);
|
|
270
|
+
res.json({ ok: true, repoId, repo: metadata, isNew });
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
274
|
+
console.error(`[gate-keeper] Repo registration error: ${msg}`);
|
|
275
|
+
res.status(500).json({ error: msg });
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
// Synchronously analyzes the file and returns the result so the hook-receiver
|
|
279
|
+
// can gate on the rating in the same PostToolUse event.
|
|
280
|
+
ipc.post('/analyze', async (req, res) => {
|
|
281
|
+
const { filePath, repoRoot: reqRepo } = req.body;
|
|
282
|
+
if (!filePath || !fs.existsSync(filePath) || !analyzer.isSupportedFile(filePath)) {
|
|
283
|
+
res.json({ analysis: null, minRating: loadConfig().minRating });
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
const analysis = await analyzer.analyze(filePath);
|
|
288
|
+
if (!analysis) {
|
|
289
|
+
res.json({ analysis: null, minRating: loadConfig().minRating });
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
analysis.repoRoot = reqRepo || repoRoot;
|
|
293
|
+
cache.save(analysis);
|
|
294
|
+
vizServer.pushAnalysis(analysis);
|
|
295
|
+
const liveConfig = loadConfig();
|
|
296
|
+
console.error(`[gate-keeper] ${path.basename(filePath)} — rating: ${analysis.rating}/10, violations: ${analysis.violations.length}`);
|
|
297
|
+
res.json({ analysis, minRating: liveConfig.minRating });
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
301
|
+
console.error(`[gate-keeper] Analysis error for ${filePath}: ${msg}`);
|
|
302
|
+
res.json({ analysis: null, minRating: loadConfig().minRating });
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
// Get list of repositories
|
|
306
|
+
ipc.get('/repos', (_req, res) => {
|
|
307
|
+
const repos = cache.getAllRepositories(true);
|
|
308
|
+
res.json({ repos });
|
|
309
|
+
});
|
|
310
|
+
// Manually trigger a full re-analysis of all files in a repo so that coverage
|
|
311
|
+
// data changes (e.g. after running `npm test --coverage`) are reflected
|
|
312
|
+
// immediately without waiting for the next file-write event.
|
|
313
|
+
ipc.post('/reanalyze-coverage', (req, res) => {
|
|
314
|
+
const { repoRoot: reqRepo } = req.body;
|
|
315
|
+
const target = reqRepo || repoRoot;
|
|
316
|
+
res.json({ ok: true, message: `Re-analysis started for ${target}` });
|
|
317
|
+
vizServer.scanRepo(target, true).catch(err => {
|
|
318
|
+
console.error(`[gate-keeper] /reanalyze-coverage error: ${err instanceof Error ? err.message : String(err)}`);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
ipc.listen(exports.IPC_PORT, '127.0.0.1', () => {
|
|
322
|
+
console.error(`[gate-keeper] IPC ready on 127.0.0.1:${exports.IPC_PORT}`);
|
|
323
|
+
console.error(`[gate-keeper] Min rating: ${config.minRating} (edit ${exports.CONFIG_FILE} to change)`);
|
|
324
|
+
});
|
|
325
|
+
// Only register signal handlers once per process
|
|
326
|
+
if (process._gateKeeperSignalsRegistered !== true) {
|
|
327
|
+
process.on('SIGTERM', () => shutdown(cache));
|
|
328
|
+
process.on('SIGINT', () => shutdown(cache));
|
|
329
|
+
process._gateKeeperSignalsRegistered = true;
|
|
330
|
+
}
|
|
331
|
+
console.error(`[gate-keeper] Daemon started (PID ${process.pid})`);
|
|
332
|
+
}
|
|
333
|
+
function ensurePidFile() {
|
|
334
|
+
const dir = path.dirname(exports.PID_FILE);
|
|
335
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
336
|
+
fs.writeFileSync(exports.PID_FILE, String(process.pid));
|
|
337
|
+
}
|
|
338
|
+
function shutdown(cache) {
|
|
339
|
+
try {
|
|
340
|
+
fs.unlinkSync(exports.PID_FILE);
|
|
341
|
+
}
|
|
342
|
+
catch { }
|
|
343
|
+
for (const p of watchedLcovPaths)
|
|
344
|
+
fs.unwatchFile(p);
|
|
345
|
+
for (const t of lcovDebounceTimers.values())
|
|
346
|
+
clearTimeout(t);
|
|
347
|
+
cache.close();
|
|
348
|
+
process.exit(0);
|
|
349
|
+
}
|
|
350
|
+
// Only run main() if this is the entry point (not in tests)
|
|
351
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
352
|
+
main().catch(err => {
|
|
353
|
+
console.error('[gate-keeper] Fatal:', err);
|
|
354
|
+
process.exit(1);
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub App webhook handler.
|
|
3
|
+
*
|
|
4
|
+
* Listens for push and pull_request webhooks from GitHub, runs graph analysis
|
|
5
|
+
* on changed files, and logs impact summaries to stderr.
|
|
6
|
+
*
|
|
7
|
+
* Configure via:
|
|
8
|
+
* EXPOSE_GITHUB_APP=true GK_WEBHOOK_SECRET=<secret> GK_GITHUB_TOKEN=<token> npx tsx src/github/app.ts
|
|
9
|
+
*
|
|
10
|
+
* GK_GITHUB_TOKEN is required for pull_request analysis (used to fetch changed files from the GitHub API).
|
|
11
|
+
*/
|
|
12
|
+
import { GraphNodeSummary } from './commenter';
|
|
13
|
+
export declare function verifySignature(payload: string, signature: string | undefined): boolean;
|
|
14
|
+
export declare function getRepoFullName(payload: Record<string, unknown>): string | null;
|
|
15
|
+
type GraphNode = {
|
|
16
|
+
id: string;
|
|
17
|
+
label: string;
|
|
18
|
+
rating: number;
|
|
19
|
+
violations: Array<{
|
|
20
|
+
severity: string;
|
|
21
|
+
}>;
|
|
22
|
+
};
|
|
23
|
+
type GraphEdge = {
|
|
24
|
+
source: string;
|
|
25
|
+
target: string;
|
|
26
|
+
};
|
|
27
|
+
type GraphData = {
|
|
28
|
+
nodes: GraphNode[];
|
|
29
|
+
edges: GraphEdge[];
|
|
30
|
+
};
|
|
31
|
+
export declare function buildPushSummaries(allFiles: Set<string>, graph: GraphData): GraphNodeSummary[];
|
|
32
|
+
export declare function startGitHubApp(): void;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=app.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../src/github/app.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,OAAO,EAA+B,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAsB5E,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CASvF;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAG/E;AAED,KAAK,SAAS,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,KAAK,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC;AACxG,KAAK,SAAS,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACpD,KAAK,SAAS,GAAG;IAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,CAAC;AAE5D,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,gBAAgB,EAAE,CAiB9F;AAmHD,wBAAgB,cAAc,IAAI,IAAI,CAiCrC"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* GitHub App webhook handler.
|
|
4
|
+
*
|
|
5
|
+
* Listens for push and pull_request webhooks from GitHub, runs graph analysis
|
|
6
|
+
* on changed files, and logs impact summaries to stderr.
|
|
7
|
+
*
|
|
8
|
+
* Configure via:
|
|
9
|
+
* EXPOSE_GITHUB_APP=true GK_WEBHOOK_SECRET=<secret> GK_GITHUB_TOKEN=<token> npx tsx src/github/app.ts
|
|
10
|
+
*
|
|
11
|
+
* GK_GITHUB_TOKEN is required for pull_request analysis (used to fetch changed files from the GitHub API).
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.verifySignature = verifySignature;
|
|
51
|
+
exports.getRepoFullName = getRepoFullName;
|
|
52
|
+
exports.buildPushSummaries = buildPushSummaries;
|
|
53
|
+
exports.startGitHubApp = startGitHubApp;
|
|
54
|
+
const express_1 = __importDefault(require("express"));
|
|
55
|
+
const crypto = __importStar(require("crypto"));
|
|
56
|
+
const http = __importStar(require("http"));
|
|
57
|
+
const https = __importStar(require("https"));
|
|
58
|
+
const commenter_1 = require("./commenter");
|
|
59
|
+
const PORT = parseInt(process.env['GK_GH_PORT'] ?? '5432', 10);
|
|
60
|
+
const WEBHOOK_SECRET = process.env['GK_WEBHOOK_SECRET'] ?? '';
|
|
61
|
+
const DAEMON_PORT = 5378;
|
|
62
|
+
// ── Helpers ────────────────────────────────────────────────
|
|
63
|
+
function fetchDaemonApi(urlPath) {
|
|
64
|
+
return new Promise((resolve) => {
|
|
65
|
+
const req = http.get(`http://127.0.0.1:${DAEMON_PORT}${urlPath}`, { timeout: 5000 }, (res) => {
|
|
66
|
+
let body = '';
|
|
67
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
68
|
+
res.on('end', () => {
|
|
69
|
+
try {
|
|
70
|
+
resolve(JSON.parse(body));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
resolve(null);
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
req.on('error', () => resolve(null));
|
|
78
|
+
req.on('timeout', () => { req.destroy(); resolve(null); });
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
function verifySignature(payload, signature) {
|
|
82
|
+
if (!WEBHOOK_SECRET)
|
|
83
|
+
return true;
|
|
84
|
+
if (!signature)
|
|
85
|
+
return false;
|
|
86
|
+
const sig = `sha256=${crypto.createHmac('sha256', WEBHOOK_SECRET).update(payload).digest('hex')}`;
|
|
87
|
+
try {
|
|
88
|
+
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(signature));
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function getRepoFullName(payload) {
|
|
95
|
+
const repo = payload['repository'];
|
|
96
|
+
return repo ? `${repo['owner']}/${repo['name']}` : null;
|
|
97
|
+
}
|
|
98
|
+
function buildPushSummaries(allFiles, graph) {
|
|
99
|
+
const summaries = [];
|
|
100
|
+
for (const file of allFiles) {
|
|
101
|
+
const node = graph.nodes.find(n => n.id.endsWith(file));
|
|
102
|
+
if (!node)
|
|
103
|
+
continue;
|
|
104
|
+
const dependents = graph.edges.filter(e => e.target === node.id);
|
|
105
|
+
const fragile = graph.nodes.filter(n => dependents.some(d => d.source === n.id) && n.rating < 6);
|
|
106
|
+
summaries.push({
|
|
107
|
+
path: file,
|
|
108
|
+
rating: node.rating,
|
|
109
|
+
directDependents: dependents.length,
|
|
110
|
+
fragileDependents: fragile.length,
|
|
111
|
+
errors: node.violations.filter(v => v.severity === 'error').length,
|
|
112
|
+
warnings: node.violations.filter(v => v.severity === 'warning').length,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
return summaries;
|
|
116
|
+
}
|
|
117
|
+
// ── Webhook handlers ──────────────────────────────────────
|
|
118
|
+
async function handlePush(payload) {
|
|
119
|
+
const repoName = getRepoFullName(payload);
|
|
120
|
+
const commits = (payload['commits'] ?? []);
|
|
121
|
+
const allFiles = new Set();
|
|
122
|
+
for (const c of commits) {
|
|
123
|
+
for (const f of c.modified ?? [])
|
|
124
|
+
allFiles.add(f);
|
|
125
|
+
for (const f of c.added ?? [])
|
|
126
|
+
allFiles.add(f);
|
|
127
|
+
}
|
|
128
|
+
if (allFiles.size === 0 || !repoName)
|
|
129
|
+
return;
|
|
130
|
+
const graphRaw = await fetchDaemonApi(`/api/graph`);
|
|
131
|
+
if (!graphRaw)
|
|
132
|
+
return;
|
|
133
|
+
const summaries = buildPushSummaries(allFiles, graphRaw);
|
|
134
|
+
if (summaries.length === 0)
|
|
135
|
+
return;
|
|
136
|
+
const ref = payload['ref'] ?? 'unknown';
|
|
137
|
+
const pr = {
|
|
138
|
+
number: 0,
|
|
139
|
+
title: `Push to ${ref}`,
|
|
140
|
+
author: payload['pusher']?.['name'] ?? 'unknown',
|
|
141
|
+
baseBranch: ref.replace('refs/heads/', ''),
|
|
142
|
+
headBranch: ref.replace('refs/heads/', ''),
|
|
143
|
+
};
|
|
144
|
+
const comment = (0, commenter_1.formatPRComment)(pr, summaries, repoName, graphRaw.nodes.length);
|
|
145
|
+
process.stderr.write(`[gate-keeper-github] Push analysis: ${summaries.length} files changed, verdict=${comment.verdict}\n`);
|
|
146
|
+
for (const s of summaries) {
|
|
147
|
+
process.stderr.write(`[gate-keeper-github] ${s.path}: ${s.rating}/10, ${s.fragileDependents} fragile\n`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
async function handlePullRequest(payload) {
|
|
151
|
+
const action = payload['action'];
|
|
152
|
+
if (action !== 'opened' && action !== 'synchronize')
|
|
153
|
+
return;
|
|
154
|
+
const repoName = getRepoFullName(payload);
|
|
155
|
+
const pr = payload['pull_request'];
|
|
156
|
+
if (!repoName || !pr)
|
|
157
|
+
return;
|
|
158
|
+
const token = process.env['GK_GITHUB_TOKEN'];
|
|
159
|
+
if (!token) {
|
|
160
|
+
process.stderr.write(`[gate-keeper-github] PR #${payload['number']} ${action} — set GK_GITHUB_TOKEN to enable PR file analysis\n`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
const [owner, repo] = repoName.split('/');
|
|
164
|
+
if (!owner || !repo)
|
|
165
|
+
return;
|
|
166
|
+
const prFiles = await fetchPRFiles(owner, repo, payload['number'], token);
|
|
167
|
+
if (prFiles.length === 0)
|
|
168
|
+
return;
|
|
169
|
+
const allFiles = new Set(prFiles.map(f => f.filename));
|
|
170
|
+
const graphRaw = await fetchDaemonApi('/api/graph');
|
|
171
|
+
if (!graphRaw)
|
|
172
|
+
return;
|
|
173
|
+
const summaries = buildPushSummaries(allFiles, graphRaw);
|
|
174
|
+
if (summaries.length === 0)
|
|
175
|
+
return;
|
|
176
|
+
const prMeta = {
|
|
177
|
+
number: payload['number'],
|
|
178
|
+
title: pr['title'] ?? 'Untitled PR',
|
|
179
|
+
author: (pr['user']?.['login']) ?? 'unknown',
|
|
180
|
+
baseBranch: (pr['base']?.['ref']) ?? 'main',
|
|
181
|
+
headBranch: (pr['head']?.['ref']) ?? 'feature',
|
|
182
|
+
};
|
|
183
|
+
const comment = (0, commenter_1.formatPRComment)(prMeta, summaries, repoName, graphRaw.nodes.length);
|
|
184
|
+
process.stderr.write(`[gate-keeper-github] PR #${prMeta.number} (${action}): ${summaries.length} files analyzed, verdict=${comment.verdict}\n`);
|
|
185
|
+
for (const s of summaries) {
|
|
186
|
+
process.stderr.write(`[gate-keeper-github] ${s.path}: ${s.rating}/10, ${s.fragileDependents} fragile\n`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function fetchPRFiles(owner, repo, prNumber, token) {
|
|
190
|
+
return new Promise((resolve) => {
|
|
191
|
+
const req = https.get({
|
|
192
|
+
hostname: 'api.github.com',
|
|
193
|
+
path: `/repos/${owner}/${repo}/pulls/${prNumber}/files`,
|
|
194
|
+
headers: {
|
|
195
|
+
Authorization: `Bearer ${token}`,
|
|
196
|
+
'User-Agent': 'gate-keeper',
|
|
197
|
+
Accept: 'application/vnd.github+json',
|
|
198
|
+
},
|
|
199
|
+
timeout: 5000,
|
|
200
|
+
}, (res) => {
|
|
201
|
+
let body = '';
|
|
202
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
203
|
+
res.on('end', () => {
|
|
204
|
+
try {
|
|
205
|
+
resolve(JSON.parse(body));
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
resolve([]);
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
req.on('error', () => resolve([]));
|
|
213
|
+
req.on('timeout', () => { req.destroy(); resolve([]); });
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
async function dispatchWebhookEvent(event, payload) {
|
|
217
|
+
if (event === 'push') {
|
|
218
|
+
await handlePush(payload);
|
|
219
|
+
}
|
|
220
|
+
else if (event === 'pull_request') {
|
|
221
|
+
await handlePullRequest(payload);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// ── Server ─────────────────────────────────────────────────
|
|
225
|
+
function startGitHubApp() {
|
|
226
|
+
const app = (0, express_1.default)();
|
|
227
|
+
app.post('/webhook', express_1.default.json({
|
|
228
|
+
verify: (req, _res, buf) => {
|
|
229
|
+
req['rawBody'] = buf;
|
|
230
|
+
},
|
|
231
|
+
}), async (req, res) => {
|
|
232
|
+
const rawBody = req['rawBody'];
|
|
233
|
+
const signature = req.headers['x-hub-signature-256'];
|
|
234
|
+
const event = req.headers['x-github-event'];
|
|
235
|
+
if (!verifySignature(rawBody?.toString() ?? '', signature)) {
|
|
236
|
+
res.status(401).json({ error: 'Invalid signature' });
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
res.status(202).json({ ok: true });
|
|
240
|
+
try {
|
|
241
|
+
await dispatchWebhookEvent(event, req.body);
|
|
242
|
+
}
|
|
243
|
+
catch (err) {
|
|
244
|
+
process.stderr.write(`[gate-keeper-github] Webhook error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
app.get('/health', (_req, res) => {
|
|
248
|
+
res.json({ ok: true, app: 'gate-keeper-github' });
|
|
249
|
+
});
|
|
250
|
+
app.listen(PORT, () => {
|
|
251
|
+
process.stderr.write(`[gate-keeper-github] Webhook server on :${PORT} (secret: ${WEBHOOK_SECRET ? 'set' : 'NOT SET'})\n`);
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
if (require.main === module) {
|
|
255
|
+
if (!process.env['EXPOSE_GITHUB_APP']) {
|
|
256
|
+
process.stderr.write('Set EXPOSE_GITHUB_APP=true to start the GitHub App webhook server.\n');
|
|
257
|
+
process.exit(0);
|
|
258
|
+
}
|
|
259
|
+
startGitHubApp();
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=app.js.map
|