@nxuss/lemma 0.9.0 → 0.9.2

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.
Files changed (166) hide show
  1. package/README.md +40 -6
  2. package/dist/cjs/cli/lemma-proxy.d.ts.map +1 -1
  3. package/dist/cjs/cli/lemma-proxy.js +52 -1
  4. package/dist/cjs/cli/lemma-proxy.js.map +1 -1
  5. package/dist/cjs/mcp/tools.d.ts.map +1 -1
  6. package/dist/cjs/mcp/tools.js +302 -0
  7. package/dist/cjs/mcp/tools.js.map +1 -1
  8. package/dist/cjs/pr-review/PRReviewEngine.d.ts +4 -0
  9. package/dist/cjs/pr-review/PRReviewEngine.d.ts.map +1 -0
  10. package/dist/cjs/pr-review/PRReviewEngine.js +203 -0
  11. package/dist/cjs/pr-review/PRReviewEngine.js.map +1 -0
  12. package/dist/cjs/pr-review/ReviewStore.d.ts +9 -0
  13. package/dist/cjs/pr-review/ReviewStore.d.ts.map +1 -0
  14. package/dist/cjs/pr-review/ReviewStore.js +29 -0
  15. package/dist/cjs/pr-review/ReviewStore.js.map +1 -0
  16. package/dist/cjs/pr-review/adapters/AzureDevOpsAdapter.d.ts +18 -0
  17. package/dist/cjs/pr-review/adapters/AzureDevOpsAdapter.d.ts.map +1 -0
  18. package/dist/cjs/pr-review/adapters/AzureDevOpsAdapter.js +156 -0
  19. package/dist/cjs/pr-review/adapters/AzureDevOpsAdapter.js.map +1 -0
  20. package/dist/cjs/pr-review/adapters/GitHubAdapter.d.ts +18 -0
  21. package/dist/cjs/pr-review/adapters/GitHubAdapter.d.ts.map +1 -0
  22. package/dist/cjs/pr-review/adapters/GitHubAdapter.js +106 -0
  23. package/dist/cjs/pr-review/adapters/GitHubAdapter.js.map +1 -0
  24. package/dist/cjs/pr-review/adapters/GitLabAdapter.d.ts +19 -0
  25. package/dist/cjs/pr-review/adapters/GitLabAdapter.d.ts.map +1 -0
  26. package/dist/cjs/pr-review/adapters/GitLabAdapter.js +137 -0
  27. package/dist/cjs/pr-review/adapters/GitLabAdapter.js.map +1 -0
  28. package/dist/cjs/pr-review/adapters/GitPlatformAdapter.d.ts +14 -0
  29. package/dist/cjs/pr-review/adapters/GitPlatformAdapter.d.ts.map +1 -0
  30. package/dist/cjs/pr-review/adapters/GitPlatformAdapter.js +3 -0
  31. package/dist/cjs/pr-review/adapters/GitPlatformAdapter.js.map +1 -0
  32. package/dist/cjs/pr-review/adapters/index.d.ts +5 -0
  33. package/dist/cjs/pr-review/adapters/index.d.ts.map +1 -0
  34. package/dist/cjs/pr-review/adapters/index.js +10 -0
  35. package/dist/cjs/pr-review/adapters/index.js.map +1 -0
  36. package/dist/cjs/pr-review/analyzers/QualityGrader.d.ts +7 -0
  37. package/dist/cjs/pr-review/analyzers/QualityGrader.d.ts.map +1 -0
  38. package/dist/cjs/pr-review/analyzers/QualityGrader.js +154 -0
  39. package/dist/cjs/pr-review/analyzers/QualityGrader.js.map +1 -0
  40. package/dist/cjs/pr-review/analyzers/RegressionDetector.d.ts +7 -0
  41. package/dist/cjs/pr-review/analyzers/RegressionDetector.d.ts.map +1 -0
  42. package/dist/cjs/pr-review/analyzers/RegressionDetector.js +151 -0
  43. package/dist/cjs/pr-review/analyzers/RegressionDetector.js.map +1 -0
  44. package/dist/cjs/pr-review/analyzers/SecurityScanner.d.ts +7 -0
  45. package/dist/cjs/pr-review/analyzers/SecurityScanner.d.ts.map +1 -0
  46. package/dist/cjs/pr-review/analyzers/SecurityScanner.js +110 -0
  47. package/dist/cjs/pr-review/analyzers/SecurityScanner.js.map +1 -0
  48. package/dist/cjs/pr-review/analyzers/StaticAnalyzer.d.ts +7 -0
  49. package/dist/cjs/pr-review/analyzers/StaticAnalyzer.d.ts.map +1 -0
  50. package/dist/cjs/pr-review/analyzers/StaticAnalyzer.js +237 -0
  51. package/dist/cjs/pr-review/analyzers/StaticAnalyzer.js.map +1 -0
  52. package/dist/cjs/pr-review/analyzers/index.d.ts +9 -0
  53. package/dist/cjs/pr-review/analyzers/index.d.ts.map +1 -0
  54. package/dist/cjs/pr-review/analyzers/index.js +12 -0
  55. package/dist/cjs/pr-review/analyzers/index.js.map +1 -0
  56. package/dist/cjs/pr-review/bridge/BrainBridge.d.ts +23 -0
  57. package/dist/cjs/pr-review/bridge/BrainBridge.d.ts.map +1 -0
  58. package/dist/cjs/pr-review/bridge/BrainBridge.js +100 -0
  59. package/dist/cjs/pr-review/bridge/BrainBridge.js.map +1 -0
  60. package/dist/cjs/pr-review/bridge/index.d.ts +2 -0
  61. package/dist/cjs/pr-review/bridge/index.d.ts.map +1 -0
  62. package/dist/cjs/pr-review/bridge/index.js +6 -0
  63. package/dist/cjs/pr-review/bridge/index.js.map +1 -0
  64. package/dist/cjs/pr-review/index.d.ts +5 -0
  65. package/dist/cjs/pr-review/index.d.ts.map +1 -0
  66. package/dist/cjs/pr-review/index.js +12 -0
  67. package/dist/cjs/pr-review/index.js.map +1 -0
  68. package/dist/cjs/pr-review/reviewRunner.d.ts +25 -0
  69. package/dist/cjs/pr-review/reviewRunner.d.ts.map +1 -0
  70. package/dist/cjs/pr-review/reviewRunner.js +97 -0
  71. package/dist/cjs/pr-review/reviewRunner.js.map +1 -0
  72. package/dist/cjs/pr-review/types.d.ts +80 -0
  73. package/dist/cjs/pr-review/types.d.ts.map +1 -0
  74. package/dist/cjs/pr-review/types.js +3 -0
  75. package/dist/cjs/pr-review/types.js.map +1 -0
  76. package/dist/cjs/pr-review/webhook/WebhookServer.d.ts +3 -0
  77. package/dist/cjs/pr-review/webhook/WebhookServer.d.ts.map +1 -0
  78. package/dist/cjs/pr-review/webhook/WebhookServer.js +114 -0
  79. package/dist/cjs/pr-review/webhook/WebhookServer.js.map +1 -0
  80. package/dist/cjs/pr-review/webhook/index.d.ts +2 -0
  81. package/dist/cjs/pr-review/webhook/index.d.ts.map +1 -0
  82. package/dist/cjs/pr-review/webhook/index.js +6 -0
  83. package/dist/cjs/pr-review/webhook/index.js.map +1 -0
  84. package/dist/esm/cli/lemma-proxy.d.ts.map +1 -1
  85. package/dist/esm/cli/lemma-proxy.js +52 -1
  86. package/dist/esm/cli/lemma-proxy.js.map +1 -1
  87. package/dist/esm/mcp/tools.d.ts.map +1 -1
  88. package/dist/esm/mcp/tools.js +302 -0
  89. package/dist/esm/mcp/tools.js.map +1 -1
  90. package/dist/esm/pr-review/PRReviewEngine.d.ts +4 -0
  91. package/dist/esm/pr-review/PRReviewEngine.d.ts.map +1 -0
  92. package/dist/esm/pr-review/PRReviewEngine.js +199 -0
  93. package/dist/esm/pr-review/PRReviewEngine.js.map +1 -0
  94. package/dist/esm/pr-review/ReviewStore.d.ts +9 -0
  95. package/dist/esm/pr-review/ReviewStore.d.ts.map +1 -0
  96. package/dist/esm/pr-review/ReviewStore.js +26 -0
  97. package/dist/esm/pr-review/ReviewStore.js.map +1 -0
  98. package/dist/esm/pr-review/adapters/AzureDevOpsAdapter.d.ts +18 -0
  99. package/dist/esm/pr-review/adapters/AzureDevOpsAdapter.d.ts.map +1 -0
  100. package/dist/esm/pr-review/adapters/AzureDevOpsAdapter.js +149 -0
  101. package/dist/esm/pr-review/adapters/AzureDevOpsAdapter.js.map +1 -0
  102. package/dist/esm/pr-review/adapters/GitHubAdapter.d.ts +18 -0
  103. package/dist/esm/pr-review/adapters/GitHubAdapter.d.ts.map +1 -0
  104. package/dist/esm/pr-review/adapters/GitHubAdapter.js +99 -0
  105. package/dist/esm/pr-review/adapters/GitHubAdapter.js.map +1 -0
  106. package/dist/esm/pr-review/adapters/GitLabAdapter.d.ts +19 -0
  107. package/dist/esm/pr-review/adapters/GitLabAdapter.d.ts.map +1 -0
  108. package/dist/esm/pr-review/adapters/GitLabAdapter.js +130 -0
  109. package/dist/esm/pr-review/adapters/GitLabAdapter.js.map +1 -0
  110. package/dist/esm/pr-review/adapters/GitPlatformAdapter.d.ts +14 -0
  111. package/dist/esm/pr-review/adapters/GitPlatformAdapter.d.ts.map +1 -0
  112. package/dist/esm/pr-review/adapters/GitPlatformAdapter.js +2 -0
  113. package/dist/esm/pr-review/adapters/GitPlatformAdapter.js.map +1 -0
  114. package/dist/esm/pr-review/adapters/index.d.ts +5 -0
  115. package/dist/esm/pr-review/adapters/index.d.ts.map +1 -0
  116. package/dist/esm/pr-review/adapters/index.js +4 -0
  117. package/dist/esm/pr-review/adapters/index.js.map +1 -0
  118. package/dist/esm/pr-review/analyzers/QualityGrader.d.ts +7 -0
  119. package/dist/esm/pr-review/analyzers/QualityGrader.d.ts.map +1 -0
  120. package/dist/esm/pr-review/analyzers/QualityGrader.js +151 -0
  121. package/dist/esm/pr-review/analyzers/QualityGrader.js.map +1 -0
  122. package/dist/esm/pr-review/analyzers/RegressionDetector.d.ts +7 -0
  123. package/dist/esm/pr-review/analyzers/RegressionDetector.d.ts.map +1 -0
  124. package/dist/esm/pr-review/analyzers/RegressionDetector.js +145 -0
  125. package/dist/esm/pr-review/analyzers/RegressionDetector.js.map +1 -0
  126. package/dist/esm/pr-review/analyzers/SecurityScanner.d.ts +7 -0
  127. package/dist/esm/pr-review/analyzers/SecurityScanner.d.ts.map +1 -0
  128. package/dist/esm/pr-review/analyzers/SecurityScanner.js +107 -0
  129. package/dist/esm/pr-review/analyzers/SecurityScanner.js.map +1 -0
  130. package/dist/esm/pr-review/analyzers/StaticAnalyzer.d.ts +7 -0
  131. package/dist/esm/pr-review/analyzers/StaticAnalyzer.d.ts.map +1 -0
  132. package/dist/esm/pr-review/analyzers/StaticAnalyzer.js +201 -0
  133. package/dist/esm/pr-review/analyzers/StaticAnalyzer.js.map +1 -0
  134. package/dist/esm/pr-review/analyzers/index.d.ts +9 -0
  135. package/dist/esm/pr-review/analyzers/index.d.ts.map +1 -0
  136. package/dist/esm/pr-review/analyzers/index.js +5 -0
  137. package/dist/esm/pr-review/analyzers/index.js.map +1 -0
  138. package/dist/esm/pr-review/bridge/BrainBridge.d.ts +23 -0
  139. package/dist/esm/pr-review/bridge/BrainBridge.d.ts.map +1 -0
  140. package/dist/esm/pr-review/bridge/BrainBridge.js +93 -0
  141. package/dist/esm/pr-review/bridge/BrainBridge.js.map +1 -0
  142. package/dist/esm/pr-review/bridge/index.d.ts +2 -0
  143. package/dist/esm/pr-review/bridge/index.d.ts.map +1 -0
  144. package/dist/esm/pr-review/bridge/index.js +2 -0
  145. package/dist/esm/pr-review/bridge/index.js.map +1 -0
  146. package/dist/esm/pr-review/index.d.ts +5 -0
  147. package/dist/esm/pr-review/index.d.ts.map +1 -0
  148. package/dist/esm/pr-review/index.js +3 -0
  149. package/dist/esm/pr-review/index.js.map +1 -0
  150. package/dist/esm/pr-review/reviewRunner.d.ts +25 -0
  151. package/dist/esm/pr-review/reviewRunner.d.ts.map +1 -0
  152. package/dist/esm/pr-review/reviewRunner.js +92 -0
  153. package/dist/esm/pr-review/reviewRunner.js.map +1 -0
  154. package/dist/esm/pr-review/types.d.ts +80 -0
  155. package/dist/esm/pr-review/types.d.ts.map +1 -0
  156. package/dist/esm/pr-review/types.js +2 -0
  157. package/dist/esm/pr-review/types.js.map +1 -0
  158. package/dist/esm/pr-review/webhook/WebhookServer.d.ts +3 -0
  159. package/dist/esm/pr-review/webhook/WebhookServer.d.ts.map +1 -0
  160. package/dist/esm/pr-review/webhook/WebhookServer.js +108 -0
  161. package/dist/esm/pr-review/webhook/WebhookServer.js.map +1 -0
  162. package/dist/esm/pr-review/webhook/index.d.ts +2 -0
  163. package/dist/esm/pr-review/webhook/index.d.ts.map +1 -0
  164. package/dist/esm/pr-review/webhook/index.js +2 -0
  165. package/dist/esm/pr-review/webhook/index.js.map +1 -0
  166. package/package.json +1 -1
@@ -0,0 +1,97 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAdapter = getAdapter;
4
+ exports.getTokenForPlatform = getTokenForPlatform;
5
+ exports.runPRReview = runPRReview;
6
+ const PRReviewEngine_1 = require("./PRReviewEngine");
7
+ const ReviewStore_1 = require("./ReviewStore");
8
+ const BrainBridge_1 = require("./bridge/BrainBridge");
9
+ const GitHubAdapter_1 = require("./adapters/GitHubAdapter");
10
+ const AzureDevOpsAdapter_1 = require("./adapters/AzureDevOpsAdapter");
11
+ const GitLabAdapter_1 = require("./adapters/GitLabAdapter");
12
+ const brainBridge = new BrainBridge_1.BrainBridge();
13
+ function getAdapter(platform, token) {
14
+ switch (platform) {
15
+ case "github": return new GitHubAdapter_1.GitHubAdapter(token);
16
+ case "azure": return new AzureDevOpsAdapter_1.AzureDevOpsAdapter(token);
17
+ case "gitlab": return new GitLabAdapter_1.GitLabAdapter(token);
18
+ default: throw new Error(`Unsupported platform: ${platform}`);
19
+ }
20
+ }
21
+ function getTokenForPlatform(platform) {
22
+ const token = process.env[platform === "github" ? "GITHUB_TOKEN"
23
+ : platform === "azure" ? "AZURE_DEVOPS_TOKEN"
24
+ : "GITLAB_TOKEN"] || "";
25
+ if (!token) {
26
+ throw new Error(`No ${platform} token found. Set ${platform === "github" ? "GITHUB_TOKEN"
27
+ : platform === "azure" ? "AZURE_DEVOPS_TOKEN"
28
+ : "GITLAB_TOKEN"} environment variable.`);
29
+ }
30
+ return token;
31
+ }
32
+ async function runPRReview(platform, repo, prNumber, options = {}) {
33
+ const autoApprove = options.autoApprove !== false;
34
+ const threshold = options.threshold || 90;
35
+ const token = getTokenForPlatform(platform);
36
+ const adapter = getAdapter(platform, token);
37
+ const [owner, ...repoParts] = repo.split("/");
38
+ const repoName = repoParts.join("/");
39
+ const [diffFiles, metadata, baseBranch] = await Promise.all([
40
+ adapter.getPRDiff(owner, repoName, prNumber),
41
+ adapter.getPRMetadata(owner, repoName, prNumber),
42
+ adapter.getBaseBranch(owner, repoName, prNumber),
43
+ ]);
44
+ const filePaths = diffFiles.map(df => df.path);
45
+ const priorBugs = await brainBridge.findPriorBugs(filePaths);
46
+ let extras = "";
47
+ if (priorBugs.size > 0) {
48
+ extras += `\n\n🧠 **Prior bug context from The Brain:**\n`;
49
+ for (const [file, memories] of priorBugs) {
50
+ extras += `- ${file}: ${memories.length} related memories\n`;
51
+ }
52
+ }
53
+ const result = (0, PRReviewEngine_1.runAnalysis)(diffFiles, { threshold, autoApprove }, process.cwd(), baseBranch);
54
+ const review = ReviewStore_1.ReviewStore.create({
55
+ score: result.score,
56
+ verdict: result.verdict,
57
+ findings: result.findings,
58
+ summary: result.summary,
59
+ approved: false,
60
+ metadata,
61
+ });
62
+ const commentBody = [
63
+ `# 🔍 Lemma PR Review — #${prNumber} ${metadata.title}`,
64
+ ``,
65
+ `**Score:** ${result.score}/100 | **Verdict:** ${result.verdict}`,
66
+ `**Files:** ${diffFiles.length} | **Findings:** ${result.findings.length}`,
67
+ extras,
68
+ ``,
69
+ result.summary,
70
+ ``,
71
+ `---`,
72
+ `*Review ID: ${review.reviewId}*`,
73
+ ].join("\n");
74
+ await adapter.postComment(owner, repoName, prNumber, commentBody);
75
+ let approved = false;
76
+ if (result.verdict === "APPROVED" && autoApprove) {
77
+ await adapter.submitReview(owner, repoName, prNumber, "APPROVE", `✅ Auto-approved by Lemma PR Review (score: ${result.score}/100, threshold: ${threshold})`);
78
+ approved = true;
79
+ }
80
+ else if (result.verdict === "CHANGES_REQUESTED") {
81
+ await adapter.submitReview(owner, repoName, prNumber, "REQUEST_CHANGES", `❌ Changes requested by Lemma PR Review (score: ${result.score}/100, threshold: ${threshold})`);
82
+ }
83
+ try {
84
+ await adapter.setStatus(owner, repoName, metadata.headSha, result.score >= threshold ? "success" : "failure", `Lemma PR Review: ${result.score}/100 — ${result.verdict}`);
85
+ }
86
+ catch { }
87
+ await brainBridge.storeReview(review.reviewId, repo, prNumber, result.score, result.verdict, result.findings, filePaths);
88
+ return {
89
+ reviewId: review.reviewId,
90
+ score: result.score,
91
+ verdict: result.verdict,
92
+ findingsCount: result.findings.length,
93
+ approved,
94
+ summary: result.summary,
95
+ };
96
+ }
97
+ //# sourceMappingURL=reviewRunner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviewRunner.js","sourceRoot":"","sources":["../../../src/pr-review/reviewRunner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ export type Severity = "CRITICAL" | "HIGH" | "MEDIUM" | "LOW";
2
+ export type Verdict = "APPROVED" | "NEUTRAL" | "CHANGES_REQUESTED";
3
+ export type Platform = "github" | "azure" | "gitlab";
4
+ export type ReviewEvent = "APPROVE" | "REQUEST_CHANGES" | "COMMENT";
5
+ export type StatusState = "pending" | "success" | "failure" | "error";
6
+ export interface Finding {
7
+ ruleId: string;
8
+ severity: Severity;
9
+ category: "security" | "regression" | "static" | "quality";
10
+ filePath: string;
11
+ line?: number;
12
+ message: string;
13
+ detail?: string;
14
+ suggestion?: string;
15
+ score: number;
16
+ }
17
+ export interface DiffFile {
18
+ path: string;
19
+ status: "added" | "modified" | "deleted" | "renamed";
20
+ additions: number;
21
+ deletions: number;
22
+ content?: string;
23
+ patch?: string;
24
+ }
25
+ export interface PRMetadata {
26
+ owner: string;
27
+ repo: string;
28
+ prNumber: number;
29
+ title: string;
30
+ description?: string;
31
+ baseBranch: string;
32
+ headBranch: string;
33
+ headSha: string;
34
+ author: string;
35
+ createdAt: string;
36
+ updatedAt: string;
37
+ }
38
+ export interface AnalyzeResult {
39
+ score: number;
40
+ verdict: Verdict;
41
+ findings: Finding[];
42
+ summary: string;
43
+ }
44
+ export interface PRReviewResult {
45
+ reviewId: string;
46
+ score: number;
47
+ verdict: Verdict;
48
+ findings: Finding[];
49
+ summary: string;
50
+ approved: boolean;
51
+ timestamp: string;
52
+ metadata?: PRMetadata;
53
+ }
54
+ export interface AnalyzerConfig {
55
+ threshold: number;
56
+ autoApprove: boolean;
57
+ }
58
+ export interface DiffAnalysisRequest {
59
+ diff: string;
60
+ baseBranch?: string;
61
+ workspaceRoot?: string;
62
+ }
63
+ export interface PRReviewRequest {
64
+ platform: Platform;
65
+ repo: string;
66
+ prNumber: number;
67
+ autoApprove?: boolean;
68
+ threshold?: number;
69
+ context?: string;
70
+ }
71
+ export interface WorkflowConfig {
72
+ platform: Platform;
73
+ autoApprove: boolean;
74
+ threshold: number;
75
+ }
76
+ export interface AdapterConfig {
77
+ token?: string;
78
+ baseUrl?: string;
79
+ }
80
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/pr-review/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/pr-review/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ import { Router } from "express";
2
+ export declare function createWebhookRouter(): Router;
3
+ //# sourceMappingURL=WebhookServer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebhookServer.d.ts","sourceRoot":"","sources":["../../../../src/pr-review/webhook/WebhookServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAqB,MAAM,SAAS,CAAC;AAUpD,wBAAgB,mBAAmB,IAAI,MAAM,CA+G5C"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createWebhookRouter = createWebhookRouter;
7
+ const express_1 = require("express");
8
+ const crypto_1 = __importDefault(require("crypto"));
9
+ const reviewRunner_1 = require("../reviewRunner");
10
+ function verifyGitHubSignature(payload, signature, secret) {
11
+ const sig = `sha256=${crypto_1.default.createHmac("sha256", secret).update(payload).digest("hex")}`;
12
+ if (signature.length !== sig.length)
13
+ return false;
14
+ return crypto_1.default.timingSafeEqual(Buffer.from(sig), Buffer.from(signature));
15
+ }
16
+ function createWebhookRouter() {
17
+ const router = (0, express_1.Router)();
18
+ router.post("/github", async (req, res) => {
19
+ const signature = req.headers["x-hub-signature-256"];
20
+ const event = req.headers["x-github-event"];
21
+ const webhookSecret = process.env.GITHUB_WEBHOOK_SECRET || "";
22
+ if (webhookSecret && signature) {
23
+ const rawBody = JSON.stringify(req.body);
24
+ if (!verifyGitHubSignature(rawBody, signature, webhookSecret)) {
25
+ res.status(401).json({ error: "Invalid signature" });
26
+ return;
27
+ }
28
+ }
29
+ if (event !== "pull_request") {
30
+ res.status(200).json({ status: "ignored", event });
31
+ return;
32
+ }
33
+ const action = req.body.action;
34
+ if (action !== "opened" && action !== "synchronize") {
35
+ res.status(200).json({ status: "ignored", action });
36
+ return;
37
+ }
38
+ const pr = req.body.pull_request;
39
+ const repo = req.body.repository;
40
+ const owner = repo.owner.login;
41
+ const repoName = repo.name;
42
+ const prNumber = pr.number;
43
+ const fullRepo = `${owner}/${repoName}`;
44
+ if (!process.env.GITHUB_TOKEN) {
45
+ res.status(500).json({ error: "GITHUB_TOKEN not set" });
46
+ return;
47
+ }
48
+ try {
49
+ const result = await (0, reviewRunner_1.runPRReview)("github", fullRepo, prNumber, {
50
+ threshold: parseInt(process.env.LEMMA_THRESHOLD || "90", 10),
51
+ autoApprove: process.env.LEMMA_AUTO_APPROVE !== "false",
52
+ });
53
+ res.json({ status: "ok", ...result });
54
+ }
55
+ catch (err) {
56
+ console.error("[Webhook] GitHub review failed:", err.message);
57
+ res.status(500).json({ error: err.message });
58
+ }
59
+ });
60
+ router.post("/azure", async (req, res) => {
61
+ const eventType = req.body.eventType;
62
+ if (eventType !== "git.pullrequest.created" && eventType !== "git.pullrequest.updated") {
63
+ res.status(200).json({ status: "ignored", eventType });
64
+ return;
65
+ }
66
+ const resource = req.body.resource;
67
+ const prNumber = resource?.pullRequestId;
68
+ const repoName = resource?.repository?.name;
69
+ const projectName = resource?.repository?.project?.name;
70
+ if (!prNumber || !repoName || !projectName || !process.env.AZURE_DEVOPS_TOKEN) {
71
+ res.status(500).json({ error: "Missing required Azure DevOps webhook fields or AZURE_DEVOPS_TOKEN" });
72
+ return;
73
+ }
74
+ const fullRepo = `${projectName}/${repoName}`;
75
+ try {
76
+ const result = await (0, reviewRunner_1.runPRReview)("azure", fullRepo, prNumber, {
77
+ threshold: parseInt(process.env.LEMMA_THRESHOLD || "90", 10),
78
+ autoApprove: process.env.LEMMA_AUTO_APPROVE !== "false",
79
+ });
80
+ res.json({ status: "ok", ...result });
81
+ }
82
+ catch (err) {
83
+ console.error("[Webhook] Azure review failed:", err.message);
84
+ res.status(500).json({ error: err.message });
85
+ }
86
+ });
87
+ router.post("/gitlab", async (req, res) => {
88
+ const objectKind = req.body.object_kind;
89
+ if (objectKind !== "merge_request") {
90
+ res.status(200).json({ status: "ignored", object_kind: objectKind });
91
+ return;
92
+ }
93
+ const mr = req.body.object_attributes;
94
+ const prNumber = mr?.iid;
95
+ const projectPath = req.body.project?.path_with_namespace;
96
+ if (!prNumber || !projectPath || !process.env.GITLAB_TOKEN) {
97
+ res.status(500).json({ error: "Missing required GitLab webhook fields or GITLAB_TOKEN" });
98
+ return;
99
+ }
100
+ try {
101
+ const result = await (0, reviewRunner_1.runPRReview)("gitlab", projectPath, prNumber, {
102
+ threshold: parseInt(process.env.LEMMA_THRESHOLD || "90", 10),
103
+ autoApprove: process.env.LEMMA_AUTO_APPROVE !== "false",
104
+ });
105
+ res.json({ status: "ok", ...result });
106
+ }
107
+ catch (err) {
108
+ console.error("[Webhook] GitLab review failed:", err.message);
109
+ res.status(500).json({ error: err.message });
110
+ }
111
+ });
112
+ return router;
113
+ }
114
+ //# sourceMappingURL=WebhookServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebhookServer.js","sourceRoot":"","sources":["../../../../src/pr-review/webhook/WebhookServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export { createWebhookRouter } from "./WebhookServer";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/pr-review/webhook/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWebhookRouter = void 0;
4
+ var WebhookServer_1 = require("./WebhookServer");
5
+ Object.defineProperty(exports, "createWebhookRouter", { enumerable: true, get: function () { return WebhookServer_1.createWebhookRouter; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/pr-review/webhook/index.ts"],"names":[],"mappings":";;;AAAA,iDAAsD;AAA7C,oHAAA,mBAAmB,OAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AAsbA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AAmgED,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
1
+ {"version":3,"file":"lemma-proxy.d.ts","sourceRoot":"","sources":["../../../src/cli/lemma-proxy.ts"],"names":[],"mappings":";AA2cA,wBAAgB,+BAA+B,CAAC,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CA4DvF;AAugED,wBAAsB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6KhL"}
@@ -36,6 +36,7 @@ function ask(query) {
36
36
  import ComplexityRouter from '../proxy/ComplexityRouter';
37
37
  import SemanticScrubber from '../security/SemanticScrubber';
38
38
  import CloudSyncClient from '../cloud/CloudSyncClient';
39
+ import { runPRReview } from '../pr-review/reviewRunner';
39
40
  import { pruneHistoryMessages, squeezePrompt } from '../utils/ContextSqueezer';
40
41
  import { AgentMultiplexer } from '../proxy/AgentMultiplexer';
41
42
  import { SseRelay } from '../proxy/SseRelay';
@@ -366,6 +367,26 @@ enabled = true
366
367
  }
367
368
  }
368
369
  catch { }
370
+ // Register lemma MCP server in OpenCode user config (~/.opencode.json)
371
+ const openCodeMcpFile = path.join(os.homedir(), '.opencode.json');
372
+ try {
373
+ let openCodeConfig = {};
374
+ if (fs.existsSync(openCodeMcpFile)) {
375
+ openCodeConfig = JSON.parse(fs.readFileSync(openCodeMcpFile, 'utf8'));
376
+ }
377
+ if (!openCodeConfig.mcp)
378
+ openCodeConfig.mcp = {};
379
+ if (!openCodeConfig.mcp.lemma) {
380
+ openCodeConfig.mcp.lemma = {
381
+ command: "npx",
382
+ args: ["-y", "@nxuss/lemma", "mcp"],
383
+ enabled: true
384
+ };
385
+ fs.writeFileSync(openCodeMcpFile, JSON.stringify(openCodeConfig, null, 2));
386
+ console.log('✅ [OpenCode] Registered lemma MCP server in ~/.opencode.json');
387
+ }
388
+ }
389
+ catch { }
369
390
  console.log(`✅ Auto-configured Lemma for [${project}]`);
370
391
  }
371
392
  const EVENT_LOG = [];
@@ -416,6 +437,7 @@ function injectIdeRules(projectName) {
416
437
  { name: 'Cursor (v2)', path: path.join(process.cwd(), '.cursor/rules/lemma.mdc') },
417
438
  { name: 'Windsurf', path: path.join(process.cwd(), '.windsurfrules') },
418
439
  { name: 'Cline', path: path.join(process.cwd(), '.clinerules') },
440
+ { name: 'OpenCode', path: path.join(process.cwd(), '.opencode.md') },
419
441
  ];
420
442
  for (const target of rulesTargets) {
421
443
  try {
@@ -1507,6 +1529,9 @@ class LemmaServer {
1507
1529
  });
1508
1530
  this.app.get('/dashboard/*', (req, res) => res.sendFile(path.join(this.dashboardPath, 'index.html')));
1509
1531
  }
1532
+ // Mount PR Review webhook endpoints
1533
+ const { createWebhookRouter } = require('../pr-review/webhook/WebhookServer');
1534
+ this.app.use('/api/webhook', createWebhookRouter());
1510
1535
  }
1511
1536
  startWorkspaceTimeWatcher() {
1512
1537
  const cwd = process.cwd();
@@ -2331,7 +2356,7 @@ program.command('init')
2331
2356
  console.log('\n🧠 \x1b[35mAuto-configuring MCP for AI IDEs...\x1b[0m');
2332
2357
  }
2333
2358
  else {
2334
- const ans = await ask('\n🧠 Configure MCP servers for your IDEs (Claude, Cursor, Windsurf, VS Code, Kiro, Codex)? (Y/n): ');
2359
+ const ans = await ask('\n🧠 Configure MCP servers for your IDEs (Claude, Cursor, Windsurf, VS Code, OpenCode, Kiro, Codex)? (Y/n): ');
2335
2360
  if (ans.toLowerCase() === 'n' || ans.toLowerCase() === 'no') {
2336
2361
  opts.configure = false;
2337
2362
  console.log('⏭️ Skipping IDE auto-configuration');
@@ -2607,6 +2632,32 @@ program.command('clipboard')
2607
2632
  process.exit(1);
2608
2633
  }
2609
2634
  });
2635
+ program.command('pr-review')
2636
+ .description('Run PR review via CLI (reads env vars for CI/CD: LEMMA_PLATFORM, LEMMA_REPO, LEMMA_PR_NUMBER)')
2637
+ .option('-p, --platform <platform>', 'Git platform (github, azure, gitlab)')
2638
+ .option('-r, --repo <repo>', 'Repository (owner/repo)')
2639
+ .option('-n, --pr-number <number>', 'PR number')
2640
+ .option('-t, --threshold <number>', 'Score threshold for auto-approve', '90')
2641
+ .option('--no-auto-approve', 'Skip auto-approve even if score meets threshold')
2642
+ .action(async (opts) => {
2643
+ const platform = opts.platform || process.env.LEMMA_PLATFORM || '';
2644
+ const repo = opts.repo || process.env.LEMMA_REPO || '';
2645
+ const prNumber = opts.prNumber || process.env.LEMMA_PR_NUMBER || '';
2646
+ const threshold = parseInt(opts.threshold, 10);
2647
+ const autoApprove = opts.autoApprove !== false;
2648
+ if (!platform || !repo || !prNumber) {
2649
+ console.error('Error: platform, repo, and pr-number are required.\nSet via args or LEMMA_PLATFORM, LEMMA_REPO, LEMMA_PR_NUMBER env vars.');
2650
+ process.exit(1);
2651
+ }
2652
+ try {
2653
+ const result = await runPRReview(platform, repo, parseInt(prNumber, 10), { threshold, autoApprove });
2654
+ console.log(JSON.stringify(result, null, 2));
2655
+ }
2656
+ catch (err) {
2657
+ console.error(`PR review failed: ${err.message}`);
2658
+ process.exit(1);
2659
+ }
2660
+ });
2610
2661
  if (process.argv[1] && (process.argv[1].includes('lemma') || process.argv[1].endsWith('.cjs') || process.argv[1].endsWith('.js'))) {
2611
2662
  // Bare `lemma` with no args → show welcome screen
2612
2663
  if (process.argv.length <= 2) {