@hatem427/code-guard-ci 1.0.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 (107) hide show
  1. package/.husky/pre-commit +27 -0
  2. package/LICENSE +21 -0
  3. package/README.md +646 -0
  4. package/config/angular.config.ts +223 -0
  5. package/config/guidelines.config.ts +229 -0
  6. package/config/nextjs.config.ts +160 -0
  7. package/config/react.config.ts +330 -0
  8. package/dist/config/angular.config.d.ts +15 -0
  9. package/dist/config/angular.config.d.ts.map +1 -0
  10. package/dist/config/angular.config.js +187 -0
  11. package/dist/config/angular.config.js.map +1 -0
  12. package/dist/config/guidelines.config.d.ts +63 -0
  13. package/dist/config/guidelines.config.d.ts.map +1 -0
  14. package/dist/config/guidelines.config.js +167 -0
  15. package/dist/config/guidelines.config.js.map +1 -0
  16. package/dist/config/nextjs.config.d.ts +18 -0
  17. package/dist/config/nextjs.config.d.ts.map +1 -0
  18. package/dist/config/nextjs.config.js +133 -0
  19. package/dist/config/nextjs.config.js.map +1 -0
  20. package/dist/config/react.config.d.ts +15 -0
  21. package/dist/config/react.config.d.ts.map +1 -0
  22. package/dist/config/react.config.js +287 -0
  23. package/dist/config/react.config.js.map +1 -0
  24. package/dist/scripts/auto-fix.d.ts +16 -0
  25. package/dist/scripts/auto-fix.d.ts.map +1 -0
  26. package/dist/scripts/auto-fix.js +130 -0
  27. package/dist/scripts/auto-fix.js.map +1 -0
  28. package/dist/scripts/cli.d.ts +17 -0
  29. package/dist/scripts/cli.d.ts.map +1 -0
  30. package/dist/scripts/cli.js +255 -0
  31. package/dist/scripts/cli.js.map +1 -0
  32. package/dist/scripts/delete-bypass-logs.d.ts +17 -0
  33. package/dist/scripts/delete-bypass-logs.d.ts.map +1 -0
  34. package/dist/scripts/delete-bypass-logs.js +242 -0
  35. package/dist/scripts/delete-bypass-logs.js.map +1 -0
  36. package/dist/scripts/generate-doc.d.ts +18 -0
  37. package/dist/scripts/generate-doc.d.ts.map +1 -0
  38. package/dist/scripts/generate-doc.js +300 -0
  39. package/dist/scripts/generate-doc.js.map +1 -0
  40. package/dist/scripts/generate-pr-checklist.d.ts +20 -0
  41. package/dist/scripts/generate-pr-checklist.d.ts.map +1 -0
  42. package/dist/scripts/generate-pr-checklist.js +276 -0
  43. package/dist/scripts/generate-pr-checklist.js.map +1 -0
  44. package/dist/scripts/precommit-check.d.ts +23 -0
  45. package/dist/scripts/precommit-check.d.ts.map +1 -0
  46. package/dist/scripts/precommit-check.js +331 -0
  47. package/dist/scripts/precommit-check.js.map +1 -0
  48. package/dist/scripts/set-admin-password.d.ts +14 -0
  49. package/dist/scripts/set-admin-password.d.ts.map +1 -0
  50. package/dist/scripts/set-admin-password.js +116 -0
  51. package/dist/scripts/set-admin-password.js.map +1 -0
  52. package/dist/scripts/set-bypass-password.d.ts +11 -0
  53. package/dist/scripts/set-bypass-password.d.ts.map +1 -0
  54. package/dist/scripts/set-bypass-password.js +106 -0
  55. package/dist/scripts/set-bypass-password.js.map +1 -0
  56. package/dist/scripts/utils/auto-fixer.d.ts +28 -0
  57. package/dist/scripts/utils/auto-fixer.d.ts.map +1 -0
  58. package/dist/scripts/utils/auto-fixer.js +177 -0
  59. package/dist/scripts/utils/auto-fixer.js.map +1 -0
  60. package/dist/scripts/utils/bypass-manager.d.ts +101 -0
  61. package/dist/scripts/utils/bypass-manager.d.ts.map +1 -0
  62. package/dist/scripts/utils/bypass-manager.js +496 -0
  63. package/dist/scripts/utils/bypass-manager.js.map +1 -0
  64. package/dist/scripts/utils/code-analyzer.d.ts +34 -0
  65. package/dist/scripts/utils/code-analyzer.d.ts.map +1 -0
  66. package/dist/scripts/utils/code-analyzer.js +323 -0
  67. package/dist/scripts/utils/code-analyzer.js.map +1 -0
  68. package/dist/scripts/utils/file-checker.d.ts +93 -0
  69. package/dist/scripts/utils/file-checker.d.ts.map +1 -0
  70. package/dist/scripts/utils/file-checker.js +248 -0
  71. package/dist/scripts/utils/file-checker.js.map +1 -0
  72. package/dist/scripts/utils/logger.d.ts +26 -0
  73. package/dist/scripts/utils/logger.d.ts.map +1 -0
  74. package/dist/scripts/utils/logger.js +86 -0
  75. package/dist/scripts/utils/logger.js.map +1 -0
  76. package/dist/scripts/utils/project-detector.d.ts +34 -0
  77. package/dist/scripts/utils/project-detector.d.ts.map +1 -0
  78. package/dist/scripts/utils/project-detector.js +124 -0
  79. package/dist/scripts/utils/project-detector.js.map +1 -0
  80. package/dist/scripts/utils/rule-engine.d.ts +57 -0
  81. package/dist/scripts/utils/rule-engine.d.ts.map +1 -0
  82. package/dist/scripts/utils/rule-engine.js +158 -0
  83. package/dist/scripts/utils/rule-engine.js.map +1 -0
  84. package/dist/scripts/view-bypass-log.d.ts +13 -0
  85. package/dist/scripts/view-bypass-log.d.ts.map +1 -0
  86. package/dist/scripts/view-bypass-log.js +117 -0
  87. package/dist/scripts/view-bypass-log.js.map +1 -0
  88. package/package.json +74 -0
  89. package/scripts/auto-fix.ts +115 -0
  90. package/scripts/cli.ts +246 -0
  91. package/scripts/delete-bypass-logs.ts +253 -0
  92. package/scripts/generate-doc.ts +317 -0
  93. package/scripts/generate-pr-checklist.ts +285 -0
  94. package/scripts/precommit-check.ts +349 -0
  95. package/scripts/set-admin-password.ts +90 -0
  96. package/scripts/set-bypass-password.ts +80 -0
  97. package/scripts/utils/auto-fixer.ts +181 -0
  98. package/scripts/utils/bypass-manager.ts +566 -0
  99. package/scripts/utils/code-analyzer.ts +341 -0
  100. package/scripts/utils/file-checker.ts +253 -0
  101. package/scripts/utils/logger.ts +88 -0
  102. package/scripts/utils/project-detector.ts +115 -0
  103. package/scripts/utils/rule-engine.ts +186 -0
  104. package/scripts/view-bypass-log.ts +92 -0
  105. package/templates/feature-doc-api.md +101 -0
  106. package/templates/feature-doc-service.md +113 -0
  107. package/templates/feature-doc-ui.md +91 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * ============================================================================
3
+ * project-detector.ts โ€” Automatically detect the frontend framework in use
4
+ * ============================================================================
5
+ *
6
+ * Inspects the project's package.json and file system to determine whether the
7
+ * current repository uses Angular, React, NextJS, or an unknown framework.
8
+ * This drives which set of coding rules should be enforced.
9
+ */
10
+
11
+ import * as fs from 'fs';
12
+ import * as path from 'path';
13
+
14
+ // โ”€โ”€ Supported project types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
15
+
16
+ export type ProjectType = 'angular' | 'react' | 'nextjs' | 'unknown';
17
+
18
+ export interface DetectionResult {
19
+ /** Which framework was detected */
20
+ type: ProjectType;
21
+ /** Human-readable label for logging */
22
+ label: string;
23
+ /** Root directory of the project */
24
+ rootDir: string;
25
+ /** package.json contents (parsed) */
26
+ packageJson: Record<string, any>;
27
+ }
28
+
29
+ // โ”€โ”€ Detection logic โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
30
+
31
+ /**
32
+ * Read the nearest package.json starting from `startDir` and walking up.
33
+ * Returns the parsed contents and the directory that contained it.
34
+ */
35
+ function findPackageJson(startDir: string): { dir: string; pkg: Record<string, any> } | null {
36
+ let current = path.resolve(startDir);
37
+
38
+ while (true) {
39
+ const candidate = path.join(current, 'package.json');
40
+ if (fs.existsSync(candidate)) {
41
+ try {
42
+ const content = fs.readFileSync(candidate, 'utf-8');
43
+ return { dir: current, pkg: JSON.parse(content) };
44
+ } catch {
45
+ // Malformed JSON โ€” keep walking
46
+ }
47
+ }
48
+
49
+ const parent = path.dirname(current);
50
+ if (parent === current) break; // reached filesystem root
51
+ current = parent;
52
+ }
53
+
54
+ return null;
55
+ }
56
+
57
+ /**
58
+ * Check whether a dependency name exists in `dependencies` or
59
+ * `devDependencies` of the given package.json object.
60
+ */
61
+ function hasDep(pkg: Record<string, any>, name: string): boolean {
62
+ return !!(pkg.dependencies?.[name] || pkg.devDependencies?.[name]);
63
+ }
64
+
65
+ /**
66
+ * Detect the project type based on the nearest package.json.
67
+ *
68
+ * Priority order (first match wins):
69
+ * 1. NextJS โ€” has `next` as a dependency
70
+ * 2. Angular โ€” has `@angular/core` as a dependency
71
+ * 3. React โ€” has `react` as a dependency
72
+ * 4. Unknown โ€” none of the above
73
+ *
74
+ * NextJS is checked first because it also pulls in React, so we want
75
+ * the more specific framework to win.
76
+ */
77
+ export function detectProject(startDir: string = process.cwd()): DetectionResult {
78
+ const result = findPackageJson(startDir);
79
+
80
+ if (!result) {
81
+ return {
82
+ type: 'unknown',
83
+ label: 'Unknown Project',
84
+ rootDir: startDir,
85
+ packageJson: {},
86
+ };
87
+ }
88
+
89
+ const { dir, pkg } = result;
90
+
91
+ // NextJS check (must come before React โ€” NextJS depends on React)
92
+ if (hasDep(pkg, 'next')) {
93
+ return { type: 'nextjs', label: 'Next.js', rootDir: dir, packageJson: pkg };
94
+ }
95
+
96
+ // Angular check
97
+ if (hasDep(pkg, '@angular/core')) {
98
+ return { type: 'angular', label: 'Angular', rootDir: dir, packageJson: pkg };
99
+ }
100
+
101
+ // React check
102
+ if (hasDep(pkg, 'react')) {
103
+ return { type: 'react', label: 'React', rootDir: dir, packageJson: pkg };
104
+ }
105
+
106
+ // Fallback โ€” additional heuristics
107
+ if (fs.existsSync(path.join(dir, 'angular.json'))) {
108
+ return { type: 'angular', label: 'Angular (heuristic)', rootDir: dir, packageJson: pkg };
109
+ }
110
+ if (fs.existsSync(path.join(dir, 'next.config.js')) || fs.existsSync(path.join(dir, 'next.config.mjs'))) {
111
+ return { type: 'nextjs', label: 'Next.js (heuristic)', rootDir: dir, packageJson: pkg };
112
+ }
113
+
114
+ return { type: 'unknown', label: 'Unknown Project', rootDir: dir, packageJson: pkg };
115
+ }
@@ -0,0 +1,186 @@
1
+ /**
2
+ * ============================================================================
3
+ * rule-engine.ts โ€” Orchestrates rule execution against a set of files
4
+ * ============================================================================
5
+ *
6
+ * The rule engine is the core processor. It takes a list of files and a list
7
+ * of rules, then runs each rule against each applicable file. Results are
8
+ * collected into a structured report.
9
+ */
10
+
11
+ import { Rule, Severity } from '../../config/guidelines.config';
12
+ import { FileInfo, findMatches, hasInlineSuppression } from './file-checker';
13
+ import * as logger from './logger';
14
+
15
+ // โ”€โ”€ Result types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
16
+
17
+ export interface Violation {
18
+ /** The file where the violation was found */
19
+ file: string;
20
+ /** 1-based line number (null for file-level violations) */
21
+ line: number | null;
22
+ /** The rule that was violated */
23
+ ruleId: string;
24
+ /** Human-readable label */
25
+ ruleLabel: string;
26
+ /** Description of the violation */
27
+ message: string;
28
+ /** How severe is this? */
29
+ severity: Severity;
30
+ /** Category for grouping */
31
+ category: string;
32
+ }
33
+
34
+ export interface RuleEngineReport {
35
+ /** All violations found */
36
+ violations: Violation[];
37
+ /** Total number of error-severity violations */
38
+ errorCount: number;
39
+ /** Total number of warning-severity violations */
40
+ warningCount: number;
41
+ /** Total number of info-severity violations */
42
+ infoCount: number;
43
+ /** How many files were checked */
44
+ filesChecked: number;
45
+ /** How many rules were executed */
46
+ rulesExecuted: number;
47
+ /** Was the check bypassed? */
48
+ bypassed: boolean;
49
+ }
50
+
51
+ // โ”€โ”€ Engine โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
52
+
53
+ /**
54
+ * Run all `rules` against all `files` and collect a report.
55
+ *
56
+ * @param files - The list of files to check (usually staged files).
57
+ * @param rules - The list of rules to apply.
58
+ * @param verbose - If true, logs each rule as it runs.
59
+ * @returns A structured report of all findings.
60
+ */
61
+ export function executeRules(
62
+ files: FileInfo[],
63
+ rules: Rule[],
64
+ verbose: boolean = false
65
+ ): RuleEngineReport {
66
+ const violations: Violation[] = [];
67
+ let rulesExecuted = 0;
68
+
69
+ for (const rule of rules) {
70
+ rulesExecuted++;
71
+
72
+ if (verbose) {
73
+ logger.dim(`Running rule: ${rule.id} โ€” ${rule.label}`);
74
+ }
75
+
76
+ for (const file of files) {
77
+ // โ”€โ”€ Extension filter โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
78
+ if (
79
+ rule.fileExtensions.length > 0 &&
80
+ !rule.fileExtensions.includes(file.extension)
81
+ ) {
82
+ continue;
83
+ }
84
+
85
+ // โ”€โ”€ Regex-based check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
86
+ if (rule.pattern) {
87
+ const matches = findMatches(file, rule.pattern);
88
+
89
+ for (const match of matches) {
90
+ // Check for inline suppression
91
+ if (hasInlineSuppression(file, rule.id, match.line)) {
92
+ continue;
93
+ }
94
+
95
+ violations.push({
96
+ file: file.relativePath,
97
+ line: match.line,
98
+ ruleId: rule.id,
99
+ ruleLabel: rule.label,
100
+ message: `${rule.description} (found: "${match.text.substring(0, 80)}")`,
101
+ severity: rule.severity,
102
+ category: rule.category,
103
+ });
104
+ }
105
+ }
106
+
107
+ // โ”€โ”€ Custom check โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
108
+ if (rule.customCheck) {
109
+ const customViolations = rule.customCheck(file);
110
+
111
+ for (const cv of customViolations) {
112
+ // Check for inline suppression (if there's a line number)
113
+ if (cv.line && hasInlineSuppression(file, rule.id, cv.line)) {
114
+ continue;
115
+ }
116
+
117
+ violations.push({
118
+ file: file.relativePath,
119
+ line: cv.line,
120
+ ruleId: rule.id,
121
+ ruleLabel: rule.label,
122
+ message: cv.message,
123
+ severity: rule.severity,
124
+ category: rule.category,
125
+ });
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ // โ”€โ”€ Count by severity โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
132
+
133
+ const errorCount = violations.filter((v) => v.severity === 'error').length;
134
+ const warningCount = violations.filter((v) => v.severity === 'warning').length;
135
+ const infoCount = violations.filter((v) => v.severity === 'info').length;
136
+
137
+ return {
138
+ violations,
139
+ errorCount,
140
+ warningCount,
141
+ infoCount,
142
+ filesChecked: files.length,
143
+ rulesExecuted,
144
+ bypassed: false,
145
+ };
146
+ }
147
+
148
+ /**
149
+ * Display a pretty-printed report in the terminal.
150
+ */
151
+ export function printReport(report: RuleEngineReport): void {
152
+ if (report.bypassed) {
153
+ logger.warn('Rules bypassed โ€” skipping checks.');
154
+ return;
155
+ }
156
+
157
+ logger.header(`Code Guardian Report โ€” ${report.filesChecked} file(s), ${report.rulesExecuted} rule(s)`);
158
+
159
+ if (report.violations.length === 0) {
160
+ logger.success('No violations found!');
161
+ logger.summary(0, 0);
162
+ return;
163
+ }
164
+
165
+ // Group violations by category
166
+ const byCategory = new Map<string, Violation[]>();
167
+ for (const v of report.violations) {
168
+ const existing = byCategory.get(v.category) || [];
169
+ existing.push(v);
170
+ byCategory.set(v.category, existing);
171
+ }
172
+
173
+ for (const [category, items] of byCategory) {
174
+ console.log(`\n ๐Ÿ“‚ ${category}`);
175
+
176
+ for (const v of items) {
177
+ logger.violation(v.file, v.line, v.ruleId, v.message);
178
+ }
179
+ }
180
+
181
+ logger.summary(report.errorCount, report.warningCount);
182
+
183
+ if (report.infoCount > 0) {
184
+ logger.info(`${report.infoCount} informational notice(s) โ€” consider addressing them.`);
185
+ }
186
+ }
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env ts-node
2
+ /**
3
+ * ============================================================================
4
+ * view-bypass-log.ts โ€” View bypass audit log
5
+ * ============================================================================
6
+ *
7
+ * Usage:
8
+ * npm run view-bypass-log
9
+ * npm run view-bypass-log -- --author="john@example.com"
10
+ * npm run view-bypass-log -- --days=7
11
+ */
12
+
13
+ import { generateBypassReport, getBypassesByAuthor, getRecentBypasses } from './utils/bypass-manager';
14
+ import * as logger from './utils/logger';
15
+
16
+ function parseArgs(): { author?: string; days?: number } {
17
+ const args = process.argv.slice(2);
18
+ const opts: { author?: string; days?: number } = {};
19
+
20
+ for (const arg of args) {
21
+ const [key, ...valueParts] = arg.replace(/^--/, '').split('=');
22
+ const value = valueParts.join('=').replace(/^["']|["']$/g, '');
23
+
24
+ switch (key) {
25
+ case 'author':
26
+ opts.author = value;
27
+ break;
28
+ case 'days':
29
+ opts.days = parseInt(value, 10);
30
+ break;
31
+ }
32
+ }
33
+
34
+ return opts;
35
+ }
36
+
37
+ function main() {
38
+ logger.header('๐Ÿ“Š Code Guardian โ€” Bypass Audit Log');
39
+
40
+ const opts = parseArgs();
41
+
42
+ if (opts.author) {
43
+ logger.info(`Filtering by author: ${opts.author}`);
44
+ const entries = getBypassesByAuthor(opts.author);
45
+
46
+ if (entries.length === 0) {
47
+ logger.info(`No bypass entries found for ${opts.author}`);
48
+ return;
49
+ }
50
+
51
+ console.log(`\nFound ${entries.length} bypass(es) by ${opts.author}:\n`);
52
+ for (const entry of entries) {
53
+ const date = new Date(entry.timestamp).toLocaleString();
54
+ console.log(`โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”`);
55
+ console.log(`๐Ÿ“… ${date}`);
56
+ console.log(`๐Ÿ“ Reason: ${entry.reason}`);
57
+ console.log(`๐ŸŒฟ Branch: ${entry.branch}`);
58
+ console.log(`๐Ÿ“ Files: ${entry.files.length} file(s)`);
59
+ console.log(`๐Ÿ”‘ Method: ${entry.method}`);
60
+ if (entry.commitHash) {
61
+ console.log(`๐Ÿ”— Commit: ${entry.commitHash}`);
62
+ }
63
+ console.log('');
64
+ }
65
+ } else if (opts.days) {
66
+ logger.info(`Showing bypasses from last ${opts.days} day(s)`);
67
+ const entries = getRecentBypasses(opts.days);
68
+
69
+ if (entries.length === 0) {
70
+ logger.info(`No bypass entries found in the last ${opts.days} day(s)`);
71
+ return;
72
+ }
73
+
74
+ console.log(`\nFound ${entries.length} bypass(es) in the last ${opts.days} day(s):\n`);
75
+ for (const entry of entries) {
76
+ const date = new Date(entry.timestamp).toLocaleString();
77
+ console.log(`โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”`);
78
+ console.log(`๐Ÿ‘ค ${entry.author} <${entry.email}>`);
79
+ console.log(`๐Ÿ“… ${date}`);
80
+ console.log(`๐Ÿ“ Reason: ${entry.reason}`);
81
+ console.log(`๐ŸŒฟ Branch: ${entry.branch}`);
82
+ console.log(`๐Ÿ”‘ Method: ${entry.method}`);
83
+ console.log('');
84
+ }
85
+ } else {
86
+ // Show full report
87
+ const report = generateBypassReport();
88
+ console.log(report);
89
+ }
90
+ }
91
+
92
+ main();
@@ -0,0 +1,101 @@
1
+ # {{FEATURE_TITLE}} โ€” API
2
+
3
+ > **Type**: API Endpoint / Route
4
+ > **Created**: {{DATE}}
5
+ > **Author**: {{AUTHOR}}
6
+ > **Status**: ๐Ÿšง Draft
7
+
8
+ ---
9
+
10
+ ## ๐Ÿ“ Description
11
+
12
+ {{DESCRIPTION}}
13
+
14
+ ## ๐ŸŒ Endpoint
15
+
16
+ | Method | Path | Auth Required |
17
+ | ------ | ----------------------- | ------------- |
18
+ | `GET` | `/api/{{FEATURE_NAME}}` | โœ… Yes |
19
+ | `POST` | `/api/{{FEATURE_NAME}}` | โœ… Yes |
20
+ | _TODO_ | _TODO_ | _TODO_ |
21
+
22
+ ## ๐Ÿ“ฅ Request
23
+
24
+ ### Headers
25
+
26
+ | Header | Value | Required |
27
+ | --------------- | ------------------ | -------- |
28
+ | `Authorization` | `Bearer <token>` | Yes |
29
+ | `Content-Type` | `application/json` | Yes |
30
+
31
+ ### Query Parameters (GET)
32
+
33
+ | Param | Type | Default | Description |
34
+ | -------- | -------- | ------- | ----------------- |
35
+ | `page` | `number` | `1` | Page number |
36
+ | `limit` | `number` | `20` | Items per page |
37
+ | `search` | `string` | `""` | Search query |
38
+ | _TODO_ | _TODO_ | _TODO_ | _Add more params_ |
39
+
40
+ ### Request Body (POST/PUT)
41
+
42
+ ```typescript
43
+ interface {{FEATURE_TITLE}}Request {
44
+ // TODO: Define request body
45
+ name: string;
46
+ description?: string;
47
+ }
48
+ ```
49
+
50
+ ### Example Request
51
+
52
+ ```bash
53
+ curl -X POST /api/{{FEATURE_NAME}} \
54
+ -H "Authorization: Bearer <token>" \
55
+ -H "Content-Type: application/json" \
56
+ -d '{"name": "example"}'
57
+ ```
58
+
59
+ ## ๐Ÿ“ค Response
60
+
61
+ ### Success Response (200)
62
+
63
+ ```typescript
64
+ interface {{FEATURE_TITLE}}Response {
65
+ success: boolean;
66
+ data: {
67
+ id: string;
68
+ // TODO: Define response shape
69
+ };
70
+ meta?: {
71
+ total: number;
72
+ page: number;
73
+ limit: number;
74
+ };
75
+ }
76
+ ```
77
+
78
+ ### Error Responses
79
+
80
+ | Status | Code | Description |
81
+ | ------ | ------------------ | ------------------------ |
82
+ | `400` | `VALIDATION_ERROR` | Invalid request body |
83
+ | `401` | `UNAUTHORIZED` | Missing or invalid token |
84
+ | `404` | `NOT_FOUND` | Resource not found |
85
+ | `500` | `INTERNAL_ERROR` | Server error |
86
+
87
+ ## ๐Ÿ”’ Authorization
88
+
89
+ - Requires authenticated user
90
+ - Role-based access: _TODO: define roles_
91
+ - Rate limiting: _TODO: define limits_
92
+
93
+ ## ๐Ÿ“ Notes
94
+
95
+ - _TODO: Add implementation notes_
96
+ - _TODO: Add links to related endpoints_
97
+ - _TODO: Add caching strategy if applicable_
98
+
99
+ ---
100
+
101
+ _Generated by Code Guardian โ€” {{DOC_TYPE}} template_
@@ -0,0 +1,113 @@
1
+ # {{FEATURE_TITLE}} โ€” Service
2
+
3
+ > **Type**: Service / Business Logic
4
+ > **Created**: {{DATE}}
5
+ > **Author**: {{AUTHOR}}
6
+ > **Status**: ๐Ÿšง Draft
7
+
8
+ ---
9
+
10
+ ## ๐Ÿ“ Description
11
+
12
+ {{DESCRIPTION}}
13
+
14
+ ## ๐Ÿ—๏ธ Architecture
15
+
16
+ ### Location
17
+
18
+ ```
19
+ src/
20
+ โ”œโ”€โ”€ services/
21
+ โ”‚ โ””โ”€โ”€ {{FEATURE_NAME}}/
22
+ โ”‚ โ”œโ”€โ”€ {{FEATURE_NAME}}.service.ts # Main service
23
+ โ”‚ โ”œโ”€โ”€ {{FEATURE_NAME}}.types.ts # TypeScript interfaces
24
+ โ”‚ โ”œโ”€โ”€ {{FEATURE_NAME}}.utils.ts # Helper functions
25
+ โ”‚ โ””โ”€โ”€ {{FEATURE_NAME}}.spec.ts # Unit tests
26
+ ```
27
+
28
+ ### Dependency Graph
29
+
30
+ ```
31
+ {{FEATURE_TITLE}}Service
32
+ โ”œโ”€โ”€ HttpClient / fetch
33
+ โ”œโ”€โ”€ AuthService (injection)
34
+ โ”œโ”€โ”€ LoggingService (injection)
35
+ โ””โ”€โ”€ ConfigService (injection)
36
+ ```
37
+
38
+ ## ๐Ÿš€ Usage
39
+
40
+ ### Angular (Injectable)
41
+
42
+ ```typescript
43
+ @Injectable({ providedIn: 'root' })
44
+ export class {{FEATURE_TITLE}}Service {
45
+ private readonly http = inject(HttpClient);
46
+
47
+ getAll(): Observable<{{FEATURE_TITLE}}[]> {
48
+ return this.http.get<{{FEATURE_TITLE}}[]>('/api/{{FEATURE_NAME}}');
49
+ }
50
+ }
51
+ ```
52
+
53
+ ### React / Next.js (Hook or Module)
54
+
55
+ ```typescript
56
+ export function use{{FEATURE_TITLE}}() {
57
+ const [data, setData] = useState<{{FEATURE_TITLE}}[]>([]);
58
+ const [loading, setLoading] = useState(true);
59
+
60
+ useEffect(() => {
61
+ fetch('/api/{{FEATURE_NAME}}')
62
+ .then(res => res.json())
63
+ .then(setData)
64
+ .finally(() => setLoading(false));
65
+ }, []);
66
+
67
+ return { data, loading };
68
+ }
69
+ ```
70
+
71
+ ## ๐Ÿ“ฅ Inputs / Parameters
72
+
73
+ | Method | Params | Return Type | Description |
74
+ | ----------- | ------------------- | --------------------------- | ------------------- |
75
+ | `getAll()` | `filters?: Filters` | `Observable<T[]>` / `T[]` | Fetch all records |
76
+ | `getById()` | `id: string` | `Observable<T>` / `T` | Fetch single record |
77
+ | `create()` | `data: CreateDTO` | `Observable<T>` / `T` | Create new record |
78
+ | `update()` | `id, data: Partial` | `Observable<T>` / `T` | Update existing |
79
+ | `delete()` | `id: string` | `Observable<void>` / `void` | Delete record |
80
+
81
+ ## ๐Ÿ“ค Outputs / Events
82
+
83
+ | Event | Payload | Description |
84
+ | ----------- | -------- | ------------------------------- |
85
+ | `onCreated` | `T` | Emitted after successful create |
86
+ | `onUpdated` | `T` | Emitted after successful update |
87
+ | `onDeleted` | `string` | Emitted after successful delete |
88
+ | `onError` | `Error` | Emitted on any error |
89
+
90
+ ## ๐Ÿงช Testing
91
+
92
+ ```typescript
93
+ describe("{{FEATURE_TITLE}}Service", () => {
94
+ it("should fetch all records", async () => {
95
+ // TODO: Add test implementation
96
+ });
97
+
98
+ it("should handle errors gracefully", async () => {
99
+ // TODO: Add error handling tests
100
+ });
101
+ });
102
+ ```
103
+
104
+ ## ๐Ÿ“ Notes
105
+
106
+ - _TODO: Add state management considerations_
107
+ - _TODO: Add caching strategy_
108
+ - _TODO: Add retry/error-handling approach_
109
+ - _TODO: Add performance considerations_
110
+
111
+ ---
112
+
113
+ _Generated by Code Guardian โ€” {{DOC_TYPE}} template_
@@ -0,0 +1,91 @@
1
+ # {{FEATURE_TITLE}}
2
+
3
+ > **Type**: UI Component
4
+ > **Created**: {{DATE}}
5
+ > **Author**: {{AUTHOR}}
6
+ > **Status**: ๐Ÿšง Draft
7
+
8
+ ---
9
+
10
+ ## ๐Ÿ“ Description
11
+
12
+ {{DESCRIPTION}}
13
+
14
+ ## ๐Ÿ–ผ๏ธ Visual Reference
15
+
16
+ <!-- Add screenshots or Figma links here -->
17
+
18
+ _TODO: Add screenshots_
19
+
20
+ ## ๐Ÿš€ Usage
21
+
22
+ ### Basic Usage
23
+
24
+ ```html
25
+ <!-- Angular -->
26
+ <app-{{FEATURE_NAME}}></app-{{FEATURE_NAME}}>
27
+
28
+ <!-- React / Next.js -->
29
+ <{{FEATURE_TITLE}} />
30
+ ```
31
+
32
+ ### With Options
33
+
34
+ ```html
35
+ <!-- Angular -->
36
+ <app-{{FEATURE_NAME}}
37
+ [variant]="'primary'"
38
+ [size]="'md'"
39
+ (action)="onAction($event)"
40
+ >
41
+ </app-{{FEATURE_NAME}}>
42
+
43
+ <!-- React / Next.js -->
44
+ <{{FEATURE_TITLE}} variant="primary" size="md" onAction={handleAction} />
45
+ ```
46
+
47
+ ## ๐Ÿ“ฅ Inputs / Props
48
+
49
+ | Name | Type | Default | Description |
50
+ | ---------- | --------- | ----------- | ---------------------------------- |
51
+ | `variant` | `string` | `'default'` | Visual variant: primary, secondary |
52
+ | `size` | `string` | `'md'` | Size: sm, md, lg |
53
+ | `disabled` | `boolean` | `false` | Whether the component is disabled |
54
+ | _TODO_ | _TODO_ | _TODO_ | _Add more inputs as needed_ |
55
+
56
+ ## ๐Ÿ“ค Outputs / Events
57
+
58
+ | Name | Payload | Description |
59
+ | -------- | ------- | ------------------------------- |
60
+ | `action` | `Event` | Emitted when the user interacts |
61
+ | _TODO_ | _TODO_ | _Add more outputs as needed_ |
62
+
63
+ ## ๐ŸŽจ Styling
64
+
65
+ - Uses **Tailwind CSS** utility classes
66
+ - Supports dark mode via `dark:` variants
67
+ - Responsive breakpoints: `sm`, `md`, `lg`, `xl`
68
+
69
+ ### CSS Custom Properties
70
+
71
+ ```css
72
+ /* Override defaults in parent context */
73
+ --{{FEATURE_NAME}}-bg: theme('colors.white');
74
+ --{{FEATURE_NAME}}-border: theme('colors.gray.200');
75
+ ```
76
+
77
+ ## โ™ฟ Accessibility
78
+
79
+ - [ ] Keyboard navigable
80
+ - [ ] Screen reader compatible (aria labels)
81
+ - [ ] Focus indicators visible
82
+ - [ ] Color contrast meets WCAG AA
83
+
84
+ ## ๐Ÿ“ Notes
85
+
86
+ - _TODO: Add implementation notes, caveats, or known limitations._
87
+ - _TODO: Add links to related components or documentation._
88
+
89
+ ---
90
+
91
+ _Generated by Code Guardian โ€” {{DOC_TYPE}} template_