gitlab-auto-reviewers 2.0.0 → 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.
Files changed (98) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +20 -10
  3. package/dist/bin/cli.js +155 -85
  4. package/dist/bin/cli.js.map +1 -1
  5. package/dist/bin/index.d.ts +1 -8
  6. package/dist/bin/index.d.ts.map +1 -1
  7. package/dist/bin/index.js +26 -9
  8. package/dist/bin/index.js.map +1 -1
  9. package/dist/bin/mcp.js +0 -0
  10. package/dist/cli/cicd-integration.d.ts +127 -0
  11. package/dist/cli/cicd-integration.d.ts.map +1 -0
  12. package/dist/cli/cicd-integration.js +385 -0
  13. package/dist/cli/cicd-integration.js.map +1 -0
  14. package/dist/cli/commands.d.ts +21 -4
  15. package/dist/cli/commands.d.ts.map +1 -1
  16. package/dist/cli/commands.js +417 -71
  17. package/dist/cli/commands.js.map +1 -1
  18. package/dist/cli/config.d.ts +145 -0
  19. package/dist/cli/config.d.ts.map +1 -0
  20. package/dist/cli/config.js +277 -0
  21. package/dist/cli/config.js.map +1 -0
  22. package/dist/cli/consistency-validator.d.ts +175 -0
  23. package/dist/cli/consistency-validator.d.ts.map +1 -0
  24. package/dist/cli/consistency-validator.js +599 -0
  25. package/dist/cli/consistency-validator.js.map +1 -0
  26. package/dist/cli/data-source-consistency.d.ts +105 -0
  27. package/dist/cli/data-source-consistency.d.ts.map +1 -0
  28. package/dist/cli/data-source-consistency.js +271 -0
  29. package/dist/cli/data-source-consistency.js.map +1 -0
  30. package/dist/cli/data-source-selector.d.ts +103 -0
  31. package/dist/cli/data-source-selector.d.ts.map +1 -0
  32. package/dist/cli/data-source-selector.js +242 -0
  33. package/dist/cli/data-source-selector.js.map +1 -0
  34. package/dist/cli/enhanced-cli.d.ts +104 -0
  35. package/dist/cli/enhanced-cli.d.ts.map +1 -0
  36. package/dist/cli/enhanced-cli.js +321 -0
  37. package/dist/cli/enhanced-cli.js.map +1 -0
  38. package/dist/cli/enhanced-data-source-resolver.d.ts +67 -0
  39. package/dist/cli/enhanced-data-source-resolver.d.ts.map +1 -0
  40. package/dist/cli/enhanced-data-source-resolver.js +249 -0
  41. package/dist/cli/enhanced-data-source-resolver.js.map +1 -0
  42. package/dist/cli/enhanced-parameter-resolver.d.ts +111 -0
  43. package/dist/cli/enhanced-parameter-resolver.d.ts.map +1 -0
  44. package/dist/cli/enhanced-parameter-resolver.js +233 -0
  45. package/dist/cli/enhanced-parameter-resolver.js.map +1 -0
  46. package/dist/cli/errors.d.ts +105 -0
  47. package/dist/cli/errors.d.ts.map +1 -0
  48. package/dist/cli/errors.js +577 -0
  49. package/dist/cli/errors.js.map +1 -0
  50. package/dist/cli/output.d.ts +43 -3
  51. package/dist/cli/output.d.ts.map +1 -1
  52. package/dist/cli/output.js +157 -30
  53. package/dist/cli/output.js.map +1 -1
  54. package/dist/cli/parameter-source-tracker.d.ts +169 -0
  55. package/dist/cli/parameter-source-tracker.d.ts.map +1 -0
  56. package/dist/cli/parameter-source-tracker.js +252 -0
  57. package/dist/cli/parameter-source-tracker.js.map +1 -0
  58. package/dist/cli/template-engine.d.ts +109 -0
  59. package/dist/cli/template-engine.d.ts.map +1 -0
  60. package/dist/cli/template-engine.js +220 -0
  61. package/dist/cli/template-engine.js.map +1 -0
  62. package/dist/config/config.service.d.ts +24 -2
  63. package/dist/config/config.service.d.ts.map +1 -1
  64. package/dist/config/config.service.js +39 -6
  65. package/dist/config/config.service.js.map +1 -1
  66. package/dist/datasources/local-git-data-source.d.ts +39 -0
  67. package/dist/datasources/local-git-data-source.d.ts.map +1 -1
  68. package/dist/datasources/local-git-data-source.js +121 -1
  69. package/dist/datasources/local-git-data-source.js.map +1 -1
  70. package/dist/enhanced-config.js +26 -0
  71. package/dist/index.js +0 -0
  72. package/dist/mcp/server.js +2 -2
  73. package/dist/mcp/server.js.map +1 -1
  74. package/dist/services/blacklist.service.d.ts +11 -5
  75. package/dist/services/blacklist.service.d.ts.map +1 -1
  76. package/dist/services/blacklist.service.js +28 -7
  77. package/dist/services/blacklist.service.js.map +1 -1
  78. package/dist/services/reviewer-service.d.ts +24 -0
  79. package/dist/services/reviewer-service.d.ts.map +1 -1
  80. package/dist/services/reviewer-service.js +177 -7
  81. package/dist/services/reviewer-service.js.map +1 -1
  82. package/dist/services/whitelist.service.js +1 -1
  83. package/dist/services/whitelist.service.js.map +1 -1
  84. package/dist/types/enhanced-config.d.ts +121 -0
  85. package/dist/types/enhanced-config.d.ts.map +1 -0
  86. package/dist/types/enhanced-config.js +27 -0
  87. package/dist/types/enhanced-config.js.map +1 -0
  88. package/dist/types.d.ts +28 -0
  89. package/dist/types.d.ts.map +1 -1
  90. package/package.json +11 -11
  91. package/dist/bin/deprecated-mcp.d.ts +0 -12
  92. package/dist/bin/deprecated-mcp.d.ts.map +0 -1
  93. package/dist/bin/deprecated-mcp.js +0 -73
  94. package/dist/bin/deprecated-mcp.js.map +0 -1
  95. package/dist/tools.d.ts +0 -22
  96. package/dist/tools.d.ts.map +0 -1
  97. package/dist/tools.js +0 -176
  98. package/dist/tools.js.map +0 -1
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Parameter Source Tracker
3
+ *
4
+ * Tracks and logs the source of each configuration parameter for debugging.
5
+ * Implements Requirement 3.5: THE System SHALL log the source of each configuration value for debugging
6
+ *
7
+ * @module cli/parameter-source-tracker
8
+ */
9
+ /**
10
+ * Parameter Source Tracker
11
+ *
12
+ * Tracks the source of each configuration parameter and provides
13
+ * comprehensive logging for debugging configuration issues.
14
+ */
15
+ export class ParameterSourceTracker {
16
+ parameters = new Map();
17
+ logger;
18
+ /**
19
+ * Creates a new ParameterSourceTracker instance
20
+ *
21
+ * @param logger - Logger instance for outputting parameter source information
22
+ */
23
+ constructor(logger) {
24
+ this.logger = logger;
25
+ }
26
+ /**
27
+ * Track a parameter with its value and source
28
+ */
29
+ track(name, value, source, options) {
30
+ this.parameters.set(name, {
31
+ name,
32
+ value,
33
+ source,
34
+ sourceDetail: options?.sourceDetail,
35
+ masked: options?.masked,
36
+ });
37
+ }
38
+ /**
39
+ * Resolve a parameter value with source tracking
40
+ * Implements the precedence: CLI argument > environment variable > auto-detected > config file > default
41
+ */
42
+ resolve(name, cliValue, envVarName, autoDetectFn, configValue, defaultValue, options) {
43
+ // Priority 1: CLI argument
44
+ if (cliValue !== undefined) {
45
+ this.track(name, cliValue, 'cli-argument', {
46
+ sourceDetail: `--${this.toKebabCase(name)}`,
47
+ masked: options?.masked,
48
+ });
49
+ return cliValue;
50
+ }
51
+ // Priority 2: Environment variable
52
+ if (envVarName) {
53
+ const envValue = process.env[envVarName];
54
+ if (envValue !== undefined && envValue !== '') {
55
+ const parsedValue = this.parseEnvValue(envValue);
56
+ this.track(name, parsedValue, 'environment', {
57
+ sourceDetail: envVarName,
58
+ masked: options?.masked,
59
+ });
60
+ return parsedValue;
61
+ }
62
+ }
63
+ // Priority 3: Auto-detection
64
+ if (autoDetectFn) {
65
+ const autoValue = autoDetectFn();
66
+ if (autoValue !== undefined) {
67
+ this.track(name, autoValue, 'auto-detected', {
68
+ masked: options?.masked,
69
+ });
70
+ return autoValue;
71
+ }
72
+ }
73
+ // Priority 4: Config file
74
+ if (configValue !== undefined) {
75
+ this.track(name, configValue, 'config-file', {
76
+ masked: options?.masked,
77
+ });
78
+ return configValue;
79
+ }
80
+ // Priority 5: Default value
81
+ if (defaultValue !== undefined) {
82
+ this.track(name, defaultValue, 'default', {
83
+ masked: options?.masked,
84
+ });
85
+ return defaultValue;
86
+ }
87
+ // Not set
88
+ this.track(name, undefined, 'not-set', {
89
+ masked: options?.masked,
90
+ });
91
+ return undefined;
92
+ }
93
+ /**
94
+ * Get all tracked parameters
95
+ */
96
+ getAll() {
97
+ return new Map(this.parameters);
98
+ }
99
+ /**
100
+ * Get a specific tracked parameter
101
+ *
102
+ * @param name - The name of the parameter to retrieve
103
+ * @returns The tracked parameter or undefined if not found
104
+ */
105
+ get(name) {
106
+ return this.parameters.get(name);
107
+ }
108
+ /**
109
+ * Log all parameter sources
110
+ * This implements Requirement 3.5
111
+ */
112
+ logParameterSources() {
113
+ this.logger.info('Configuration resolved - parameter sources:');
114
+ const sortedParams = Array.from(this.parameters.entries()).sort(([a], [b]) => a.localeCompare(b));
115
+ for (const [name, param] of sortedParams) {
116
+ const displayValue = this.formatValueForLog(param);
117
+ const sourceInfo = this.formatSourceForLog(param);
118
+ this.logger.info(` ${name}: ${displayValue} (${sourceInfo})`);
119
+ }
120
+ }
121
+ /**
122
+ * Log parameter sources in a structured format (for JSON output)
123
+ */
124
+ toStructuredLog() {
125
+ const result = {};
126
+ for (const [name, param] of this.parameters) {
127
+ result[name] = {
128
+ value: param.masked ? '***' : param.value,
129
+ source: param.source,
130
+ sourceDetail: param.sourceDetail,
131
+ };
132
+ }
133
+ return result;
134
+ }
135
+ /**
136
+ * Format value for logging (handles masking and undefined)
137
+ */
138
+ formatValueForLog(param) {
139
+ if (param.value === undefined) {
140
+ return '<not set>';
141
+ }
142
+ if (param.masked) {
143
+ return '***';
144
+ }
145
+ if (typeof param.value === 'string') {
146
+ // Truncate long strings
147
+ if (param.value.length > 50) {
148
+ return `"${param.value.substring(0, 47)}..."`;
149
+ }
150
+ return `"${param.value}"`;
151
+ }
152
+ return String(param.value);
153
+ }
154
+ /**
155
+ * Format source information for logging
156
+ */
157
+ formatSourceForLog(param) {
158
+ switch (param.source) {
159
+ case 'cli-argument':
160
+ return `CLI argument ${param.sourceDetail || ''}`.trim();
161
+ case 'environment':
162
+ return `environment variable ${param.sourceDetail || ''}`.trim();
163
+ case 'auto-detected':
164
+ return param.sourceDetail ? `auto-detected from ${param.sourceDetail}` : 'auto-detected';
165
+ case 'config-file':
166
+ return param.sourceDetail ? `config file ${param.sourceDetail}` : 'config file';
167
+ case 'default':
168
+ return 'default';
169
+ case 'not-set':
170
+ return 'not set';
171
+ default:
172
+ return param.source;
173
+ }
174
+ }
175
+ /**
176
+ * Convert camelCase to kebab-case
177
+ */
178
+ toKebabCase(str) {
179
+ return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
180
+ }
181
+ /**
182
+ * Parse environment variable value to appropriate type
183
+ */
184
+ parseEnvValue(value) {
185
+ // Try to parse as number
186
+ const num = Number(value);
187
+ if (!isNaN(num) && value.trim() !== '') {
188
+ return num;
189
+ }
190
+ // Try to parse as boolean
191
+ if (value.toLowerCase() === 'true') {
192
+ return true;
193
+ }
194
+ if (value.toLowerCase() === 'false') {
195
+ return false;
196
+ }
197
+ // Return as string
198
+ return value;
199
+ }
200
+ }
201
+ /**
202
+ * Create a parameter source tracker and resolve all CLI parameters
203
+ *
204
+ * @param options - CLI options from argument parsing
205
+ * @param cicdEnv - CI/CD environment detection result
206
+ * @param logger - Logger instance
207
+ * @returns Resolved parameters with source tracking
208
+ */
209
+ export function resolveParametersWithTracking(options, cicdEnv, logger) {
210
+ const tracker = new ParameterSourceTracker(logger);
211
+ // Resolve each parameter with source tracking
212
+ // NOTE: We need to resolve project FIRST to determine if we should auto-detect repoPath
213
+ // When both project ID and project directory are available in CI, prefer API mode (project ID)
214
+ // because it provides more reliable data access in CI environments
215
+ const project = tracker.resolve('project', options.project, 'CI_PROJECT_ID', // Also check CI_PROJECT_ID environment variable
216
+ () => cicdEnv.isCI ? cicdEnv.projectId : undefined, undefined, undefined);
217
+ // Only auto-detect repoPath from CI_PROJECT_DIR if project is NOT already set
218
+ // This prevents the "Cannot specify both --repo-path and --project" conflict
219
+ const repoPath = tracker.resolve('repoPath', options.repoPath, project ? undefined : 'CI_PROJECT_DIR', // Only use CI_PROJECT_DIR if project is not set
220
+ undefined, undefined, undefined);
221
+ // Resolve mergeRequestIid FIRST to determine if we should auto-detect branch
222
+ // When both MR IID and branch are available in CI, prefer MR IID because
223
+ // it provides more specific context for reviewer suggestions
224
+ const mergeRequestIid = tracker.resolve('mergeRequestIid', options.mergeRequestIid, 'CI_MERGE_REQUEST_IID', () => cicdEnv.isCI ? cicdEnv.mergeRequestIid : undefined, undefined, undefined);
225
+ // Only auto-detect branch from CI_COMMIT_REF_NAME if mergeRequestIid is NOT already set
226
+ // This prevents the "Cannot specify both merge request IID and branch name" conflict
227
+ const branch = tracker.resolve('branch', options.branch, mergeRequestIid ? undefined : 'CI_COMMIT_REF_NAME', // Only use CI_COMMIT_REF_NAME if MR IID is not set
228
+ () => (cicdEnv.isCI && !mergeRequestIid) ? cicdEnv.branch : undefined, undefined, undefined);
229
+ const gitlabUrl = tracker.resolve('gitlabUrl', options.gitlabUrl, 'GITLAB_URL', () => process.env.CI_SERVER_URL, // Auto-detect from GitLab CI environment
230
+ undefined, 'https://gitlab.com') || 'https://gitlab.com';
231
+ const gitlabToken = tracker.resolve('gitlabToken', options.gitlabToken, 'GITLAB_TOKEN', () => process.env.CI_JOB_TOKEN, undefined, undefined, { masked: true });
232
+ const format = tracker.resolve('format', options.format, undefined, () => cicdEnv.isCI ? 'json' : undefined, undefined, 'text') || 'text';
233
+ const verbose = tracker.resolve('verbose', options.verbose, undefined, undefined, undefined, false) || false;
234
+ const dryRun = tracker.resolve('dryRun', options.dryRun, undefined, undefined, undefined, false) || false;
235
+ const quiet = tracker.resolve('quiet', options.quiet, undefined, () => cicdEnv.isCI ? true : undefined, undefined, false) || false;
236
+ return {
237
+ tracker,
238
+ resolved: {
239
+ repoPath,
240
+ project,
241
+ mergeRequestIid,
242
+ branch,
243
+ gitlabUrl,
244
+ gitlabToken,
245
+ format,
246
+ verbose,
247
+ dryRun,
248
+ quiet,
249
+ },
250
+ };
251
+ }
252
+ //# sourceMappingURL=parameter-source-tracker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parameter-source-tracker.js","sourceRoot":"","sources":["../../src/cli/parameter-source-tracker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Template Engine for CLI Comment Generation
3
+ *
4
+ * This module provides template loading, compilation, and rendering
5
+ * for custom comment formats in the CLI.
6
+ *
7
+ * @module cli/template-engine
8
+ */
9
+ import type { AutoReviewerResult } from '../types.js';
10
+ /**
11
+ * Compiled template interface
12
+ */
13
+ export interface CompiledTemplate {
14
+ render(data: TemplateData): string;
15
+ validate(): boolean;
16
+ }
17
+ /**
18
+ * Template data interface
19
+ *
20
+ * @property contributors - Array of contributor suggestions with scoring and reasoning
21
+ * @property teamMembers - Array of team member suggestions with workload information
22
+ * @property codeOwners - Array of code owner suggestions based on CODEOWNERS file
23
+ * @property summary - Summary statistics for the reviewer suggestions
24
+ * @property timestamp - ISO timestamp when the analysis was performed
25
+ * @property projectId - Optional GitLab project ID for context
26
+ * @property mergeRequestIid - Optional merge request internal ID for context
27
+ */
28
+ export interface TemplateData {
29
+ contributors: Array<{
30
+ username: string;
31
+ reason: string;
32
+ workload: number;
33
+ fte?: number;
34
+ }>;
35
+ teamMembers: Array<{
36
+ username: string;
37
+ reason: string;
38
+ workload: number;
39
+ fte?: number;
40
+ }>;
41
+ codeOwners: Array<{
42
+ username: string;
43
+ reason: string;
44
+ workload: number;
45
+ fte?: number;
46
+ }>;
47
+ summary: {
48
+ totalSuggestions: number;
49
+ contributorCount: number;
50
+ teamMemberCount: number;
51
+ codeOwnerCount: number;
52
+ };
53
+ timestamp: string;
54
+ projectId?: string;
55
+ mergeRequestIid?: number;
56
+ [key: string]: unknown;
57
+ }
58
+ /**
59
+ * Template engine for custom comment formats
60
+ */
61
+ export declare class TemplateEngine {
62
+ private templates;
63
+ /**
64
+ * Load and compile a template from file
65
+ *
66
+ * @param templatePath - Path to the template file
67
+ * @returns Compiled template
68
+ * @throws Error if template cannot be loaded or compiled
69
+ */
70
+ loadTemplate(templatePath: string): Promise<CompiledTemplate>;
71
+ /**
72
+ * Compile a template from string content
73
+ *
74
+ * @param content - Template content
75
+ * @returns Compiled template
76
+ */
77
+ compileTemplate(content: string): CompiledTemplate;
78
+ /**
79
+ * Get the default template content
80
+ *
81
+ * @returns Default template content matching MCP server format
82
+ */
83
+ getDefaultTemplate(): string;
84
+ /**
85
+ * Render a comment using the default or custom template
86
+ *
87
+ * @param result - Reviewer analysis result
88
+ * @param templatePath - Optional custom template path
89
+ * @returns Rendered comment
90
+ */
91
+ renderComment(result: AutoReviewerResult, templatePath?: string): Promise<string>;
92
+ /**
93
+ * Validate a template file
94
+ *
95
+ * @param templatePath - Path to the template file
96
+ * @returns True if template is valid
97
+ * @throws Error if template is invalid
98
+ */
99
+ validateTemplate(templatePath: string): Promise<boolean>;
100
+ /**
101
+ * Clear template cache
102
+ */
103
+ clearCache(): void;
104
+ }
105
+ /**
106
+ * Default template engine instance
107
+ */
108
+ export declare const templateEngine: TemplateEngine;
109
+ //# sourceMappingURL=template-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-engine.d.ts","sourceRoot":"","sources":["../../src/cli/template-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,MAAM,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAAC;IACnC,QAAQ,IAAI,OAAO,CAAC;CACrB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,KAAK,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,WAAW,EAAE,KAAK,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,UAAU,EAAE,KAAK,CAAC;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IACH,OAAO,EAAE;QACP,gBAAgB,EAAE,MAAM,CAAC;QACzB,gBAAgB,EAAE,MAAM,CAAC;QACzB,eAAe,EAAE,MAAM,CAAC;QACxB,cAAc,EAAE,MAAM,CAAC;KACxB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAwED;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,SAAS,CAAuC;IAExD;;;;;;OAMG;IACG,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA0BnE;;;;;OAKG;IACH,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB;IAIlD;;;;OAIG;IACH,kBAAkB,IAAI,MAAM;IAkC5B;;;;;;OAMG;IACG,aAAa,CAAC,MAAM,EAAE,kBAAkB,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAwCvF;;;;;;OAMG;IACG,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK9D;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB;AAED;;GAEG;AACH,eAAO,MAAM,cAAc,gBAAuB,CAAC"}
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Template Engine for CLI Comment Generation
3
+ *
4
+ * This module provides template loading, compilation, and rendering
5
+ * for custom comment formats in the CLI.
6
+ *
7
+ * @module cli/template-engine
8
+ */
9
+ import { readFileSync, existsSync } from 'fs';
10
+ import { resolve } from 'path';
11
+ /**
12
+ * Simple template implementation
13
+ */
14
+ class SimpleTemplate {
15
+ content;
16
+ constructor(content) {
17
+ this.content = content;
18
+ }
19
+ render(data) {
20
+ let result = this.content;
21
+ // Replace template variables
22
+ result = result.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (match, path) => {
23
+ const value = this.getNestedValue(data, path);
24
+ return value !== undefined ? String(value) : match;
25
+ });
26
+ // Handle loops for contributors
27
+ result = result.replace(/\{\{#each contributors\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, template) => {
28
+ return data.contributors.map(contributor => {
29
+ return template.replace(/\{\{(\w+)\}\}/g, (innerMatch, prop) => {
30
+ const value = contributor[prop];
31
+ return value !== undefined ? String(value) : innerMatch;
32
+ });
33
+ }).join('');
34
+ });
35
+ // Handle loops for team members
36
+ result = result.replace(/\{\{#each teamMembers\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, template) => {
37
+ return data.teamMembers.map(member => {
38
+ return template.replace(/\{\{(\w+)\}\}/g, (innerMatch, prop) => {
39
+ const value = member[prop];
40
+ return value !== undefined ? String(value) : innerMatch;
41
+ });
42
+ }).join('');
43
+ });
44
+ // Handle loops for code owners
45
+ result = result.replace(/\{\{#each codeOwners\}\}([\s\S]*?)\{\{\/each\}\}/g, (_match, template) => {
46
+ return data.codeOwners.map(owner => {
47
+ return template.replace(/\{\{(\w+)\}\}/g, (innerMatch, prop) => {
48
+ const value = owner[prop];
49
+ return value !== undefined ? String(value) : innerMatch;
50
+ });
51
+ }).join('');
52
+ });
53
+ // Handle conditionals
54
+ result = result.replace(/\{\{#if (\w+(?:\.\w+)*)\}\}([\s\S]*?)\{\{\/if\}\}/g, (_match, path, content) => {
55
+ const value = this.getNestedValue(data, path);
56
+ return value ? content : '';
57
+ });
58
+ return result;
59
+ }
60
+ validate() {
61
+ // Basic validation - check for balanced template tags
62
+ const openTags = (this.content.match(/\{\{#/g) || []).length;
63
+ const closeTags = (this.content.match(/\{\{\//g) || []).length;
64
+ return openTags === closeTags;
65
+ }
66
+ getNestedValue(obj, path) {
67
+ return path.split('.').reduce((current, key) => {
68
+ return current && typeof current === 'object' && current !== null && key in current
69
+ ? current[key]
70
+ : undefined;
71
+ }, obj);
72
+ }
73
+ }
74
+ /**
75
+ * Template engine for custom comment formats
76
+ */
77
+ export class TemplateEngine {
78
+ templates = new Map();
79
+ /**
80
+ * Load and compile a template from file
81
+ *
82
+ * @param templatePath - Path to the template file
83
+ * @returns Compiled template
84
+ * @throws Error if template cannot be loaded or compiled
85
+ */
86
+ async loadTemplate(templatePath) {
87
+ if (this.templates.has(templatePath)) {
88
+ return this.templates.get(templatePath);
89
+ }
90
+ const resolvedPath = resolve(templatePath);
91
+ if (!existsSync(resolvedPath)) {
92
+ throw new Error(`Template file not found: ${resolvedPath}`);
93
+ }
94
+ try {
95
+ const content = readFileSync(resolvedPath, 'utf-8');
96
+ const compiled = this.compileTemplate(content);
97
+ if (!compiled.validate()) {
98
+ throw new Error(`Template validation failed: ${templatePath}`);
99
+ }
100
+ this.templates.set(templatePath, compiled);
101
+ return compiled;
102
+ }
103
+ catch (error) {
104
+ throw new Error(`Failed to load template ${templatePath}: ${error instanceof Error ? error.message : String(error)}`);
105
+ }
106
+ }
107
+ /**
108
+ * Compile a template from string content
109
+ *
110
+ * @param content - Template content
111
+ * @returns Compiled template
112
+ */
113
+ compileTemplate(content) {
114
+ return new SimpleTemplate(content);
115
+ }
116
+ /**
117
+ * Get the default template content
118
+ *
119
+ * @returns Default template content matching MCP server format
120
+ */
121
+ getDefaultTemplate() {
122
+ return `## 🔍 Suggested Reviewers
123
+
124
+ {{#if summary.totalSuggestions}}
125
+ Based on the analysis of changed files, here are the suggested reviewers:
126
+
127
+ {{#if contributors}}
128
+ ### 📝 **Contributors** ({{contributors.length}})
129
+ {{#each contributors}}
130
+ - **@{{username}}** - {{reason}} (Current workload: {{workload}} MRs{{#if fte}}, FTE: {{fte}}{{/if}})
131
+ {{/each}}
132
+
133
+ {{/if}}
134
+ {{#if teamMembers}}
135
+ ### 👥 **Team Members** ({{teamMembers.length}})
136
+ {{#each teamMembers}}
137
+ - **@{{username}}** - {{reason}} (Current workload: {{workload}} MRs{{#if fte}}, FTE: {{fte}}{{/if}})
138
+ {{/each}}
139
+
140
+ {{/if}}
141
+ {{#if codeOwners}}
142
+ ### 🏠 **Code Owners** ({{codeOwners.length}})
143
+ {{#each codeOwners}}
144
+ - **@{{username}}** - {{reason}} (Current workload: {{workload}} MRs{{#if fte}}, FTE: {{fte}}{{/if}})
145
+ {{/each}}
146
+
147
+ {{/if}}
148
+ ---
149
+ *Total suggestions: {{summary.totalSuggestions}} | Generated at {{timestamp}}*
150
+ {{else}}
151
+ No reviewer suggestions found based on the current analysis.
152
+ {{/if}}`;
153
+ }
154
+ /**
155
+ * Render a comment using the default or custom template
156
+ *
157
+ * @param result - Reviewer analysis result
158
+ * @param templatePath - Optional custom template path
159
+ * @returns Rendered comment
160
+ */
161
+ async renderComment(result, templatePath) {
162
+ let template;
163
+ if (templatePath) {
164
+ template = await this.loadTemplate(templatePath);
165
+ }
166
+ else {
167
+ template = this.compileTemplate(this.getDefaultTemplate());
168
+ }
169
+ const templateData = {
170
+ contributors: result.contributors.map(c => ({
171
+ username: c.username,
172
+ reason: c.reason,
173
+ workload: c.workload,
174
+ fte: c.fte,
175
+ })),
176
+ teamMembers: result.teamMembers.map(t => ({
177
+ username: t.username,
178
+ reason: t.reason,
179
+ workload: t.workload,
180
+ fte: t.fte,
181
+ })),
182
+ codeOwners: result.codeOwners.map(o => ({
183
+ username: o.username,
184
+ reason: o.reason,
185
+ workload: o.workload,
186
+ fte: o.fte,
187
+ })),
188
+ summary: {
189
+ totalSuggestions: result.contributors.length + result.teamMembers.length + result.codeOwners.length,
190
+ contributorCount: result.contributors.length,
191
+ teamMemberCount: result.teamMembers.length,
192
+ codeOwnerCount: result.codeOwners.length,
193
+ },
194
+ timestamp: new Date().toISOString(),
195
+ };
196
+ return template.render(templateData);
197
+ }
198
+ /**
199
+ * Validate a template file
200
+ *
201
+ * @param templatePath - Path to the template file
202
+ * @returns True if template is valid
203
+ * @throws Error if template is invalid
204
+ */
205
+ async validateTemplate(templatePath) {
206
+ const template = await this.loadTemplate(templatePath);
207
+ return template.validate();
208
+ }
209
+ /**
210
+ * Clear template cache
211
+ */
212
+ clearCache() {
213
+ this.templates.clear();
214
+ }
215
+ }
216
+ /**
217
+ * Default template engine instance
218
+ */
219
+ export const templateEngine = new TemplateEngine();
220
+ //# sourceMappingURL=template-engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-engine.js","sourceRoot":"","sources":["../../src/cli/template-engine.ts"],"names":[],"mappings":"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"}
@@ -37,17 +37,36 @@ export interface MCPServerConfig {
37
37
  *
38
38
  * Loads configuration from environment variables, applies defaults,
39
39
  * validates settings, and provides type-safe access to configuration.
40
+ *
41
+ * Supports singleton pattern to avoid multiple instantiations and duplicate logging.
40
42
  */
41
43
  export declare class ConfigService {
44
+ private static instance;
45
+ private static hasLoggedDefaults;
42
46
  private config;
43
47
  private appliedDefaults;
44
48
  /**
45
49
  * Create a new configuration service
46
50
  *
47
51
  * Automatically loads and validates configuration from environment variables.
48
- * Logs any default values that were applied.
52
+ * Logs any default values that were applied (only once per process).
53
+ *
54
+ * @param skipLogging - If true, skip logging applied defaults (useful for testing)
49
55
  */
50
- constructor();
56
+ constructor(skipLogging?: boolean);
57
+ /**
58
+ * Get the singleton instance of ConfigService
59
+ *
60
+ * This ensures configuration is only loaded and logged once per process,
61
+ * avoiding duplicate log messages when multiple components need config.
62
+ *
63
+ * @returns The shared ConfigService instance
64
+ */
65
+ static getInstance(): ConfigService;
66
+ /**
67
+ * Reset the singleton instance (primarily for testing)
68
+ */
69
+ static resetInstance(): void;
51
70
  /**
52
71
  * Get the current configuration (read-only)
53
72
  */
@@ -58,6 +77,8 @@ export declare class ConfigService {
58
77
  getAppliedDefaults(): ReadonlyMap<string, unknown>;
59
78
  /**
60
79
  * Load configuration from environment variables and validate
80
+ *
81
+ * @param skipLogging - If true, skip logging applied defaults
61
82
  */
62
83
  private loadAndValidate;
63
84
  /**
@@ -83,6 +104,7 @@ export declare class ConfigService {
83
104
  /**
84
105
  * Log which default values were applied
85
106
  * Uses console.error since MCP servers log to stderr
107
+ * Only logs once per process to avoid duplicate messages
86
108
  */
87
109
  private logAppliedDefaults;
88
110
  }
@@ -1 +1 @@
1
- {"version":3,"file":"config.service.d.ts","sourceRoot":"","sources":["../../src/config/config.service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe;IAE9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAG5B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IAGrB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC9C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAmC;IAE1D;;;;;OAKG;;IAKH;;OAEG;IACH,GAAG,IAAI,QAAQ,CAAC,eAAe,CAAC;IAIhC;;OAEG;IACH,kBAAkB,IAAI,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC;IAKlD;;OAEG;IACH,OAAO,CAAC,eAAe;IA6BvB;;OAEG;IACH,OAAO,CAAC,cAAc;IA2CtB;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;CAY3B"}
1
+ {"version":3,"file":"config.service.d.ts","sourceRoot":"","sources":["../../src/config/config.service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,eAAe;IAE9B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAG5B,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IAGrB,QAAQ,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC9C,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA8B;IACrD,OAAO,CAAC,MAAM,CAAC,iBAAiB,CAAS;IAEzC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAmC;IAE1D;;;;;;;OAOG;gBACS,WAAW,UAAQ;IAI/B;;;;;;;OAOG;IACH,MAAM,CAAC,WAAW,IAAI,aAAa;IAOnC;;OAEG;IACH,MAAM,CAAC,aAAa,IAAI,IAAI;IAK5B;;OAEG;IACH,GAAG,IAAI,QAAQ,CAAC,eAAe,CAAC;IAIhC;;OAEG;IACH,kBAAkB,IAAI,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC;IAKlD;;;;OAIG;IACH,OAAO,CAAC,eAAe;IA+BvB;;OAEG;IACH,OAAO,CAAC,cAAc;IA2CtB;;OAEG;IACH,OAAO,CAAC,eAAe;IASvB;;OAEG;IACH,OAAO,CAAC,aAAa;IASrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAepB;;OAEG;IACH,OAAO,CAAC,WAAW;IAiBnB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;CAa3B"}