@tinkcarlos/skillora 0.2.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 (234) hide show
  1. package/.claude/skills/.temp-skill-index.md +245 -0
  2. package/.claude/skills/SKILL.md +264 -0
  3. package/.claude/skills/api-scaffolding/SKILL.md +431 -0
  4. package/.claude/skills/api-scaffolding/agents/backend-architect.md +282 -0
  5. package/.claude/skills/api-scaffolding/agents/django-pro.md +144 -0
  6. package/.claude/skills/api-scaffolding/agents/fastapi-pro.md +156 -0
  7. package/.claude/skills/api-scaffolding/agents/graphql-architect.md +146 -0
  8. package/.claude/skills/api-scaffolding/skills/fastapi-templates/SKILL.md +171 -0
  9. package/.claude/skills/api-testing-observability/SKILL.md +583 -0
  10. package/.claude/skills/api-testing-observability/agents/api-documenter.md +146 -0
  11. package/.claude/skills/api-testing-observability/commands/api-mock.md +1320 -0
  12. package/.claude/skills/brainstorming/SKILL.md +283 -0
  13. package/.claude/skills/bug-fixing/SKILL.md +382 -0
  14. package/.claude/skills/bug-fixing/references/backend-guide.md +132 -0
  15. package/.claude/skills/bug-fixing/references/bug-guide.md +354 -0
  16. package/.claude/skills/bug-fixing/references/bug-record-template.md +134 -0
  17. package/.claude/skills/bug-fixing/references/bug-records.md +88 -0
  18. package/.claude/skills/bug-fixing/references/code-review-gate.md +81 -0
  19. package/.claude/skills/bug-fixing/references/common-bugs.md +140 -0
  20. package/.claude/skills/bug-fixing/references/complete-workflow.md +361 -0
  21. package/.claude/skills/bug-fixing/references/config-driven-fixes.md +136 -0
  22. package/.claude/skills/bug-fixing/references/context-isolation-protocol.md +268 -0
  23. package/.claude/skills/bug-fixing/references/cross-surface-regression.md +120 -0
  24. package/.claude/skills/bug-fixing/references/database-investigation.md +129 -0
  25. package/.claude/skills/bug-fixing/references/dependency-and-integrity-protocol.md +369 -0
  26. package/.claude/skills/bug-fixing/references/fix-completeness-checklist.md +239 -0
  27. package/.claude/skills/bug-fixing/references/frontend-guide.md +219 -0
  28. package/.claude/skills/bug-fixing/references/fullstack-joint-guide.md +123 -0
  29. package/.claude/skills/bug-fixing/references/functional-breakage.md +117 -0
  30. package/.claude/skills/bug-fixing/references/ide-lint-errors-guide.md +176 -0
  31. package/.claude/skills/bug-fixing/references/impact-analysis.md +511 -0
  32. package/.claude/skills/bug-fixing/references/investigation-checklist.md +263 -0
  33. package/.claude/skills/bug-fixing/references/knowledge-extraction-guide.md +531 -0
  34. package/.claude/skills/bug-fixing/references/knowledge-workflow.md +212 -0
  35. package/.claude/skills/bug-fixing/references/post-edit-quality-gate.md +30 -0
  36. package/.claude/skills/bug-fixing/references/python-env-and-testing.md +126 -0
  37. package/.claude/skills/bug-fixing/references/rca-guide.md +428 -0
  38. package/.claude/skills/bug-fixing/references/similar-bug-patterns.md +113 -0
  39. package/.claude/skills/bug-fixing/references/skill-delegation-guide.md +350 -0
  40. package/.claude/skills/bug-fixing/references/skill-orchestration.md +155 -0
  41. package/.claude/skills/bug-fixing/references/testing-strategy.md +350 -0
  42. package/.claude/skills/bug-fixing/references/tooling-build-scripts.md +162 -0
  43. package/.claude/skills/bug-fixing/references/user-input-validation.md +77 -0
  44. package/.claude/skills/bug-fixing/references/ux-patterns.md +158 -0
  45. package/.claude/skills/bug-fixing/references/windows-terminal-hygiene.md +106 -0
  46. package/.claude/skills/bug-fixing/references/zero-regression-matrix.md +239 -0
  47. package/.claude/skills/bug-fixing/references/zero-risk-protocol.md +102 -0
  48. package/.claude/skills/bug-fixing/scripts/format_code.py +611 -0
  49. package/.claude/skills/bug-fixing/scripts/generate_report_template.py +74 -0
  50. package/.claude/skills/bug-fixing/scripts/lint_check.py +816 -0
  51. package/.claude/skills/bug-fixing/scripts/requirements.txt +36 -0
  52. package/.claude/skills/cicd-pipeline/SKILL.md +300 -0
  53. package/.claude/skills/code-review/SKILL.md +535 -0
  54. package/.claude/skills/code-review/references/anti-pattern-scan.md +102 -0
  55. package/.claude/skills/code-review/references/automated-analysis.md +456 -0
  56. package/.claude/skills/code-review/references/backend-common-issues.md +589 -0
  57. package/.claude/skills/code-review/references/backend-expert-guide.md +415 -0
  58. package/.claude/skills/code-review/references/backend-review.md +868 -0
  59. package/.claude/skills/code-review/references/batch-processing-strategy.md +198 -0
  60. package/.claude/skills/code-review/references/call-chain-analysis-protocol.md +166 -0
  61. package/.claude/skills/code-review/references/common-patterns.md +321 -0
  62. package/.claude/skills/code-review/references/configuration-review.md +425 -0
  63. package/.claude/skills/code-review/references/control-flow-completeness.md +114 -0
  64. package/.claude/skills/code-review/references/database-review.md +298 -0
  65. package/.claude/skills/code-review/references/dependency-and-integrity-protocol.md +313 -0
  66. package/.claude/skills/code-review/references/external-standards.md +51 -0
  67. package/.claude/skills/code-review/references/feature-review.md +329 -0
  68. package/.claude/skills/code-review/references/file-review-template.md +326 -0
  69. package/.claude/skills/code-review/references/frontend-advanced.md +654 -0
  70. package/.claude/skills/code-review/references/frontend-common-issues.md +482 -0
  71. package/.claude/skills/code-review/references/frontend-expert-guide.md +342 -0
  72. package/.claude/skills/code-review/references/frontend-review.md +783 -0
  73. package/.claude/skills/code-review/references/fullstack-consistency.md +418 -0
  74. package/.claude/skills/code-review/references/fullstack-review.md +477 -0
  75. package/.claude/skills/code-review/references/functional-completeness.md +386 -0
  76. package/.claude/skills/code-review/references/hidden-bugs-detection.md +473 -0
  77. package/.claude/skills/code-review/references/ide-lint-errors-guide.md +173 -0
  78. package/.claude/skills/code-review/references/infrastructure-review.md +453 -0
  79. package/.claude/skills/code-review/references/iteration-review.md +264 -0
  80. package/.claude/skills/code-review/references/job-review.md +335 -0
  81. package/.claude/skills/code-review/references/layered-checklist-protocol.md +157 -0
  82. package/.claude/skills/code-review/references/logic-completeness.md +535 -0
  83. package/.claude/skills/code-review/references/mandatory-checklist.md +288 -0
  84. package/.claude/skills/code-review/references/multi-language-guide.md +800 -0
  85. package/.claude/skills/code-review/references/new-project-review.md +226 -0
  86. package/.claude/skills/code-review/references/non-code-files-review.md +451 -0
  87. package/.claude/skills/code-review/references/overlooked-issues.md +657 -0
  88. package/.claude/skills/code-review/references/platform-specific-review.md +195 -0
  89. package/.claude/skills/code-review/references/precision-analysis-protocol.md +260 -0
  90. package/.claude/skills/code-review/references/python-patterns.md +494 -0
  91. package/.claude/skills/code-review/references/rca-techniques.md +362 -0
  92. package/.claude/skills/code-review/references/report-template.md +430 -0
  93. package/.claude/skills/code-review/references/resource-limits-and-degradation.md +137 -0
  94. package/.claude/skills/code-review/references/review-dimensions.md +311 -0
  95. package/.claude/skills/code-review/references/review-guide.md +202 -0
  96. package/.claude/skills/code-review/references/review-knowledge-workflow.md +257 -0
  97. package/.claude/skills/code-review/references/review-progress-tracker-protocol.md +172 -0
  98. package/.claude/skills/code-review/references/review-record-template.md +195 -0
  99. package/.claude/skills/code-review/references/skill-orchestration.md +143 -0
  100. package/.claude/skills/code-review/references/ui-ux-review.md +470 -0
  101. package/.claude/skills/containerization/SKILL.md +313 -0
  102. package/.claude/skills/database-migrations/agents/database-admin.md +142 -0
  103. package/.claude/skills/database-migrations/agents/database-optimizer.md +144 -0
  104. package/.claude/skills/database-migrations/commands/migration-observability.md +408 -0
  105. package/.claude/skills/database-migrations/commands/sql-migrations.md +492 -0
  106. package/.claude/skills/finishing-a-development-branch/SKILL.md +319 -0
  107. package/.claude/skills/frontend-design/LICENSE.txt +177 -0
  108. package/.claude/skills/frontend-design/SKILL.md +587 -0
  109. package/.claude/skills/frontend-design/references/color-consistency.md +487 -0
  110. package/.claude/skills/frontend-design/references/color-palettes-full.md +657 -0
  111. package/.claude/skills/frontend-design/references/design-system-generator.md +285 -0
  112. package/.claude/skills/frontend-design/references/font-pairings-full.md +705 -0
  113. package/.claude/skills/frontend-design/references/industry-anti-patterns.md +281 -0
  114. package/.claude/skills/frontend-design/references/layout-anti-patterns.md +582 -0
  115. package/.claude/skills/frontend-design/references/motion-patterns.md +659 -0
  116. package/.claude/skills/frontend-design/references/pre-delivery-checklist.md +153 -0
  117. package/.claude/skills/frontend-design/references/responsive-design.md +555 -0
  118. package/.claude/skills/frontend-design/references/style-modification-rules.md +335 -0
  119. package/.claude/skills/frontend-design/references/ui-styles-full.md +383 -0
  120. package/.claude/skills/frontend-design/references/ui-styles-rating.md +191 -0
  121. package/.claude/skills/frontend-design/references/ux-guidelines.md +640 -0
  122. package/.claude/skills/fullstack-developer/SKILL.md +512 -0
  123. package/.claude/skills/fullstack-developer/references/api-contract-guide.md +312 -0
  124. package/.claude/skills/fullstack-developer/references/api-response-patterns.md +223 -0
  125. package/.claude/skills/fullstack-developer/references/async-patterns.md +220 -0
  126. package/.claude/skills/fullstack-developer/references/bug-prevention.md +914 -0
  127. package/.claude/skills/fullstack-developer/references/code-quality-checklist.md +271 -0
  128. package/.claude/skills/fullstack-developer/references/complete-development-workflow.md +278 -0
  129. package/.claude/skills/fullstack-developer/references/context-isolation-protocol.md +256 -0
  130. package/.claude/skills/fullstack-developer/references/database-migration.md +331 -0
  131. package/.claude/skills/fullstack-developer/references/dependency-and-integrity-protocol.md +390 -0
  132. package/.claude/skills/fullstack-developer/references/development-phases.md +333 -0
  133. package/.claude/skills/fullstack-developer/references/expert-guide.md +214 -0
  134. package/.claude/skills/fullstack-developer/references/file-import-patterns.md +114 -0
  135. package/.claude/skills/fullstack-developer/references/graceful-degradation-patterns.md +78 -0
  136. package/.claude/skills/fullstack-developer/references/ide-lint-errors-guide.md +183 -0
  137. package/.claude/skills/fullstack-developer/references/integration-testing.md +301 -0
  138. package/.claude/skills/fullstack-developer/references/mock-api-patterns.md +307 -0
  139. package/.claude/skills/fullstack-developer/references/phase-gate-template.md +249 -0
  140. package/.claude/skills/fullstack-developer/references/post-edit-quality-gate.md +30 -0
  141. package/.claude/skills/fullstack-developer/references/python-engineering.md +79 -0
  142. package/.claude/skills/fullstack-developer/references/skill-orchestration.md +214 -0
  143. package/.claude/skills/fullstack-developer/references/skill-router-table.md +304 -0
  144. package/.claude/skills/fullstack-developer/references/state-sync.md +217 -0
  145. package/.claude/skills/fullstack-developer/references/ui-testing-checklist.md +292 -0
  146. package/.claude/skills/fullstack-developer/scripts/format_code.py +611 -0
  147. package/.claude/skills/fullstack-developer/scripts/lint_check.py +816 -0
  148. package/.claude/skills/fullstack-developer/scripts/requirements.txt +36 -0
  149. package/.claude/skills/performance-optimization/SKILL.md +250 -0
  150. package/.claude/skills/product-requirements/SKILL.md +357 -0
  151. package/.claude/skills/product-requirements/references/acceptance-criteria.md +335 -0
  152. package/.claude/skills/product-requirements/references/answer-first-questioning-protocol.md +299 -0
  153. package/.claude/skills/product-requirements/references/competitive-analysis-guide.md +183 -0
  154. package/.claude/skills/product-requirements/references/document-accuracy-protocol.md +253 -0
  155. package/.claude/skills/product-requirements/references/document-management-protocol.md +278 -0
  156. package/.claude/skills/product-requirements/references/external-standards.md +62 -0
  157. package/.claude/skills/product-requirements/references/feature-spec-template.md +359 -0
  158. package/.claude/skills/product-requirements/references/knowledge-acquisition-protocol.md +251 -0
  159. package/.claude/skills/product-requirements/references/plan-execution-protocol.md +334 -0
  160. package/.claude/skills/product-requirements/references/plan-generation-protocol.md +264 -0
  161. package/.claude/skills/product-requirements/references/prioritization-frameworks.md +80 -0
  162. package/.claude/skills/product-requirements/references/requirement-decomposition-protocol.md +291 -0
  163. package/.claude/skills/product-requirements/references/user-story-examples.md +297 -0
  164. package/.claude/skills/product-requirements/references/workflow-templates.md +266 -0
  165. package/.claude/skills/react-best-practices/SKILL.md +198 -0
  166. package/.claude/skills/react-best-practices/references/advanced-patterns.md +94 -0
  167. package/.claude/skills/react-best-practices/references/bundle-optimization.md +182 -0
  168. package/.claude/skills/react-best-practices/references/client-data-fetching.md +112 -0
  169. package/.claude/skills/react-best-practices/references/complete-guide.md +2249 -0
  170. package/.claude/skills/react-best-practices/references/eliminating-waterfalls.md +169 -0
  171. package/.claude/skills/react-best-practices/references/javascript-performance.md +256 -0
  172. package/.claude/skills/react-best-practices/references/rendering-performance.md +230 -0
  173. package/.claude/skills/react-best-practices/references/rerender-optimization.md +214 -0
  174. package/.claude/skills/react-best-practices/references/server-performance.md +182 -0
  175. package/.claude/skills/security-audit/SKILL.md +226 -0
  176. package/.claude/skills/shared-references/advanced-debugging-techniques.md +186 -0
  177. package/.claude/skills/shared-references/code-quality-checklist.md +218 -0
  178. package/.claude/skills/shared-references/code-review-efficiency-guide.md +125 -0
  179. package/.claude/skills/shared-references/mcp-dependency-compatibility-protocol.md +276 -0
  180. package/.claude/skills/shared-references/skill-call-graph.md +230 -0
  181. package/.claude/skills/shared-references/skill-orchestration-protocol.md +281 -0
  182. package/.claude/skills/shared-references/subagent-dispatch-templates.md +199 -0
  183. package/.claude/skills/skill-expert-skills/LICENSE.txt +204 -0
  184. package/.claude/skills/skill-expert-skills/QUICK_NAVIGATION.md +374 -0
  185. package/.claude/skills/skill-expert-skills/SKILL.md +247 -0
  186. package/.claude/skills/skill-expert-skills/docs/_index.md +91 -0
  187. package/.claude/skills/skill-expert-skills/references/deep-research-methodology.md +389 -0
  188. package/.claude/skills/skill-expert-skills/references/docs-generation-workflow.md +398 -0
  189. package/.claude/skills/skill-expert-skills/references/domain-expertise-protocol.md +343 -0
  190. package/.claude/skills/skill-expert-skills/references/domain-knowledge/_index.md +54 -0
  191. package/.claude/skills/skill-expert-skills/references/domain-knowledge/backend-expertise.md +517 -0
  192. package/.claude/skills/skill-expert-skills/references/domain-knowledge/bug-fixing-expertise.md +363 -0
  193. package/.claude/skills/skill-expert-skills/references/domain-knowledge/code-review-expertise.md +392 -0
  194. package/.claude/skills/skill-expert-skills/references/domain-knowledge/frontend-expertise.md +410 -0
  195. package/.claude/skills/skill-expert-skills/references/domain-knowledge-template.md +503 -0
  196. package/.claude/skills/skill-expert-skills/references/examples.md +782 -0
  197. package/.claude/skills/skill-expert-skills/references/integration-examples.md +655 -0
  198. package/.claude/skills/skill-expert-skills/references/knowledge-validation-checklist.md +246 -0
  199. package/.claude/skills/skill-expert-skills/references/latest-knowledge-acquisition.md +461 -0
  200. package/.claude/skills/skill-expert-skills/references/mcp-tools-guide.md +439 -0
  201. package/.claude/skills/skill-expert-skills/references/official-best-practices.md +616 -0
  202. package/.claude/skills/skill-expert-skills/references/patterns.md +218 -0
  203. package/.claude/skills/skill-expert-skills/references/plugin-skills-guide.md +432 -0
  204. package/.claude/skills/skill-expert-skills/references/requirement-elicitation-protocol.md +290 -0
  205. package/.claude/skills/skill-expert-skills/references/skill-creator-SKILL.md +353 -0
  206. package/.claude/skills/skill-expert-skills/references/skill-templates.md +583 -0
  207. package/.claude/skills/skill-expert-skills/references/skills-knowledge-base.md +561 -0
  208. package/.claude/skills/skill-expert-skills/references/tools-guide.md +379 -0
  209. package/.claude/skills/skill-expert-skills/references/troubleshooting.md +378 -0
  210. package/.claude/skills/skill-expert-skills/references/universality-guide.md +205 -0
  211. package/.claude/skills/skill-expert-skills/references/writing-style-guide.md +466 -0
  212. package/.claude/skills/skill-expert-skills/scripts/__pycache__/quick_validate.cpython-313.pyc +0 -0
  213. package/.claude/skills/skill-expert-skills/scripts/__pycache__/universal_validate.cpython-313.pyc +0 -0
  214. package/.claude/skills/skill-expert-skills/scripts/analyze_trigger.py +425 -0
  215. package/.claude/skills/skill-expert-skills/scripts/diff_with_official.py +188 -0
  216. package/.claude/skills/skill-expert-skills/scripts/init_skill.py +349 -0
  217. package/.claude/skills/skill-expert-skills/scripts/package_skill.py +156 -0
  218. package/.claude/skills/skill-expert-skills/scripts/quick_validate.py +493 -0
  219. package/.claude/skills/skill-expert-skills/scripts/requirements.txt +2 -0
  220. package/.claude/skills/skill-expert-skills/scripts/universal_validate.py +182 -0
  221. package/.claude/skills/skill-expert-skills/scripts/upgrade_skill.py +431 -0
  222. package/.claude/skills/subagent-driven-development/SKILL.md +268 -0
  223. package/.claude/skills/test-driven-development/SKILL.md +246 -0
  224. package/.claude/skills/test-driven-development/references/testing-anti-patterns.md +192 -0
  225. package/.claude/skills/using-git-worktrees/SKILL.md +266 -0
  226. package/.claude/skills/using-skillstack/SKILL.md +127 -0
  227. package/.claude/skills/vercel-deploy/SKILL.md +166 -0
  228. package/.claude/skills/vercel-deploy/scripts/deploy.sh +249 -0
  229. package/.claude/skills/verification-before-completion/SKILL.md +305 -0
  230. package/.claude/skills/writing-plans/SKILL.md +259 -0
  231. package/README.md +69 -0
  232. package/bin/cli.js +468 -0
  233. package/lib/init.js +333 -0
  234. package/package.json +29 -0
@@ -0,0 +1,816 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Lint Check Script - Detect and categorize code warnings/errors after modification.
4
+
5
+ Features:
6
+ - Supports Python (ruff/pylint/mypy), TypeScript/JavaScript (eslint/tsc)
7
+ - Smart priority classification with rule-based and pattern-based detection
8
+ - Parallel processing for multiple files
9
+ - JSON output for CI/CD integration
10
+ - Auto-fix support for compatible linters
11
+ - Dependency checking with install suggestions
12
+
13
+ Usage:
14
+ python lint_check.py <file_path> # Check single file
15
+ python lint_check.py <file1> <file2> # Check multiple files (parallel)
16
+ python lint_check.py --dir <directory> # Check directory
17
+ python lint_check.py <file_path> --fix # Auto-fix if possible
18
+ python lint_check.py --check-deps # Check linter dependencies
19
+ python lint_check.py <file_path> --json # JSON output for CI/CD
20
+
21
+ Exit codes:
22
+ 0 - No errors found (may have warnings)
23
+ 1 - P0/P1 errors found (must fix)
24
+ 2 - P2 warnings found (should fix)
25
+ 3 - Linter not available
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import argparse
31
+ import subprocess
32
+ import sys
33
+ import os
34
+ import re
35
+ import json
36
+ from pathlib import Path
37
+ from typing import List, Tuple, Optional, Dict, Any, Set
38
+ from dataclasses import dataclass, field, asdict
39
+ from enum import Enum
40
+ from concurrent.futures import ThreadPoolExecutor, as_completed
41
+ import threading
42
+
43
+
44
+ # Configure stdout/stderr encoding for Windows
45
+ def _configure_stdio() -> None:
46
+ """Ensure UTF-8 encoding for stdout/stderr on Windows"""
47
+ if sys.platform == 'win32':
48
+ os.environ.setdefault('PYTHONIOENCODING', 'utf-8')
49
+ for stream in (sys.stdout, sys.stderr):
50
+ try:
51
+ stream.reconfigure(encoding='utf-8', errors='replace')
52
+ except Exception:
53
+ pass
54
+
55
+ _configure_stdio()
56
+
57
+
58
+ class Priority(Enum):
59
+ """Error priority levels"""
60
+ P0 = 0 # Must fix immediately (syntax, critical type errors)
61
+ P1 = 1 # Must fix before commit (imports, declarations)
62
+ P2 = 2 # Should fix (linting warnings)
63
+ P3 = 3 # Optional (style nits)
64
+
65
+ def __str__(self) -> str:
66
+ return self.name
67
+
68
+
69
+ @dataclass
70
+ class DependencyStatus:
71
+ """Status of a linter dependency"""
72
+ name: str
73
+ available: bool
74
+ version: Optional[str] = None
75
+ install_cmd: Optional[str] = None
76
+
77
+
78
+ @dataclass
79
+ class LintIssue:
80
+ """Single lint issue"""
81
+ file_path: str
82
+ line: int
83
+ column: int
84
+ message: str
85
+ rule_id: str
86
+ priority: Priority
87
+ category: str
88
+ suggestion: Optional[str] = None
89
+ fixable: bool = False
90
+
91
+ def to_dict(self) -> Dict[str, Any]:
92
+ d = asdict(self)
93
+ d['priority'] = str(self.priority)
94
+ return d
95
+
96
+
97
+ @dataclass
98
+ class LintResult:
99
+ """Lint result for a file"""
100
+ file_path: str
101
+ success: bool
102
+ issues: List[LintIssue] = field(default_factory=list)
103
+ linter_used: Optional[str] = None
104
+ error_message: Optional[str] = None
105
+
106
+ @property
107
+ def p0_count(self) -> int:
108
+ return sum(1 for i in self.issues if i.priority == Priority.P0)
109
+
110
+ @property
111
+ def p1_count(self) -> int:
112
+ return sum(1 for i in self.issues if i.priority == Priority.P1)
113
+
114
+ @property
115
+ def p2_count(self) -> int:
116
+ return sum(1 for i in self.issues if i.priority == Priority.P2)
117
+
118
+ @property
119
+ def p3_count(self) -> int:
120
+ return sum(1 for i in self.issues if i.priority == Priority.P3)
121
+
122
+ @property
123
+ def has_blocking_issues(self) -> bool:
124
+ return self.p0_count > 0 or self.p1_count > 0
125
+
126
+ def to_dict(self) -> Dict[str, Any]:
127
+ return {
128
+ 'file_path': self.file_path,
129
+ 'success': self.success,
130
+ 'issues': [i.to_dict() for i in self.issues],
131
+ 'linter_used': self.linter_used,
132
+ 'error_message': self.error_message,
133
+ 'counts': {
134
+ 'p0': self.p0_count,
135
+ 'p1': self.p1_count,
136
+ 'p2': self.p2_count,
137
+ 'p3': self.p3_count,
138
+ 'total': len(self.issues)
139
+ }
140
+ }
141
+
142
+
143
+ class PriorityClassifier:
144
+ """Smart priority classification for lint issues"""
145
+
146
+ # Rule ID prefixes that indicate specific priorities
147
+ RULE_PRIORITY_MAP = {
148
+ # Python - Ruff
149
+ Priority.P0: {
150
+ 'E999', # Syntax error
151
+ 'E902', # IO error
152
+ 'F401', # Imported but unused (can cause issues)
153
+ 'F821', # Undefined name
154
+ 'F822', # Undefined name in __all__
155
+ 'F823', # Local variable referenced before assignment
156
+ },
157
+ Priority.P1: {
158
+ 'E', # Error prefix
159
+ 'F', # Pyflakes
160
+ 'PLE', # Pylint errors
161
+ 'I001', # Import sorting
162
+ },
163
+ Priority.P2: {
164
+ 'W', # Warning prefix
165
+ 'PLW', # Pylint warnings
166
+ 'C', # Convention
167
+ 'N', # Naming
168
+ 'D', # Docstring
169
+ },
170
+ # TypeScript/ESLint
171
+ 'error': Priority.P1,
172
+ 'warn': Priority.P2,
173
+ 'warning': Priority.P2,
174
+ }
175
+
176
+ # Pattern-based classification (regex patterns)
177
+ PATTERN_PRIORITY = {
178
+ Priority.P0: [
179
+ r'syntax\s*error', r'invalid\s*syntax', r'unexpected\s*token',
180
+ r'cannot\s*parse', r'parse\s*error', r'SyntaxError',
181
+ r'unterminated', r'unexpected\s*end', r'unexpected\s*EOF',
182
+ r'missing.*semicolon', r'missing.*bracket', r'missing.*brace',
183
+ r'illegal', r'invalid\s*character',
184
+ ],
185
+ Priority.P1: [
186
+ r'undefined', r'not\s*defined', r'cannot\s*find', r'no\s*such',
187
+ r'import.*error', r'module.*not\s*found', r'cannot\s*resolve',
188
+ r'type.*mismatch', r'incompatible\s*type', r'not\s*assignable',
189
+ r'missing.*import', r'unresolved.*reference', r'does\s*not\s*exist',
190
+ r'has\s*no\s*attribute', r'has\s*no\s*member', r'is\s*not\s*a\s*function',
191
+ r'expected.*argument', r'too\s*(many|few)\s*arguments',
192
+ r'cannot\s*call', r'not\s*callable', r'return\s*type.*mismatch',
193
+ ],
194
+ Priority.P2: [
195
+ r'unused', r'never\s*used', r'is\s*defined\s*but\s*never',
196
+ r'deprecated', r'complexity', r'too\s*many', r'too\s*long',
197
+ r'line\s*too\s*long', r'missing\s*docstring', r'missing\s*type',
198
+ r'could\s*be', r'consider', r'prefer', r'should\s*be',
199
+ r'shadowing', r'redefinition', r'reassigned',
200
+ ],
201
+ }
202
+
203
+ # Fix suggestions based on patterns
204
+ SUGGESTIONS = {
205
+ r'undefined|not\s*defined': "Add import statement or define the variable/function",
206
+ r'unused|never\s*used': "Remove unused code or add usage",
207
+ r'import': "Check import path and module name",
208
+ r'type.*mismatch|not\s*assignable': "Check type annotations and ensure compatibility",
209
+ r'missing': "Add required syntax element or import",
210
+ r'deprecated': "Update to use recommended API",
211
+ r'cannot\s*find\s*module': "Install package or check import path",
212
+ r'no\s*attribute|no\s*member': "Check spelling or add required method/property",
213
+ r'argument': "Check function signature and argument count",
214
+ }
215
+
216
+ def __init__(self):
217
+ # Compile patterns for efficiency
218
+ self._compiled_patterns = {
219
+ priority: [re.compile(p, re.IGNORECASE) for p in patterns]
220
+ for priority, patterns in self.PATTERN_PRIORITY.items()
221
+ }
222
+ self._suggestion_patterns = [
223
+ (re.compile(p, re.IGNORECASE), suggestion)
224
+ for p, suggestion in self.SUGGESTIONS.items()
225
+ ]
226
+
227
+ def classify(self, message: str, rule_id: str, severity: Optional[str] = None) -> Priority:
228
+ """Classify issue priority based on rule ID, message, and severity"""
229
+ rule_upper = rule_id.upper()
230
+
231
+ # 1. Check exact rule ID match
232
+ for priority, rules in self.RULE_PRIORITY_MAP.items():
233
+ if isinstance(rules, set) and rule_upper in rules:
234
+ return priority
235
+
236
+ # 2. Check rule ID prefix
237
+ for priority, rules in self.RULE_PRIORITY_MAP.items():
238
+ if isinstance(rules, set):
239
+ for rule_prefix in rules:
240
+ if len(rule_prefix) <= 3 and rule_upper.startswith(rule_prefix):
241
+ return priority
242
+
243
+ # 3. Check severity string
244
+ if severity:
245
+ severity_lower = severity.lower()
246
+ if 'error' in severity_lower:
247
+ return Priority.P1
248
+ elif 'warn' in severity_lower:
249
+ return Priority.P2
250
+
251
+ # 4. Check message patterns
252
+ for priority, patterns in self._compiled_patterns.items():
253
+ for pattern in patterns:
254
+ if pattern.search(message):
255
+ return priority
256
+
257
+ # 5. Default based on rule prefix conventions
258
+ if rule_upper.startswith('E') or rule_id.startswith('TS'):
259
+ return Priority.P1
260
+ elif rule_upper.startswith('W'):
261
+ return Priority.P2
262
+
263
+ return Priority.P3
264
+
265
+ def get_suggestion(self, message: str) -> Optional[str]:
266
+ """Get fix suggestion based on message"""
267
+ for pattern, suggestion in self._suggestion_patterns:
268
+ if pattern.search(message):
269
+ return suggestion
270
+ return None
271
+
272
+
273
+ class LintChecker:
274
+ """Multi-language lint checker with parallel processing"""
275
+
276
+ EXTENSION_MAP = {
277
+ '.py': 'python', '.pyw': 'python', '.pyi': 'python',
278
+ '.ts': 'typescript', '.tsx': 'typescript',
279
+ '.js': 'javascript', '.jsx': 'javascript',
280
+ '.mjs': 'javascript', '.cjs': 'javascript',
281
+ '.vue': 'vue', '.go': 'go', '.rs': 'rust',
282
+ }
283
+
284
+ INSTALL_COMMANDS = {
285
+ 'ruff': 'pip install ruff',
286
+ 'pylint': 'pip install pylint',
287
+ 'mypy': 'pip install mypy',
288
+ 'eslint': 'npm install -g eslint',
289
+ 'tsc': 'npm install -g typescript',
290
+ }
291
+
292
+ def __init__(self, verbose: bool = False, max_workers: int = 4):
293
+ self.verbose = verbose
294
+ self.max_workers = max_workers
295
+ self.classifier = PriorityClassifier()
296
+ self._linter_cache: Dict[str, bool] = {}
297
+ self._cache_lock = threading.Lock()
298
+
299
+ def _log(self, message: str) -> None:
300
+ if self.verbose:
301
+ print(f"[LINT] {message}", file=sys.stderr)
302
+
303
+ def _check_command(self, cmd: str) -> bool:
304
+ """Check if a command is available (thread-safe)"""
305
+ with self._cache_lock:
306
+ if cmd in self._linter_cache:
307
+ return self._linter_cache[cmd]
308
+
309
+ try:
310
+ check_cmd = 'where' if sys.platform == 'win32' else 'which'
311
+ result = subprocess.run([check_cmd, cmd], capture_output=True, text=True, timeout=5)
312
+ available = result.returncode == 0
313
+ except Exception:
314
+ available = False
315
+
316
+ with self._cache_lock:
317
+ self._linter_cache[cmd] = available
318
+ return available
319
+
320
+ def _get_version(self, cmd: str) -> Optional[str]:
321
+ """Get version of a command"""
322
+ try:
323
+ result = subprocess.run([cmd, '--version'], capture_output=True, text=True, timeout=5)
324
+ if result.returncode == 0:
325
+ return result.stdout.strip().split('\n')[0]
326
+ except Exception:
327
+ pass
328
+ return None
329
+
330
+ def check_dependencies(self) -> List[DependencyStatus]:
331
+ """Check all linter dependencies"""
332
+ deps = []
333
+ for name in ['ruff', 'pylint', 'mypy', 'eslint', 'tsc']:
334
+ # For eslint/tsc, also check npx
335
+ if name in ('eslint', 'tsc'):
336
+ available = self._check_command(name) or self._check_command('npx')
337
+ else:
338
+ available = self._check_command(name)
339
+
340
+ deps.append(DependencyStatus(
341
+ name=name,
342
+ available=available,
343
+ version=self._get_version(name) if available else None,
344
+ install_cmd=self.INSTALL_COMMANDS.get(name)
345
+ ))
346
+ return deps
347
+
348
+ def _parse_ruff_output(self, output: str, file_path: str) -> List[LintIssue]:
349
+ """Parse ruff linter output"""
350
+ issues = []
351
+ # Ruff format: file:line:col: CODE message
352
+ pattern = r'^(.+?):(\d+):(\d+):\s*(\w+)\s+(.+)$'
353
+
354
+ for line in output.strip().split('\n'):
355
+ if not line.strip():
356
+ continue
357
+ match = re.match(pattern, line)
358
+ if match:
359
+ _, line_num, col, rule_id, message = match.groups()
360
+ priority = self.classifier.classify(message, rule_id)
361
+ issues.append(LintIssue(
362
+ file_path=file_path,
363
+ line=int(line_num),
364
+ column=int(col),
365
+ message=message.strip(),
366
+ rule_id=rule_id,
367
+ priority=priority,
368
+ category='ruff',
369
+ suggestion=self.classifier.get_suggestion(message),
370
+ fixable=rule_id not in ('E999', 'E902')
371
+ ))
372
+ return issues
373
+
374
+ def _parse_mypy_output(self, output: str, file_path: str) -> List[LintIssue]:
375
+ """Parse mypy type checker output"""
376
+ issues = []
377
+ # mypy format: file:line: error: message [error-code]
378
+ pattern = r'^(.+?):(\d+):\s*(error|warning|note):\s*(.+?)(?:\s*\[([^\]]+)\])?$'
379
+
380
+ for line in output.strip().split('\n'):
381
+ if not line.strip():
382
+ continue
383
+ match = re.match(pattern, line)
384
+ if match:
385
+ _, line_num, severity, message, error_code = match.groups()
386
+ rule_id = error_code or f'mypy-{severity}'
387
+ priority = self.classifier.classify(message, rule_id, severity)
388
+
389
+ # Mypy errors are typically P1
390
+ if severity == 'error' and priority == Priority.P3:
391
+ priority = Priority.P1
392
+
393
+ issues.append(LintIssue(
394
+ file_path=file_path,
395
+ line=int(line_num),
396
+ column=0,
397
+ message=message.strip(),
398
+ rule_id=rule_id,
399
+ priority=priority,
400
+ category='mypy',
401
+ suggestion=self.classifier.get_suggestion(message),
402
+ fixable=False
403
+ ))
404
+ return issues
405
+
406
+ def _parse_eslint_output(self, output: str, file_path: str) -> List[LintIssue]:
407
+ """Parse ESLint JSON output"""
408
+ issues = []
409
+ try:
410
+ data = json.loads(output)
411
+ for file_result in data:
412
+ for msg in file_result.get('messages', []):
413
+ rule_id = msg.get('ruleId') or 'eslint'
414
+ message = msg.get('message', '')
415
+ severity = 'error' if msg.get('severity', 1) == 2 else 'warning'
416
+ priority = self.classifier.classify(message, rule_id, severity)
417
+
418
+ issues.append(LintIssue(
419
+ file_path=file_path,
420
+ line=msg.get('line', 0),
421
+ column=msg.get('column', 0),
422
+ message=message.strip(),
423
+ rule_id=rule_id,
424
+ priority=priority,
425
+ category='eslint',
426
+ suggestion=self.classifier.get_suggestion(message),
427
+ fixable=msg.get('fix') is not None
428
+ ))
429
+ except json.JSONDecodeError:
430
+ pass
431
+ return issues
432
+
433
+ def _parse_tsc_output(self, output: str, file_path: str) -> List[LintIssue]:
434
+ """Parse TypeScript compiler output"""
435
+ issues = []
436
+ # TSC format: file(line,col): error TSXXXX: message
437
+ pattern = r'^(.+?)\((\d+),(\d+)\):\s*(error|warning)\s+(TS\d+):\s*(.+)$'
438
+
439
+ for line in output.strip().split('\n'):
440
+ match = re.match(pattern, line)
441
+ if match:
442
+ _, line_num, col, severity, code, message = match.groups()
443
+ priority = self.classifier.classify(message, code, severity)
444
+ issues.append(LintIssue(
445
+ file_path=file_path,
446
+ line=int(line_num),
447
+ column=int(col),
448
+ message=message.strip(),
449
+ rule_id=code,
450
+ priority=priority,
451
+ category='tsc',
452
+ suggestion=self.classifier.get_suggestion(message),
453
+ fixable=False
454
+ ))
455
+ return issues
456
+
457
+ def _check_python(self, file_path: str, auto_fix: bool = False) -> LintResult:
458
+ """Check Python file using ruff and optionally mypy"""
459
+ path = Path(file_path).resolve()
460
+ issues = []
461
+ linters_used = []
462
+
463
+ # Run ruff
464
+ if self._check_command('ruff'):
465
+ cmd = ['ruff', 'check']
466
+ if auto_fix:
467
+ cmd.append('--fix')
468
+ cmd.append(str(path))
469
+
470
+ try:
471
+ result = subprocess.run(
472
+ cmd, capture_output=True, text=True,
473
+ encoding='utf-8', errors='replace', timeout=30
474
+ )
475
+ ruff_issues = self._parse_ruff_output(result.stdout + result.stderr, str(path))
476
+ issues.extend(ruff_issues)
477
+ linters_used.append('ruff')
478
+ except Exception as e:
479
+ self._log(f"ruff error: {e}")
480
+
481
+ # Run mypy for type checking
482
+ if self._check_command('mypy'):
483
+ cmd = ['mypy', '--no-error-summary', str(path)]
484
+ try:
485
+ result = subprocess.run(
486
+ cmd, capture_output=True, text=True,
487
+ encoding='utf-8', errors='replace', timeout=60
488
+ )
489
+ mypy_issues = self._parse_mypy_output(result.stdout + result.stderr, str(path))
490
+ # Deduplicate with ruff issues
491
+ existing_locations = {(i.line, i.message[:50]) for i in issues}
492
+ for issue in mypy_issues:
493
+ if (issue.line, issue.message[:50]) not in existing_locations:
494
+ issues.append(issue)
495
+ linters_used.append('mypy')
496
+ except Exception as e:
497
+ self._log(f"mypy error: {e}")
498
+
499
+ if not linters_used:
500
+ return LintResult(
501
+ file_path=str(path),
502
+ success=False,
503
+ error_message="No Python linter available. Install: pip install ruff mypy"
504
+ )
505
+
506
+ return LintResult(
507
+ file_path=str(path),
508
+ success=True,
509
+ issues=issues,
510
+ linter_used='+'.join(linters_used)
511
+ )
512
+
513
+ def _check_js_ts(self, file_path: str, auto_fix: bool = False) -> LintResult:
514
+ """Check JavaScript/TypeScript file"""
515
+ path = Path(file_path).resolve()
516
+ issues = []
517
+ linters_used = []
518
+
519
+ # Run ESLint
520
+ eslint_cmd = None
521
+ if self._check_command('eslint'):
522
+ eslint_cmd = ['eslint']
523
+ elif self._check_command('npx'):
524
+ eslint_cmd = ['npx', '--yes', 'eslint']
525
+
526
+ if eslint_cmd:
527
+ cmd = eslint_cmd + ['--format=json']
528
+ if auto_fix:
529
+ cmd.append('--fix')
530
+ cmd.append(str(path))
531
+
532
+ try:
533
+ result = subprocess.run(
534
+ cmd, capture_output=True, text=True,
535
+ encoding='utf-8', errors='replace', timeout=30
536
+ )
537
+ eslint_issues = self._parse_eslint_output(result.stdout, str(path))
538
+ issues.extend(eslint_issues)
539
+ linters_used.append('eslint')
540
+ except Exception as e:
541
+ self._log(f"eslint error: {e}")
542
+
543
+ # Run TypeScript compiler for type checking
544
+ if str(path).endswith(('.ts', '.tsx')):
545
+ tsc_cmd = None
546
+ if self._check_command('tsc'):
547
+ tsc_cmd = ['tsc']
548
+ elif self._check_command('npx'):
549
+ tsc_cmd = ['npx', '--yes', 'tsc']
550
+
551
+ if tsc_cmd:
552
+ cmd = tsc_cmd + ['--noEmit', '--pretty', 'false', str(path)]
553
+ try:
554
+ result = subprocess.run(
555
+ cmd, capture_output=True, text=True,
556
+ encoding='utf-8', errors='replace', timeout=60
557
+ )
558
+ tsc_issues = self._parse_tsc_output(result.stdout + result.stderr, str(path))
559
+ issues.extend(tsc_issues)
560
+ if 'tsc' not in linters_used:
561
+ linters_used.append('tsc')
562
+ except Exception as e:
563
+ self._log(f"tsc error: {e}")
564
+
565
+ if not linters_used:
566
+ return LintResult(
567
+ file_path=str(path),
568
+ success=False,
569
+ error_message="No JS/TS linter available. Install: npm install -g eslint typescript"
570
+ )
571
+
572
+ return LintResult(
573
+ file_path=str(path),
574
+ success=True,
575
+ issues=issues,
576
+ linter_used='+'.join(linters_used)
577
+ )
578
+
579
+ def check_file(self, file_path: str, auto_fix: bool = False) -> LintResult:
580
+ """Check a single file for lint issues"""
581
+ path = Path(file_path)
582
+
583
+ if not path.exists():
584
+ return LintResult(
585
+ file_path=str(path),
586
+ success=False,
587
+ error_message=f"File not found: {file_path}"
588
+ )
589
+
590
+ ext = path.suffix.lower()
591
+ language = self.EXTENSION_MAP.get(ext)
592
+
593
+ if language == 'python':
594
+ return self._check_python(str(path), auto_fix)
595
+ elif language in ('typescript', 'javascript', 'vue'):
596
+ return self._check_js_ts(str(path), auto_fix)
597
+ else:
598
+ return LintResult(
599
+ file_path=str(path),
600
+ success=True,
601
+ issues=[],
602
+ error_message=f"No linter configured for extension: {ext}"
603
+ )
604
+
605
+ def check_files(self, file_paths: List[str], auto_fix: bool = False) -> List[LintResult]:
606
+ """Check multiple files (parallel processing)"""
607
+ if len(file_paths) == 1:
608
+ return [self.check_file(file_paths[0], auto_fix)]
609
+
610
+ results = []
611
+ with ThreadPoolExecutor(max_workers=self.max_workers) as executor:
612
+ future_to_path = {
613
+ executor.submit(self.check_file, path, auto_fix): path
614
+ for path in file_paths
615
+ }
616
+ for future in as_completed(future_to_path):
617
+ results.append(future.result())
618
+
619
+ # Sort by original order
620
+ path_order = {path: i for i, path in enumerate(file_paths)}
621
+ results.sort(key=lambda r: path_order.get(r.file_path, 999))
622
+ return results
623
+
624
+ def check_directory(self, dir_path: str, auto_fix: bool = False,
625
+ extensions: Optional[List[str]] = None) -> List[LintResult]:
626
+ """Check all supported files in a directory"""
627
+ path = Path(dir_path)
628
+ if not path.exists():
629
+ return [LintResult(
630
+ file_path=str(path),
631
+ success=False,
632
+ error_message=f"Directory not found: {dir_path}"
633
+ )]
634
+
635
+ if extensions is None:
636
+ extensions = list(self.EXTENSION_MAP.keys())
637
+
638
+ files = []
639
+ for ext in extensions:
640
+ files.extend(path.rglob(f'*{ext}'))
641
+
642
+ exclude_patterns = [
643
+ 'node_modules', '__pycache__', '.git', 'dist', 'build',
644
+ 'venv', '.venv', 'target', '.next', '.nuxt', 'coverage'
645
+ ]
646
+ files = [f for f in files if not any(p in str(f) for p in exclude_patterns)]
647
+
648
+ return self.check_files([str(f) for f in files], auto_fix)
649
+
650
+
651
+ def print_dependencies(deps: List[DependencyStatus]) -> None:
652
+ """Print dependency status"""
653
+ print("\n" + "=" * 60)
654
+ print("šŸ”§ LINTER DEPENDENCIES")
655
+ print("=" * 60)
656
+
657
+ for dep in deps:
658
+ status = "āœ…" if dep.available else "āŒ"
659
+ version = f" ({dep.version})" if dep.version else ""
660
+ print(f" {status} {dep.name}{version}")
661
+ if not dep.available and dep.install_cmd:
662
+ print(f" Install: {dep.install_cmd}")
663
+
664
+ print("=" * 60)
665
+
666
+
667
+ def print_issues(results: List[LintResult], summary_only: bool = False,
668
+ json_output: bool = False) -> None:
669
+ """Print lint issues with formatting"""
670
+ if json_output:
671
+ output = {
672
+ 'results': [r.to_dict() for r in results],
673
+ 'summary': {
674
+ 'total_files': len(results),
675
+ 'p0': sum(r.p0_count for r in results),
676
+ 'p1': sum(r.p1_count for r in results),
677
+ 'p2': sum(r.p2_count for r in results),
678
+ 'p3': sum(r.p3_count for r in results),
679
+ 'blocking': any(r.has_blocking_issues for r in results)
680
+ }
681
+ }
682
+ print(json.dumps(output, indent=2, ensure_ascii=False))
683
+ return
684
+
685
+ print("\n" + "=" * 70)
686
+ print("šŸ” LINT CHECK RESULTS")
687
+ print("=" * 70)
688
+
689
+ total_p0 = sum(r.p0_count for r in results)
690
+ total_p1 = sum(r.p1_count for r in results)
691
+ total_p2 = sum(r.p2_count for r in results)
692
+ total_p3 = sum(r.p3_count for r in results)
693
+
694
+ if not summary_only:
695
+ for result in results:
696
+ if result.error_message and not result.success:
697
+ print(f"\nāŒ {result.file_path}")
698
+ print(f" Error: {result.error_message}")
699
+ continue
700
+
701
+ if not result.issues:
702
+ print(f"\nāœ… {result.file_path} - No issues [{result.linter_used}]")
703
+ continue
704
+
705
+ print(f"\nšŸ“„ {result.file_path} [{result.linter_used}]")
706
+
707
+ priority_emoji = {
708
+ Priority.P0: "šŸ”“ P0 (CRITICAL)",
709
+ Priority.P1: "🟠 P1 (ERROR)",
710
+ Priority.P2: "🟔 P2 (WARNING)",
711
+ Priority.P3: "⚪ P3 (INFO)"
712
+ }
713
+
714
+ for priority in Priority:
715
+ priority_issues = [i for i in result.issues if i.priority == priority]
716
+ if not priority_issues:
717
+ continue
718
+
719
+ print(f"\n {priority_emoji[priority]}:")
720
+ for issue in priority_issues[:10]: # Limit to 10 per priority
721
+ fix_indicator = "šŸ”§" if issue.fixable else ""
722
+ print(f" L{issue.line}:{issue.column} [{issue.rule_id}] {issue.message} {fix_indicator}")
723
+ if issue.suggestion:
724
+ print(f" šŸ’” {issue.suggestion}")
725
+
726
+ if len(priority_issues) > 10:
727
+ print(f" ... and {len(priority_issues) - 10} more")
728
+
729
+ # Summary
730
+ print("\n" + "-" * 70)
731
+ print("šŸ“Š SUMMARY")
732
+ print("-" * 70)
733
+ print(f" šŸ”“ P0 (Critical): {total_p0}")
734
+ print(f" 🟠 P1 (Error): {total_p1}")
735
+ print(f" 🟔 P2 (Warning): {total_p2}")
736
+ print(f" ⚪ P3 (Info): {total_p3}")
737
+ print(f" ─────────────────────")
738
+ print(f" Total Issues: {total_p0 + total_p1 + total_p2 + total_p3}")
739
+
740
+ if total_p0 + total_p1 > 0:
741
+ print("\n āŒ STATUS: BLOCKING - Must fix P0/P1 issues before commit")
742
+ elif total_p2 > 0:
743
+ print("\n āš ļø STATUS: WARNING - Should fix P2 issues")
744
+ else:
745
+ print("\n āœ… STATUS: PASS - No blocking issues")
746
+
747
+ print("=" * 70)
748
+
749
+
750
+ def main() -> int:
751
+ parser = argparse.ArgumentParser(
752
+ description="Check code files for lint errors and warnings",
753
+ formatter_class=argparse.RawDescriptionHelpFormatter,
754
+ epilog="""
755
+ Examples:
756
+ python lint_check.py src/app.py # Check single file
757
+ python lint_check.py src/app.py src/utils.ts # Check multiple files (parallel)
758
+ python lint_check.py --dir src/ # Check directory
759
+ python lint_check.py src/app.py --fix # Auto-fix if possible
760
+ python lint_check.py --check-deps # Check linter dependencies
761
+ python lint_check.py src/app.py --json # JSON output for CI/CD
762
+ """
763
+ )
764
+ parser.add_argument('files', nargs='*', help='Files to check')
765
+ parser.add_argument('--dir', '-d', help='Check all supported files in directory')
766
+ parser.add_argument('--fix', '-f', action='store_true', help='Attempt to auto-fix issues')
767
+ parser.add_argument('--check-deps', action='store_true', help='Check linter dependencies')
768
+ parser.add_argument('--summary-only', '-s', action='store_true', help='Only show summary')
769
+ parser.add_argument('--json', '-j', action='store_true', help='Output results as JSON')
770
+ parser.add_argument('--verbose', '-v', action='store_true', help='Show detailed output')
771
+ parser.add_argument('--ext', action='append', help='File extensions to check')
772
+ parser.add_argument('--workers', '-w', type=int, default=4, help='Number of parallel workers')
773
+
774
+ args = parser.parse_args()
775
+
776
+ checker = LintChecker(verbose=args.verbose, max_workers=args.workers)
777
+
778
+ # Check dependencies mode
779
+ if args.check_deps:
780
+ deps = checker.check_dependencies()
781
+ if args.json:
782
+ print(json.dumps([asdict(d) for d in deps], indent=2))
783
+ else:
784
+ print_dependencies(deps)
785
+ return 0 if all(d.available for d in deps) else 3
786
+
787
+ if not args.files and not args.dir:
788
+ parser.print_help()
789
+ return 1
790
+
791
+ if args.dir:
792
+ results = checker.check_directory(args.dir, auto_fix=args.fix, extensions=args.ext)
793
+ else:
794
+ results = checker.check_files(args.files, auto_fix=args.fix)
795
+
796
+ print_issues(results, summary_only=args.summary_only, json_output=args.json)
797
+
798
+ # Determine exit code
799
+ total_p0 = sum(r.p0_count for r in results)
800
+ total_p1 = sum(r.p1_count for r in results)
801
+ total_p2 = sum(r.p2_count for r in results)
802
+
803
+ if not all(r.success for r in results):
804
+ if any("not available" in (r.error_message or "") for r in results):
805
+ return 3
806
+
807
+ if total_p0 + total_p1 > 0:
808
+ return 1
809
+ elif total_p2 > 0:
810
+ return 2
811
+
812
+ return 0
813
+
814
+
815
+ if __name__ == "__main__":
816
+ sys.exit(main())