thrivekit 2.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 (164) hide show
  1. package/.claude/commands/explain.md +114 -0
  2. package/.claude/commands/idea.md +370 -0
  3. package/.claude/commands/my-dna.md +122 -0
  4. package/.claude/commands/prd.md +286 -0
  5. package/.claude/commands/review.md +167 -0
  6. package/.claude/commands/sign.md +32 -0
  7. package/.claude/commands/styleguide.md +450 -0
  8. package/.claude/commands/tour.md +301 -0
  9. package/.claude/commands/vibe-check.md +116 -0
  10. package/.claude/commands/vibe-help.md +47 -0
  11. package/.claude/commands/vibe-list.md +203 -0
  12. package/.claude/settings.json +75 -0
  13. package/.claude/settings.local.json +12 -0
  14. package/.pre-commit-hooks.yaml +102 -0
  15. package/LICENSE +21 -0
  16. package/README.md +214 -0
  17. package/bin/postinstall.sh +29 -0
  18. package/bin/ralph.sh +171 -0
  19. package/bin/thrivekit.sh +24 -0
  20. package/bin/vibe-check.js +19 -0
  21. package/dist/checks/check-any-types.d.ts +6 -0
  22. package/dist/checks/check-any-types.d.ts.map +1 -0
  23. package/dist/checks/check-any-types.js +73 -0
  24. package/dist/checks/check-any-types.js.map +1 -0
  25. package/dist/checks/check-commented-code.d.ts +6 -0
  26. package/dist/checks/check-commented-code.d.ts.map +1 -0
  27. package/dist/checks/check-commented-code.js +81 -0
  28. package/dist/checks/check-commented-code.js.map +1 -0
  29. package/dist/checks/check-console-error.d.ts +6 -0
  30. package/dist/checks/check-console-error.d.ts.map +1 -0
  31. package/dist/checks/check-console-error.js +41 -0
  32. package/dist/checks/check-console-error.js.map +1 -0
  33. package/dist/checks/check-debug-statements.d.ts +6 -0
  34. package/dist/checks/check-debug-statements.d.ts.map +1 -0
  35. package/dist/checks/check-debug-statements.js +120 -0
  36. package/dist/checks/check-debug-statements.js.map +1 -0
  37. package/dist/checks/check-deep-nesting.d.ts +6 -0
  38. package/dist/checks/check-deep-nesting.d.ts.map +1 -0
  39. package/dist/checks/check-deep-nesting.js +116 -0
  40. package/dist/checks/check-deep-nesting.js.map +1 -0
  41. package/dist/checks/check-docker-platform.d.ts +6 -0
  42. package/dist/checks/check-docker-platform.d.ts.map +1 -0
  43. package/dist/checks/check-docker-platform.js +42 -0
  44. package/dist/checks/check-docker-platform.js.map +1 -0
  45. package/dist/checks/check-dry-violations.d.ts +6 -0
  46. package/dist/checks/check-dry-violations.d.ts.map +1 -0
  47. package/dist/checks/check-dry-violations.js +124 -0
  48. package/dist/checks/check-dry-violations.js.map +1 -0
  49. package/dist/checks/check-empty-catch.d.ts +6 -0
  50. package/dist/checks/check-empty-catch.d.ts.map +1 -0
  51. package/dist/checks/check-empty-catch.js +111 -0
  52. package/dist/checks/check-empty-catch.js.map +1 -0
  53. package/dist/checks/check-function-length.d.ts +6 -0
  54. package/dist/checks/check-function-length.d.ts.map +1 -0
  55. package/dist/checks/check-function-length.js +152 -0
  56. package/dist/checks/check-function-length.js.map +1 -0
  57. package/dist/checks/check-hardcoded-ai-models.d.ts +10 -0
  58. package/dist/checks/check-hardcoded-ai-models.d.ts.map +1 -0
  59. package/dist/checks/check-hardcoded-ai-models.js +102 -0
  60. package/dist/checks/check-hardcoded-ai-models.js.map +1 -0
  61. package/dist/checks/check-hardcoded-urls.d.ts +6 -0
  62. package/dist/checks/check-hardcoded-urls.d.ts.map +1 -0
  63. package/dist/checks/check-hardcoded-urls.js +124 -0
  64. package/dist/checks/check-hardcoded-urls.js.map +1 -0
  65. package/dist/checks/check-magic-numbers.d.ts +6 -0
  66. package/dist/checks/check-magic-numbers.d.ts.map +1 -0
  67. package/dist/checks/check-magic-numbers.js +116 -0
  68. package/dist/checks/check-magic-numbers.js.map +1 -0
  69. package/dist/checks/check-secrets.d.ts +6 -0
  70. package/dist/checks/check-secrets.d.ts.map +1 -0
  71. package/dist/checks/check-secrets.js +138 -0
  72. package/dist/checks/check-secrets.js.map +1 -0
  73. package/dist/checks/check-snake-case-ts.d.ts +6 -0
  74. package/dist/checks/check-snake-case-ts.d.ts.map +1 -0
  75. package/dist/checks/check-snake-case-ts.js +78 -0
  76. package/dist/checks/check-snake-case-ts.js.map +1 -0
  77. package/dist/checks/check-todo-fixme.d.ts +6 -0
  78. package/dist/checks/check-todo-fixme.d.ts.map +1 -0
  79. package/dist/checks/check-todo-fixme.js +41 -0
  80. package/dist/checks/check-todo-fixme.js.map +1 -0
  81. package/dist/checks/check-unsafe-html.d.ts +6 -0
  82. package/dist/checks/check-unsafe-html.d.ts.map +1 -0
  83. package/dist/checks/check-unsafe-html.js +101 -0
  84. package/dist/checks/check-unsafe-html.js.map +1 -0
  85. package/dist/checks/index.d.ts +30 -0
  86. package/dist/checks/index.d.ts.map +1 -0
  87. package/dist/checks/index.js +57 -0
  88. package/dist/checks/index.js.map +1 -0
  89. package/dist/cli.d.ts +13 -0
  90. package/dist/cli.d.ts.map +1 -0
  91. package/dist/cli.js +206 -0
  92. package/dist/cli.js.map +1 -0
  93. package/dist/index.d.ts +9 -0
  94. package/dist/index.d.ts.map +1 -0
  95. package/dist/index.js +10 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/utils/file-reader.d.ts +24 -0
  98. package/dist/utils/file-reader.d.ts.map +1 -0
  99. package/dist/utils/file-reader.js +140 -0
  100. package/dist/utils/file-reader.js.map +1 -0
  101. package/dist/utils/patterns.d.ts +27 -0
  102. package/dist/utils/patterns.d.ts.map +1 -0
  103. package/dist/utils/patterns.js +84 -0
  104. package/dist/utils/patterns.js.map +1 -0
  105. package/dist/utils/reporters.d.ts +21 -0
  106. package/dist/utils/reporters.d.ts.map +1 -0
  107. package/dist/utils/reporters.js +115 -0
  108. package/dist/utils/reporters.js.map +1 -0
  109. package/dist/utils/types.d.ts +71 -0
  110. package/dist/utils/types.d.ts.map +1 -0
  111. package/dist/utils/types.js +5 -0
  112. package/dist/utils/types.js.map +1 -0
  113. package/package.json +82 -0
  114. package/ralph/api.sh +210 -0
  115. package/ralph/backup.sh +838 -0
  116. package/ralph/browser-verify/README.md +135 -0
  117. package/ralph/browser-verify/verify.ts +450 -0
  118. package/ralph/checks/check-fastapi-responses.py +155 -0
  119. package/ralph/hooks/hooks-config.json +72 -0
  120. package/ralph/hooks/inject-context.sh +44 -0
  121. package/ralph/hooks/install.sh +207 -0
  122. package/ralph/hooks/log-tools.sh +45 -0
  123. package/ralph/hooks/protect-prd.sh +27 -0
  124. package/ralph/hooks/save-learnings.sh +36 -0
  125. package/ralph/hooks/warn-debug.sh +54 -0
  126. package/ralph/hooks/warn-empty-catch.sh +63 -0
  127. package/ralph/hooks/warn-secrets.sh +89 -0
  128. package/ralph/hooks/warn-urls.sh +77 -0
  129. package/ralph/init.sh +388 -0
  130. package/ralph/loop.sh +570 -0
  131. package/ralph/playwright.sh +238 -0
  132. package/ralph/prd.sh +295 -0
  133. package/ralph/setup/feature-tour.sh +155 -0
  134. package/ralph/setup/quick-setup.sh +239 -0
  135. package/ralph/setup/tutorial.sh +159 -0
  136. package/ralph/setup/ui.sh +136 -0
  137. package/ralph/setup.sh +353 -0
  138. package/ralph/signs.sh +150 -0
  139. package/ralph/utils.sh +682 -0
  140. package/ralph/verify/browser.sh +324 -0
  141. package/ralph/verify/lint.sh +363 -0
  142. package/ralph/verify/review.sh +164 -0
  143. package/ralph/verify/tests.sh +81 -0
  144. package/ralph/verify.sh +224 -0
  145. package/templates/PROMPT.md +235 -0
  146. package/templates/config/fullstack.json +86 -0
  147. package/templates/config/go.json +81 -0
  148. package/templates/config/minimal.json +76 -0
  149. package/templates/config/node.json +81 -0
  150. package/templates/config/python.json +81 -0
  151. package/templates/config/rust.json +81 -0
  152. package/templates/examples/CLAUDE-django.md +174 -0
  153. package/templates/examples/CLAUDE-fastapi.md +270 -0
  154. package/templates/examples/CLAUDE-fastmcp.md +352 -0
  155. package/templates/examples/CLAUDE-fullstack.md +256 -0
  156. package/templates/examples/CLAUDE-node.md +246 -0
  157. package/templates/examples/CLAUDE-react.md +138 -0
  158. package/templates/optional/cursorrules.template +147 -0
  159. package/templates/optional/eslint.config.js +34 -0
  160. package/templates/optional/lint-staged.config.js +34 -0
  161. package/templates/optional/ruff.toml +125 -0
  162. package/templates/optional/vibe-check.yml +116 -0
  163. package/templates/optional/vscode-settings.json +127 -0
  164. package/templates/signs.json +46 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Check for DRY (Don't Repeat Yourself) violations - duplicated code blocks
3
+ */
4
+ // Minimum number of similar lines to consider a duplicate
5
+ const MIN_DUPLICATE_LINES = 5;
6
+ // Minimum similarity threshold (0-1)
7
+ const SIMILARITY_THRESHOLD = 0.85;
8
+ // Paths that indicate frontend component files (skip these - too many false positives)
9
+ const FRONTEND_PATH_PATTERNS = [
10
+ /\/components\//i,
11
+ /\/pages\//i,
12
+ /\/views\//i,
13
+ /\/layouts\//i,
14
+ /\/ui\//i,
15
+ /\.styled\./i,
16
+ /\.styles\./i,
17
+ /styleguide/i,
18
+ ];
19
+ export const checkDryViolations = {
20
+ id: 'dry',
21
+ name: 'Check DRY Violations',
22
+ description: 'Detect duplicated code blocks that should be extracted',
23
+ severity: 'warning',
24
+ // Skip JSX/TSX - too many false positives with similar component patterns
25
+ fileTypes: ['js', 'ts', 'mjs', 'cjs', 'py'],
26
+ check(context) {
27
+ const results = [];
28
+ // Skip frontend component files
29
+ if (FRONTEND_PATH_PATTERNS.some((pattern) => pattern.test(context.filePath))) {
30
+ return results;
31
+ }
32
+ const lines = context.content.split('\n');
33
+ // Normalize lines for comparison (remove whitespace, comments)
34
+ const normalizedLines = lines.map((line, index) => ({
35
+ original: line,
36
+ normalized: normalizeLine(line, context.extension),
37
+ lineNum: index + 1,
38
+ }));
39
+ // Filter out empty/trivial lines
40
+ const significantLines = normalizedLines.filter((l) => l.normalized.length > 10 && !isTrivialLine(l.normalized));
41
+ // Find duplicate blocks using a sliding window approach
42
+ const reportedBlocks = new Set();
43
+ for (let i = 0; i < significantLines.length - MIN_DUPLICATE_LINES; i++) {
44
+ // Create a "fingerprint" of the next N lines
45
+ const block1 = significantLines.slice(i, i + MIN_DUPLICATE_LINES);
46
+ const fingerprint1 = block1.map((l) => l.normalized).join('\n');
47
+ // Look for similar blocks later in the file
48
+ for (let j = i + MIN_DUPLICATE_LINES; j < significantLines.length - MIN_DUPLICATE_LINES; j++) {
49
+ const block2 = significantLines.slice(j, j + MIN_DUPLICATE_LINES);
50
+ const fingerprint2 = block2.map((l) => l.normalized).join('\n');
51
+ // Check similarity
52
+ const similarity = calculateSimilarity(fingerprint1, fingerprint2);
53
+ if (similarity >= SIMILARITY_THRESHOLD) {
54
+ // Create a unique key for this duplicate pair
55
+ const blockKey = `${block1[0].lineNum}-${block2[0].lineNum}`;
56
+ if (!reportedBlocks.has(blockKey)) {
57
+ reportedBlocks.add(blockKey);
58
+ results.push({
59
+ line: block1[0].lineNum,
60
+ column: 0,
61
+ message: `Similar code block found at line ${block2[0].lineNum} - consider extracting to a function`,
62
+ severity: 'warning',
63
+ ruleId: 'dry/duplicate-block',
64
+ });
65
+ }
66
+ }
67
+ }
68
+ }
69
+ return results;
70
+ },
71
+ };
72
+ function normalizeLine(line, extension) {
73
+ let normalized = line;
74
+ // Remove comments
75
+ if (['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'].includes(extension)) {
76
+ normalized = normalized.replace(/\/\/.*$/, '').replace(/\/\*.*?\*\//g, '');
77
+ }
78
+ else if (['py', 'pyw'].includes(extension)) {
79
+ normalized = normalized.replace(/#.*$/, '');
80
+ }
81
+ // Normalize whitespace
82
+ normalized = normalized.replace(/\s+/g, ' ').trim();
83
+ // Replace variable names with placeholders (simplified)
84
+ // This helps match similar code with different variable names
85
+ normalized = normalized
86
+ .replace(/\b[a-z][a-zA-Z0-9]*\b/g, 'VAR')
87
+ .replace(/"[^"]*"/g, 'STR')
88
+ .replace(/'[^']*'/g, 'STR')
89
+ .replace(/\d+/g, 'NUM');
90
+ return normalized;
91
+ }
92
+ function isTrivialLine(normalized) {
93
+ // Lines that are too generic to be meaningful duplicates
94
+ const trivialPatterns = [
95
+ /^[{}()\[\];,]+$/, // Just brackets/punctuation
96
+ /^(?:return|break|continue|pass);?$/, // Single keywords
97
+ /^VAR\s*=\s*(?:VAR|STR|NUM);?$/, // Simple assignments
98
+ /^}\s*(?:else|catch|finally)\s*{?$/, // Control flow brackets
99
+ /^import\s/, // Import statements (often similar)
100
+ /^export\s/, // Export statements
101
+ ];
102
+ return trivialPatterns.some((pattern) => pattern.test(normalized));
103
+ }
104
+ function calculateSimilarity(str1, str2) {
105
+ // Simple Jaccard similarity based on character n-grams
106
+ const ngram = (s, n) => {
107
+ const grams = new Set();
108
+ for (let i = 0; i <= s.length - n; i++) {
109
+ grams.add(s.slice(i, i + n));
110
+ }
111
+ return grams;
112
+ };
113
+ const grams1 = ngram(str1, 3);
114
+ const grams2 = ngram(str2, 3);
115
+ let intersection = 0;
116
+ for (const gram of grams1) {
117
+ if (grams2.has(gram)) {
118
+ intersection++;
119
+ }
120
+ }
121
+ const union = grams1.size + grams2.size - intersection;
122
+ return union > 0 ? intersection / union : 0;
123
+ }
124
+ //# sourceMappingURL=check-dry-violations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-dry-violations.js","sourceRoot":"","sources":["../../src/checks/check-dry-violations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Check for empty catch blocks that silently swallow errors
3
+ */
4
+ import type { Hook } from '../utils/types.js';
5
+ export declare const checkEmptyCatch: Hook;
6
+ //# sourceMappingURL=check-empty-catch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-empty-catch.d.ts","sourceRoot":"","sources":["../../src/checks/check-empty-catch.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,mBAAmB,CAAC;AAEvE,eAAO,MAAM,eAAe,EAAE,IAoB7B,CAAC"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Check for empty catch blocks that silently swallow errors
3
+ */
4
+ export const checkEmptyCatch = {
5
+ id: 'empty-catch',
6
+ name: 'Check Empty Catch',
7
+ description: 'Detect empty catch blocks that silently swallow errors',
8
+ severity: 'warning',
9
+ fileTypes: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py'],
10
+ check(context) {
11
+ const results = [];
12
+ const lines = context.content.split('\n');
13
+ const language = getLanguage(context.extension);
14
+ if (language === 'javascript' || language === 'typescript') {
15
+ results.push(...checkJavaScriptCatch(lines));
16
+ }
17
+ else if (language === 'python') {
18
+ results.push(...checkPythonCatch(lines));
19
+ }
20
+ return results;
21
+ },
22
+ };
23
+ function getLanguage(ext) {
24
+ if (['js', 'jsx', 'mjs', 'cjs'].includes(ext))
25
+ return 'javascript';
26
+ if (['ts', 'tsx', 'mts', 'cts'].includes(ext))
27
+ return 'typescript';
28
+ if (['py', 'pyw'].includes(ext))
29
+ return 'python';
30
+ return 'unknown';
31
+ }
32
+ function checkJavaScriptCatch(lines) {
33
+ const results = [];
34
+ const content = lines.join('\n');
35
+ // Pattern: catch block with empty body or just whitespace/comments
36
+ // Matches: catch (e) { } or catch { } or catch(error) { /* comment */ }
37
+ const catchPattern = /catch\s*\([^)]*\)\s*\{\s*(?:\/\/[^\n]*\n?\s*|\/\*[\s\S]*?\*\/\s*)?\}/g;
38
+ let match;
39
+ while ((match = catchPattern.exec(content)) !== null) {
40
+ // Find line number
41
+ const beforeMatch = content.substring(0, match.index);
42
+ const lineNum = beforeMatch.split('\n').length;
43
+ results.push({
44
+ line: lineNum,
45
+ column: 0,
46
+ message: 'Empty catch block - handle or rethrow the error',
47
+ severity: 'warning',
48
+ ruleId: 'empty-catch/js',
49
+ });
50
+ }
51
+ // Also check for catch without body content (single line)
52
+ for (let i = 0; i < lines.length; i++) {
53
+ const line = lines[i];
54
+ // Pattern: catch (e) {} on single line
55
+ if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(line)) {
56
+ // Avoid duplicates from the multi-line check
57
+ if (!results.some((r) => r.line === i + 1)) {
58
+ results.push({
59
+ line: i + 1,
60
+ column: line.indexOf('catch'),
61
+ message: 'Empty catch block - handle or rethrow the error',
62
+ severity: 'warning',
63
+ ruleId: 'empty-catch/js',
64
+ });
65
+ }
66
+ }
67
+ }
68
+ return results;
69
+ }
70
+ function checkPythonCatch(lines) {
71
+ const results = [];
72
+ for (let i = 0; i < lines.length; i++) {
73
+ const line = lines[i];
74
+ const lineNum = i + 1;
75
+ // Look for except: or except Exception: etc.
76
+ if (/^\s*except\s*(?:\w+(?:\s+as\s+\w+)?)?:\s*$/.test(line)) {
77
+ // Check next non-empty line
78
+ let nextLineIndex = i + 1;
79
+ while (nextLineIndex < lines.length) {
80
+ const nextLine = lines[nextLineIndex].trim();
81
+ if (nextLine === '') {
82
+ nextLineIndex++;
83
+ continue;
84
+ }
85
+ // Check if it's just 'pass' or a comment
86
+ if (nextLine === 'pass' || nextLine.startsWith('#')) {
87
+ results.push({
88
+ line: lineNum,
89
+ column: 0,
90
+ message: 'Empty except block - handle or reraise the exception',
91
+ severity: 'warning',
92
+ ruleId: 'empty-catch/py',
93
+ });
94
+ }
95
+ break;
96
+ }
97
+ }
98
+ // Also catch bare except: pass on same or adjacent line
99
+ if (/except.*:\s*pass\s*$/.test(line)) {
100
+ results.push({
101
+ line: lineNum,
102
+ column: line.indexOf('except'),
103
+ message: 'Empty except block - handle or reraise the exception',
104
+ severity: 'warning',
105
+ ruleId: 'empty-catch/py',
106
+ });
107
+ }
108
+ }
109
+ return results;
110
+ }
111
+ //# sourceMappingURL=check-empty-catch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-empty-catch.js","sourceRoot":"","sources":["../../src/checks/check-empty-catch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Check for functions that are too long
3
+ */
4
+ import type { Hook } from '../utils/types.js';
5
+ export declare const checkFunctionLength: Hook;
6
+ //# sourceMappingURL=check-function-length.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-function-length.d.ts","sourceRoot":"","sources":["../../src/checks/check-function-length.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,mBAAmB,CAAC;AAIvE,eAAO,MAAM,mBAAmB,EAAE,IAmBjC,CAAC"}
@@ -0,0 +1,152 @@
1
+ /**
2
+ * Check for functions that are too long
3
+ */
4
+ const MAX_FUNCTION_LENGTH = 150; // lines
5
+ export const checkFunctionLength = {
6
+ id: 'function-length',
7
+ name: 'Check Function Length',
8
+ description: 'Detect functions that are too long and should be refactored',
9
+ severity: 'warning',
10
+ fileTypes: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py'],
11
+ check(context) {
12
+ const results = [];
13
+ const language = getLanguage(context.extension);
14
+ if (language === 'javascript' || language === 'typescript') {
15
+ results.push(...checkJavaScriptFunctions(context.content));
16
+ }
17
+ else if (language === 'python') {
18
+ results.push(...checkPythonFunctions(context.content));
19
+ }
20
+ return results;
21
+ },
22
+ };
23
+ function getLanguage(ext) {
24
+ if (['js', 'jsx', 'mjs', 'cjs'].includes(ext))
25
+ return 'javascript';
26
+ if (['ts', 'tsx', 'mts', 'cts'].includes(ext))
27
+ return 'typescript';
28
+ if (['py', 'pyw'].includes(ext))
29
+ return 'python';
30
+ return 'unknown';
31
+ }
32
+ function checkJavaScriptFunctions(content) {
33
+ const results = [];
34
+ const lines = content.split('\n');
35
+ // Track function declarations
36
+ const functionStarts = [];
37
+ for (let i = 0; i < lines.length; i++) {
38
+ const line = lines[i];
39
+ const lineNum = i + 1;
40
+ // Detect function starts
41
+ // - function name()
42
+ // - const name = function
43
+ // - const name = () =>
44
+ // - async function name()
45
+ // - method() { or method = () =>
46
+ const funcMatch = line.match(/(?:(?:async\s+)?function\s+(\w+)|(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s*)?\(?|(\w+)\s*(?:=\s*(?:async\s*)?\(|[:(]\s*\)\s*(?:=>|{)))/);
47
+ if (funcMatch) {
48
+ const name = funcMatch[1] || funcMatch[2] || funcMatch[3] || 'anonymous';
49
+ // Count opening braces on this line
50
+ const openBraces = (line.match(/\{/g) || []).length;
51
+ const closeBraces = (line.match(/\}/g) || []).length;
52
+ if (openBraces > 0) {
53
+ functionStarts.push({
54
+ line: lineNum,
55
+ name,
56
+ braceCount: openBraces - closeBraces,
57
+ });
58
+ }
59
+ }
60
+ else {
61
+ // Update brace counts for tracked functions
62
+ const openBraces = (line.match(/\{/g) || []).length;
63
+ const closeBraces = (line.match(/\}/g) || []).length;
64
+ for (let j = functionStarts.length - 1; j >= 0; j--) {
65
+ functionStarts[j].braceCount += openBraces - closeBraces;
66
+ // Function ended
67
+ if (functionStarts[j].braceCount <= 0) {
68
+ const func = functionStarts[j];
69
+ const length = lineNum - func.line + 1;
70
+ if (length > MAX_FUNCTION_LENGTH) {
71
+ results.push({
72
+ line: func.line,
73
+ column: 0,
74
+ message: `Function "${func.name}" is ${length} lines (max: ${MAX_FUNCTION_LENGTH}) - consider refactoring`,
75
+ severity: 'warning',
76
+ ruleId: 'function-length/too-long',
77
+ });
78
+ }
79
+ functionStarts.splice(j, 1);
80
+ }
81
+ }
82
+ }
83
+ }
84
+ return results;
85
+ }
86
+ function checkPythonFunctions(content) {
87
+ const results = [];
88
+ const lines = content.split('\n');
89
+ // Track function definitions by indentation
90
+ const functionStarts = [];
91
+ for (let i = 0; i < lines.length; i++) {
92
+ const line = lines[i];
93
+ const lineNum = i + 1;
94
+ // Detect function definition
95
+ const funcMatch = line.match(/^(\s*)(?:async\s+)?def\s+(\w+)\s*\(/);
96
+ if (funcMatch) {
97
+ const indent = funcMatch[1].length;
98
+ const name = funcMatch[2];
99
+ // Close any functions with same or greater indentation
100
+ while (functionStarts.length > 0 &&
101
+ functionStarts[functionStarts.length - 1].indent >= indent) {
102
+ const func = functionStarts.pop();
103
+ const length = lineNum - func.line;
104
+ if (length > MAX_FUNCTION_LENGTH) {
105
+ results.push({
106
+ line: func.line,
107
+ column: 0,
108
+ message: `Function "${func.name}" is ${length} lines (max: ${MAX_FUNCTION_LENGTH}) - consider refactoring`,
109
+ severity: 'warning',
110
+ ruleId: 'function-length/too-long',
111
+ });
112
+ }
113
+ }
114
+ functionStarts.push({ line: lineNum, name, indent });
115
+ }
116
+ else if (line.trim() && !line.trim().startsWith('#')) {
117
+ // Non-empty, non-comment line - check indentation to close functions
118
+ const indent = line.match(/^(\s*)/)?.[1].length || 0;
119
+ while (functionStarts.length > 0 &&
120
+ indent <= functionStarts[functionStarts.length - 1].indent &&
121
+ !line.trim().startsWith('@') // decorators don't close functions
122
+ ) {
123
+ const func = functionStarts.pop();
124
+ const length = i - func.line; // Previous line was the end
125
+ if (length > MAX_FUNCTION_LENGTH) {
126
+ results.push({
127
+ line: func.line,
128
+ column: 0,
129
+ message: `Function "${func.name}" is ${length} lines (max: ${MAX_FUNCTION_LENGTH}) - consider refactoring`,
130
+ severity: 'warning',
131
+ ruleId: 'function-length/too-long',
132
+ });
133
+ }
134
+ }
135
+ }
136
+ }
137
+ // Close remaining functions at EOF
138
+ for (const func of functionStarts) {
139
+ const length = lines.length - func.line + 1;
140
+ if (length > MAX_FUNCTION_LENGTH) {
141
+ results.push({
142
+ line: func.line,
143
+ column: 0,
144
+ message: `Function "${func.name}" is ${length} lines (max: ${MAX_FUNCTION_LENGTH}) - consider refactoring`,
145
+ severity: 'warning',
146
+ ruleId: 'function-length/too-long',
147
+ });
148
+ }
149
+ }
150
+ return results;
151
+ }
152
+ //# sourceMappingURL=check-function-length.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-function-length.js","sourceRoot":"","sources":["../../src/checks/check-function-length.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Check for hardcoded AI model names and configurations
3
+ *
4
+ * AI models should be configured via environment variables or settings,
5
+ * not hardcoded in the source code. This allows for easy model switching
6
+ * and proper configuration management.
7
+ */
8
+ import type { Hook } from '../utils/types.js';
9
+ export declare const checkHardcodedAiModels: Hook;
10
+ //# sourceMappingURL=check-hardcoded-ai-models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-hardcoded-ai-models.d.ts","sourceRoot":"","sources":["../../src/checks/check-hardcoded-ai-models.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,mBAAmB,CAAC;AAiDvE,eAAO,MAAM,sBAAsB,EAAE,IAgDpC,CAAC"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Check for hardcoded AI model names and configurations
3
+ *
4
+ * AI models should be configured via environment variables or settings,
5
+ * not hardcoded in the source code. This allows for easy model switching
6
+ * and proper configuration management.
7
+ */
8
+ // Common AI model name patterns
9
+ const AI_MODEL_PATTERNS = [
10
+ // OpenAI models
11
+ /["']gpt-4(?:-turbo|-vision|-\d+)?["']/gi,
12
+ /["']gpt-3\.5-turbo(?:-\d+)?["']/gi,
13
+ /["']text-davinci-\d+["']/gi,
14
+ /["']text-embedding-(?:ada-\d+|3-\w+)["']/gi,
15
+ /["']dall-e-\d+["']/gi,
16
+ /["']whisper-\d+["']/gi,
17
+ /["']tts-\d+(?:-hd)?["']/gi,
18
+ /["']o1(?:-preview|-mini)?["']/gi,
19
+ // Anthropic models
20
+ /["']claude-(?:3|2|instant)(?:-\d+)?(?:-sonnet|-opus|-haiku)?(?:-\d+)?["']/gi,
21
+ // Google models
22
+ /["']gemini-(?:pro|ultra|nano)(?:-vision)?(?:-\d+)?["']/gi,
23
+ /["']palm-\d+["']/gi,
24
+ // Cohere models
25
+ /["']command(?:-light|-nightly|-r)?(?:-\d+)?["']/gi,
26
+ // Mistral models
27
+ /["']mistral-(?:tiny|small|medium|large)(?:-\d+)?["']/gi,
28
+ /["']mixtral-\d+x\d+b(?:-\d+)?["']/gi,
29
+ // Llama models
30
+ /["']llama-?\d+(?:-\d+b)?(?:-chat)?["']/gi,
31
+ /["']codellama-\d+b["']/gi,
32
+ ];
33
+ // Patterns that indicate it's in a config/env context (OK)
34
+ const ALLOWED_CONTEXTS = [
35
+ /process\.env\./,
36
+ /os\.environ/,
37
+ /settings\./,
38
+ /config\./,
39
+ /getenv/,
40
+ /ENV\[/,
41
+ /default[=:]/i, // Default value in env lookup
42
+ /fallback/i,
43
+ /\.env/,
44
+ /# noqa/,
45
+ /\/\/ noqa/,
46
+ /eslint-disable/,
47
+ ];
48
+ export const checkHardcodedAiModels = {
49
+ id: 'ai-models',
50
+ name: 'Check Hardcoded AI Models',
51
+ description: 'Detect hardcoded AI model names - use environment variables or settings instead',
52
+ severity: 'warning',
53
+ fileTypes: ['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py'],
54
+ check(context) {
55
+ const results = [];
56
+ const lines = context.content.split('\n');
57
+ for (let i = 0; i < lines.length; i++) {
58
+ const line = lines[i];
59
+ const lineNum = i + 1;
60
+ // Skip comments
61
+ if (isCommentLine(line, context.extension)) {
62
+ continue;
63
+ }
64
+ // Skip if line has noqa directive
65
+ if (line.includes('noqa') || line.includes('eslint-disable')) {
66
+ continue;
67
+ }
68
+ // Check if line is in an allowed context (env lookup, config, etc.)
69
+ if (ALLOWED_CONTEXTS.some(pattern => pattern.test(line))) {
70
+ continue;
71
+ }
72
+ // Check for hardcoded model names
73
+ for (const pattern of AI_MODEL_PATTERNS) {
74
+ const match = line.match(pattern);
75
+ if (match) {
76
+ results.push({
77
+ line: lineNum,
78
+ column: line.indexOf(match[0]),
79
+ message: `Hardcoded AI model "${match[0].replace(/["']/g, '')}" - use environment variable or settings`,
80
+ severity: 'warning',
81
+ ruleId: 'ai-models/hardcoded-model',
82
+ fix: 'Use os.environ.get("AI_MODEL") or settings.AI_MODEL instead',
83
+ });
84
+ }
85
+ }
86
+ }
87
+ return results;
88
+ },
89
+ };
90
+ function isCommentLine(line, extension) {
91
+ const trimmed = line.trim();
92
+ // JavaScript/TypeScript style comments
93
+ if (['js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs'].includes(extension)) {
94
+ return trimmed.startsWith('//') || trimmed.startsWith('*') || trimmed.startsWith('/*');
95
+ }
96
+ // Python style comments
97
+ if (['py', 'pyw'].includes(extension)) {
98
+ return trimmed.startsWith('#');
99
+ }
100
+ return false;
101
+ }
102
+ //# sourceMappingURL=check-hardcoded-ai-models.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-hardcoded-ai-models.js","sourceRoot":"","sources":["../../src/checks/check-hardcoded-ai-models.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Check for hardcoded URLs that should use environment variables
3
+ */
4
+ import type { Hook } from '../utils/types.js';
5
+ export declare const checkHardcodedUrls: Hook;
6
+ //# sourceMappingURL=check-hardcoded-urls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-hardcoded-urls.d.ts","sourceRoot":"","sources":["../../src/checks/check-hardcoded-urls.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,mBAAmB,CAAC;AA8BvE,eAAO,MAAM,kBAAkB,EAAE,IA4FhC,CAAC"}