sinapse-ai 1.12.2 → 1.14.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 (244) hide show
  1. package/.claude/CLAUDE.md +2 -2
  2. package/.claude/rules/agent-memory-imports.md +4 -0
  3. package/.sinapse-ai/cli/commands/pro/index.js +8 -48
  4. package/.sinapse-ai/constitution.md +6 -2
  5. package/.sinapse-ai/data/entity-registry.yaml +63 -429
  6. package/.sinapse-ai/development/agents/analyst/MEMORY.md +19 -0
  7. package/.sinapse-ai/development/agents/architect/MEMORY.md +52 -0
  8. package/.sinapse-ai/development/agents/data-engineer/MEMORY.md +55 -0
  9. package/.sinapse-ai/development/agents/developer/MEMORY.md +53 -0
  10. package/.sinapse-ai/development/agents/devops/MEMORY.md +56 -0
  11. package/.sinapse-ai/development/agents/product-lead/MEMORY.md +53 -0
  12. package/.sinapse-ai/development/agents/project-lead/MEMORY.md +53 -0
  13. package/.sinapse-ai/development/agents/quality-gate/MEMORY.md +52 -0
  14. package/.sinapse-ai/development/agents/snps-orqx.md +15 -0
  15. package/.sinapse-ai/development/agents/sprint-lead/MEMORY.md +53 -0
  16. package/.sinapse-ai/development/agents/squad-creator.md +15 -0
  17. package/.sinapse-ai/development/agents/ux/MEMORY.md +21 -0
  18. package/.sinapse-ai/development/templates/chrome-brain/knowledge-base/chrome-brain.md +2 -2
  19. package/.sinapse-ai/infrastructure/scripts/ide-sync/index.js +15 -0
  20. package/.sinapse-ai/infrastructure/scripts/validate-agents.js +159 -8
  21. package/.sinapse-ai/install-manifest.yaml +16 -152
  22. package/AGENTS.md +13 -2
  23. package/CHANGELOG.md +135 -3
  24. package/README.en.md +1 -1
  25. package/README.md +6 -26
  26. package/bin/cli.js +2 -7
  27. package/bin/commands/install.js +19 -257
  28. package/bin/commands/update.js +18 -78
  29. package/bin/lib/command-generator.js +261 -0
  30. package/bin/lib/prompts.js +2 -65
  31. package/bin/modules/chrome-brain-installer.js +2 -1
  32. package/bin/postinstall.js +6 -6
  33. package/docs/getting-started.md +0 -1
  34. package/docs/pt/getting-started.md +1 -1
  35. package/docs/security/dependabot-triage.md +17 -17
  36. package/package.json +6 -3
  37. package/packages/installer/src/wizard/i18n.js +3 -204
  38. package/packages/installer/src/wizard/index.js +1 -1
  39. package/packages/installer/src/wizard/questions.js +5 -368
  40. package/packages/installer/src/wizard/wizard.js +0 -9
  41. package/scripts/generate-install-manifest.js +6 -0
  42. package/scripts/validate-changelog-tags.js +97 -0
  43. package/scripts/validate-no-personal-leaks.js +184 -28
  44. package/scripts/validate-schemas.js +55 -10
  45. package/scripts/validate-story-meta.js +25 -12
  46. package/squads/claude-code-mastery/agents/claude-mastery-chief.md +15 -1
  47. package/squads/claude-code-mastery/agents/config-engineer.md +15 -0
  48. package/squads/claude-code-mastery/agents/hooks-architect.md +27 -20
  49. package/squads/claude-code-mastery/agents/mcp-integrator.md +15 -0
  50. package/squads/claude-code-mastery/agents/project-integrator.md +15 -0
  51. package/squads/claude-code-mastery/agents/roadmap-sentinel.md +15 -0
  52. package/squads/claude-code-mastery/agents/skill-craftsman.md +15 -0
  53. package/squads/claude-code-mastery/agents/swarm-orqx.md +15 -0
  54. package/squads/claude-code-mastery/tasks/audit-setup.md +1 -1
  55. package/squads/squad-animations/agents/animation-interpreter.md +15 -0
  56. package/squads/squad-animations/agents/animation-performance-engineer.md +15 -0
  57. package/squads/squad-animations/agents/animations-orqx.md +13 -0
  58. package/squads/squad-animations/agents/css-motion-artist.md +15 -0
  59. package/squads/squad-animations/agents/generative-particle-engineer.md +15 -0
  60. package/squads/squad-animations/agents/motion-choreographer.md +15 -0
  61. package/squads/squad-animations/agents/scroll-narrative-engineer.md +15 -0
  62. package/squads/squad-animations/agents/shader-artist.md +15 -0
  63. package/squads/squad-animations/agents/threejs-architect.md +15 -0
  64. package/squads/squad-brand/agents/brand-archetype-strategist.md +13 -0
  65. package/squads/squad-brand/agents/brand-auditor.md +15 -0
  66. package/squads/squad-brand/agents/brand-collateral-designer.md +15 -0
  67. package/squads/squad-brand/agents/brand-compiler.md +13 -0
  68. package/squads/squad-brand/agents/brand-creative-engineer.md +15 -0
  69. package/squads/squad-brand/agents/brand-culture-architect.md +15 -0
  70. package/squads/squad-brand/agents/brand-growth-strategist.md +15 -0
  71. package/squads/squad-brand/agents/brand-identity-designer.md +15 -0
  72. package/squads/squad-brand/agents/brand-motion-vfx.md +15 -0
  73. package/squads/squad-brand/agents/brand-naming-specialist.md +15 -0
  74. package/squads/squad-brand/agents/brand-orqx.md +13 -0
  75. package/squads/squad-brand/agents/brand-positioning-strategist.md +15 -0
  76. package/squads/squad-brand/agents/brand-sonic-designer.md +15 -0
  77. package/squads/squad-brand/agents/brand-strategist.md +15 -0
  78. package/squads/squad-brand/agents/brand-system-architect.md +15 -0
  79. package/squads/squad-cloning/agents/agent-forger.md +15 -0
  80. package/squads/squad-cloning/agents/cloning-orqx.md +15 -0
  81. package/squads/squad-cloning/agents/cognitive-extractor.md +15 -0
  82. package/squads/squad-cloning/agents/content-capturer.md +15 -0
  83. package/squads/squad-cloning/agents/kb-architect.md +15 -0
  84. package/squads/squad-cloning/agents/mind-synthesizer.md +15 -0
  85. package/squads/squad-cloning/agents/sop-extractor.md +15 -0
  86. package/squads/squad-cloning/agents/source-hunter.md +13 -0
  87. package/squads/squad-cloning/agents/squad-assembler.md +15 -0
  88. package/squads/squad-commercial/agents/commercial-orqx.md +13 -0
  89. package/squads/squad-commercial/agents/cs-business-auditor.md +15 -0
  90. package/squads/squad-commercial/agents/cs-client-success.md +15 -0
  91. package/squads/squad-commercial/agents/cs-crm-specialist.md +15 -0
  92. package/squads/squad-commercial/agents/cs-funnel-architect.md +15 -0
  93. package/squads/squad-commercial/agents/cs-lead-generation-strategist.md +15 -0
  94. package/squads/squad-commercial/agents/cs-offer-designer.md +15 -0
  95. package/squads/squad-commercial/agents/cs-revops-analyst.md +15 -0
  96. package/squads/squad-commercial/agents/cs-sales-closer.md +13 -0
  97. package/squads/squad-commercial/agents/cs-sales-enablement.md +15 -0
  98. package/squads/squad-content/agents/content-analyst.md +13 -0
  99. package/squads/squad-content/agents/content-engineer.md +15 -0
  100. package/squads/squad-content/agents/content-governor.md +13 -0
  101. package/squads/squad-content/agents/content-orqx.md +13 -0
  102. package/squads/squad-content/agents/editorial-strategist.md +15 -0
  103. package/squads/squad-content/agents/platform-specialist.md +15 -0
  104. package/squads/squad-content/agents/signal-intelligence.md +13 -0
  105. package/squads/squad-copy/agents/ad-copywriter.md +13 -0
  106. package/squads/squad-copy/agents/brand-voice-writer.md +15 -0
  107. package/squads/squad-copy/agents/conversion-writer.md +13 -0
  108. package/squads/squad-copy/agents/copy-editor.md +15 -0
  109. package/squads/squad-copy/agents/copy-orqx.md +13 -0
  110. package/squads/squad-copy/agents/copy-strategist.md +15 -0
  111. package/squads/squad-copy/agents/direct-response-writer.md +15 -0
  112. package/squads/squad-copy/agents/email-sequence-strategist.md +15 -0
  113. package/squads/squad-copy/agents/funnel-copywriter.md +15 -0
  114. package/squads/squad-copy/agents/headline-specialist.md +13 -0
  115. package/squads/squad-copy/agents/long-form-writer.md +15 -0
  116. package/squads/squad-copy/agents/persuasion-psychologist.md +15 -0
  117. package/squads/squad-copy/agents/proof-architect.md +15 -0
  118. package/squads/squad-council/agents/brene-brown.md +13 -0
  119. package/squads/squad-council/agents/charlie-munger.md +13 -0
  120. package/squads/squad-council/agents/council-orqx.md +13 -0
  121. package/squads/squad-council/agents/derek-sivers.md +13 -0
  122. package/squads/squad-council/agents/naval-ravikant.md +13 -0
  123. package/squads/squad-council/agents/patrick-lencioni.md +15 -0
  124. package/squads/squad-council/agents/peter-thiel.md +13 -0
  125. package/squads/squad-council/agents/ray-dalio.md +13 -0
  126. package/squads/squad-council/agents/reid-hoffman.md +13 -0
  127. package/squads/squad-council/agents/simon-sinek.md +15 -0
  128. package/squads/squad-council/agents/yvon-chouinard.md +13 -0
  129. package/squads/squad-courses/agents/assessment-creator.md +15 -0
  130. package/squads/squad-courses/agents/content-writer.md +15 -0
  131. package/squads/squad-courses/agents/courses-orqx.md +15 -0
  132. package/squads/squad-courses/agents/curriculum-designer.md +15 -0
  133. package/squads/squad-courses/agents/launch-strategist.md +15 -0
  134. package/squads/squad-courses/agents/lesson-architect.md +15 -0
  135. package/squads/squad-courses/agents/production-director.md +13 -0
  136. package/squads/squad-courses/agents/slide-designer.md +15 -0
  137. package/squads/squad-cybersecurity/agents/cloud-security-engineer.md +15 -0
  138. package/squads/squad-cybersecurity/agents/compliance-officer.md +15 -0
  139. package/squads/squad-cybersecurity/agents/cyber-orqx.md +15 -0
  140. package/squads/squad-cybersecurity/agents/incident-responder.md +15 -0
  141. package/squads/squad-cybersecurity/agents/network-security-engineer.md +15 -0
  142. package/squads/squad-cybersecurity/agents/penetration-tester.md +15 -0
  143. package/squads/squad-cybersecurity/agents/soc-analyst.md +15 -0
  144. package/squads/squad-cybersecurity/agents/threat-analyst.md +15 -0
  145. package/squads/squad-design/agents/cro-persuasion.md +15 -0
  146. package/squads/squad-design/agents/design-orqx.md +13 -0
  147. package/squads/squad-design/agents/design-system.md +15 -0
  148. package/squads/squad-design/agents/dx-accessibility-specialist.md +15 -0
  149. package/squads/squad-design/agents/dx-design-system-architect.md +15 -0
  150. package/squads/squad-design/agents/dx-frontend-engineer.md +15 -0
  151. package/squads/squad-design/agents/dx-interaction-designer.md +15 -0
  152. package/squads/squad-design/agents/dx-performance-engineer.md +15 -0
  153. package/squads/squad-design/agents/dx-ui-designer.md +15 -0
  154. package/squads/squad-design/agents/dx-ux-strategist.md +15 -0
  155. package/squads/squad-design/agents/platform-aesthetic-director.md +15 -0
  156. package/squads/squad-design/agents/premium-packaging-strategist.md +15 -0
  157. package/squads/squad-design/agents/product-surface-director.md +15 -0
  158. package/squads/squad-design/agents/ux-designer.md +15 -0
  159. package/squads/squad-finance/agents/budget-controller.md +15 -0
  160. package/squads/squad-finance/agents/cost-optimizer.md +15 -0
  161. package/squads/squad-finance/agents/finance-orqx.md +15 -0
  162. package/squads/squad-finance/agents/fiscal-compliance-br.md +15 -0
  163. package/squads/squad-finance/agents/forecast-strategist.md +15 -0
  164. package/squads/squad-finance/agents/pricing-strategist.md +15 -0
  165. package/squads/squad-finance/agents/profitability-analyst.md +15 -0
  166. package/squads/squad-finance/agents/revenue-analyst.md +15 -0
  167. package/squads/squad-growth/agents/ga-analytics-engineer.md +15 -0
  168. package/squads/squad-growth/agents/ga-campaign-analyst.md +15 -0
  169. package/squads/squad-growth/agents/ga-cro-specialist.md +15 -0
  170. package/squads/squad-growth/agents/ga-data-analyst.md +13 -0
  171. package/squads/squad-growth/agents/ga-growth-hacker.md +15 -0
  172. package/squads/squad-growth/agents/ga-seo-strategist.md +15 -0
  173. package/squads/squad-growth/agents/growth-orqx.md +15 -0
  174. package/squads/squad-paidmedia/agents/campaign-analyst.md +15 -0
  175. package/squads/squad-paidmedia/agents/creative-strategist.md +15 -0
  176. package/squads/squad-paidmedia/agents/cro-specialist.md +15 -0
  177. package/squads/squad-paidmedia/agents/google-ads-specialist.md +15 -0
  178. package/squads/squad-paidmedia/agents/meta-ads-specialist.md +15 -0
  179. package/squads/squad-paidmedia/agents/paidmedia-orqx.md +15 -0
  180. package/squads/squad-paidmedia/agents/performance-engineer.md +15 -0
  181. package/squads/squad-paidmedia/agents/pm-creative-performance-analyst.md +15 -0
  182. package/squads/squad-paidmedia/agents/pm-youtube-ads-specialist.md +15 -0
  183. package/squads/squad-product/agents/product-orqx.md +13 -1
  184. package/squads/squad-product/agents/ps-client-product-manager.md +13 -1
  185. package/squads/squad-product/agents/ps-delivery-manager.md +13 -1
  186. package/squads/squad-product/agents/ps-discovery-lead.md +15 -1
  187. package/squads/squad-product/agents/ps-product-analyst.md +15 -1
  188. package/squads/squad-product/agents/ps-product-ops-specialist.md +15 -1
  189. package/squads/squad-product/agents/ps-product-strategist.md +15 -1
  190. package/squads/squad-research/agents/audience-intelligence.md +15 -0
  191. package/squads/squad-research/agents/competitive-intelligence.md +15 -0
  192. package/squads/squad-research/agents/data-synthesizer.md +15 -0
  193. package/squads/squad-research/agents/deep-researcher.md +15 -0
  194. package/squads/squad-research/agents/market-analyst.md +15 -0
  195. package/squads/squad-research/agents/research-orqx.md +15 -0
  196. package/squads/squad-research/agents/trend-forecaster.md +15 -0
  197. package/squads/squad-storytelling/agents/blake-snyder.md +13 -0
  198. package/squads/squad-storytelling/agents/dan-harmon.md +13 -0
  199. package/squads/squad-storytelling/agents/joseph-campbell.md +13 -0
  200. package/squads/squad-storytelling/agents/keith-johnstone.md +13 -0
  201. package/squads/squad-storytelling/agents/kindra-hall.md +15 -0
  202. package/squads/squad-storytelling/agents/marshall-ganz.md +15 -0
  203. package/squads/squad-storytelling/agents/nancy-duarte.md +15 -0
  204. package/squads/squad-storytelling/agents/oren-klaff.md +15 -0
  205. package/squads/squad-storytelling/agents/park-howell.md +13 -0
  206. package/squads/squad-storytelling/agents/storytelling-orqx.md +13 -0
  207. package/.sinapse-ai/core/grounding/README.md +0 -83
  208. package/.sinapse-ai/core/grounding/brand.cjs +0 -29
  209. package/.sinapse-ai/core/grounding/config-loader.cjs +0 -52
  210. package/.sinapse-ai/core/grounding/design-system.cjs +0 -29
  211. package/.sinapse-ai/core/grounding/vault.cjs +0 -36
  212. package/.sinapse-ai/development/scripts/approval-workflow.js +0 -643
  213. package/.sinapse-ai/development/scripts/backup-manager.js +0 -607
  214. package/.sinapse-ai/development/scripts/branch-manager.js +0 -390
  215. package/.sinapse-ai/development/scripts/code-quality-improver.js +0 -1329
  216. package/.sinapse-ai/development/scripts/commit-message-generator.js +0 -850
  217. package/.sinapse-ai/development/scripts/conflict-resolver.js +0 -675
  218. package/.sinapse-ai/development/scripts/dependency-analyzer.js +0 -638
  219. package/.sinapse-ai/development/scripts/diff-generator.js +0 -352
  220. package/.sinapse-ai/development/scripts/git-wrapper.js +0 -462
  221. package/.sinapse-ai/development/scripts/modification-validator.js +0 -555
  222. package/.sinapse-ai/development/scripts/performance-analyzer.js +0 -758
  223. package/.sinapse-ai/development/scripts/refactoring-suggester.js +0 -1148
  224. package/.sinapse-ai/development/scripts/rollback-handler.js +0 -531
  225. package/.sinapse-ai/development/scripts/security-checker.js +0 -359
  226. package/.sinapse-ai/development/scripts/template-engine.js +0 -240
  227. package/.sinapse-ai/development/scripts/template-validator.js +0 -279
  228. package/.sinapse-ai/development/scripts/test-generator.js +0 -844
  229. package/.sinapse-ai/development/scripts/transaction-manager.js +0 -590
  230. package/.sinapse-ai/development/scripts/yaml-validator.js +0 -397
  231. package/.sinapse-ai/hooks/sinapse-brand-grounding.cjs +0 -162
  232. package/.sinapse-ai/hooks/sinapse-ds-grounding.cjs +0 -211
  233. package/.sinapse-ai/hooks/sinapse-vault-grounding.cjs +0 -194
  234. package/bin/lib/register-grounding-hooks.js +0 -145
  235. package/docs/guides/agents/traces/execution-traces.zip +0 -0
  236. package/docs/guides/grounding-setup.md +0 -154
  237. package/docs/guides/workflows/SINAPSE-WORKFLOWS.zip +0 -0
  238. package/packages/installer/src/pro/pro-scaffolder.js +0 -449
  239. package/packages/installer/src/wizard/grounding-config.js +0 -131
  240. package/packages/installer/src/wizard/pro-setup.js +0 -1439
  241. package/packages/installer/templates/README.md +0 -16
  242. package/packages/installer/templates/brand-routing.example.json +0 -12
  243. package/packages/installer/templates/ds-routing.example.json +0 -12
  244. package/packages/installer/templates/vault-routing.example.json +0 -12
@@ -1,1329 +0,0 @@
1
- const fs = require('fs').promises;
2
- const path = require('path');
3
- const chalk = require('chalk');
4
-
5
- // INS-4.12: Optional dev-time deps — wrap in try-catch for brownfield installs
6
- let ESLint, prettier, jscodeshift;
7
- try { ({ ESLint } = require('eslint')); } catch { ESLint = null; }
8
- try { prettier = require('prettier'); } catch { prettier = null; }
9
- try { jscodeshift = require('jscodeshift'); } catch { jscodeshift = null; }
10
-
11
- /**
12
- * Automated code quality improvement system
13
- * Applies automatic fixes and improvements to enhance code quality
14
- */
15
- class CodeQualityImprover {
16
- constructor(options = {}) {
17
- this.rootPath = options.rootPath || process.cwd();
18
- this.improvements = [];
19
- this.metrics = new Map();
20
- this.eslint = null;
21
- this.prettierConfig = null;
22
- this.improvementPatterns = new Map();
23
- this.initializePatterns();
24
- }
25
-
26
- /**
27
- * Initialize improvement patterns
28
- */
29
- initializePatterns() {
30
- // Code formatting improvements
31
- this.improvementPatterns.set('formatting', {
32
- name: 'Code Formatting',
33
- description: 'Apply consistent code formatting',
34
- improver: this.improveFormatting.bind(this),
35
- priority: 'medium',
36
- automatic: true
37
- });
38
-
39
- // Linting fixes
40
- this.improvementPatterns.set('linting', {
41
- name: 'Linting Fixes',
42
- description: 'Fix linting errors and warnings',
43
- improver: this.improveLinting.bind(this),
44
- priority: 'high',
45
- automatic: true
46
- });
47
-
48
- // Modern syntax upgrades
49
- this.improvementPatterns.set('modern_syntax', {
50
- name: 'Modern Syntax',
51
- description: 'Upgrade to modern JavaScript syntax',
52
- improver: this.upgradeToModernSyntax.bind(this),
53
- priority: 'medium',
54
- automatic: true
55
- });
56
-
57
- // Import optimization
58
- this.improvementPatterns.set('optimize_imports', {
59
- name: 'Optimize Imports',
60
- description: 'Organize and optimize import statements',
61
- improver: this.optimizeImports.bind(this),
62
- priority: 'low',
63
- automatic: true
64
- });
65
-
66
- // Dead code elimination
67
- this.improvementPatterns.set('remove_unused', {
68
- name: 'Remove Unused Code',
69
- description: 'Remove unused variables and functions',
70
- improver: this.removeUnusedCode.bind(this),
71
- priority: 'high',
72
- automatic: false
73
- });
74
-
75
- // Consistent naming
76
- this.improvementPatterns.set('naming_conventions', {
77
- name: 'Naming Conventions',
78
- description: 'Apply consistent naming conventions',
79
- improver: this.improveNaming.bind(this),
80
- priority: 'medium',
81
- automatic: false
82
- });
83
-
84
- // Error handling improvements
85
- this.improvementPatterns.set('error_handling', {
86
- name: 'Error Handling',
87
- description: 'Improve error handling patterns',
88
- improver: this.improveErrorHandling.bind(this),
89
- priority: 'high',
90
- automatic: false
91
- });
92
-
93
- // Async/await conversion
94
- this.improvementPatterns.set('async_await', {
95
- name: 'Async/Await Conversion',
96
- description: 'Convert promises to async/await',
97
- improver: this.convertToAsyncAwait.bind(this),
98
- priority: 'medium',
99
- automatic: true
100
- });
101
-
102
- // Type safety improvements
103
- this.improvementPatterns.set('type_safety', {
104
- name: 'Type Safety',
105
- description: 'Add type checks and validations',
106
- improver: this.improveTypeSafety.bind(this),
107
- priority: 'high',
108
- automatic: false
109
- });
110
-
111
- // Documentation generation
112
- this.improvementPatterns.set('documentation', {
113
- name: 'Documentation',
114
- description: 'Generate missing JSDoc comments',
115
- improver: this.generateDocumentation.bind(this),
116
- priority: 'medium',
117
- automatic: false
118
- });
119
- }
120
-
121
- /**
122
- * Initialize tools
123
- */
124
- async initialize() {
125
- // INS-4.12: Guard optional deps — may be null in brownfield installs
126
- if (ESLint) {
127
- this.eslint = new ESLint({
128
- fix: true,
129
- baseConfig: await this.loadESLintConfig(),
130
- useEslintrc: true
131
- });
132
- } else {
133
- console.warn('⚠️ eslint not available — linting improvements disabled');
134
- }
135
-
136
- if (prettier) {
137
- this.prettierConfig = await this.loadPrettierConfig();
138
- } else {
139
- console.warn('⚠️ prettier not available — formatting improvements disabled');
140
- }
141
- }
142
-
143
- /**
144
- * Analyze and improve code quality
145
- */
146
- async improveCode(_filePath, options = {}) {
147
- console.log(chalk.blue(`🎯 Improving: ${_filePath}`));
148
-
149
- try {
150
- const content = await fs.readFile(_filePath, 'utf-8');
151
- const fileType = path.extname(_filePath);
152
-
153
- if (!['.js', '.jsx', '.ts', '.tsx'].includes(fileType)) {
154
- return {
155
- _filePath,
156
- improvements: [],
157
- error: 'Unsupported file type'
158
- };
159
- }
160
-
161
- // Calculate initial metrics
162
- const initialMetrics = await this.calculateMetrics(content, filePath);
163
- this.metrics.set(_filePath, { before: initialMetrics });
164
-
165
- // Clear previous improvements
166
- this.improvements = [];
167
-
168
- let improvedContent = content;
169
- const appliedImprovements = [];
170
-
171
- // Apply improvement patterns
172
- for (const [patternId, pattern] of this.improvementPatterns) {
173
- if (options.patterns && !options.patterns.includes(patternId)) {
174
- continue;
175
- }
176
-
177
- if (!options.manual && !pattern.automatic) {
178
- continue; // Skip manual improvements in automatic mode
179
- }
180
-
181
- try {
182
- const result = await pattern.improver(improvedContent, _filePath, options);
183
-
184
- if (result.improved) {
185
- improvedContent = result.content;
186
- appliedImprovements.push({
187
- patternId,
188
- pattern: pattern.name,
189
- priority: pattern.priority,
190
- changes: result.changes,
191
- impact: result.impact || 'medium'
192
- });
193
-
194
- this.improvements.push(...result.improvements || []);
195
- }
196
- } catch (_error) {
197
- console.warn(chalk.yellow(`Failed to apply ${pattern.name}: ${error.message}`));
198
- }
199
- }
200
-
201
- // Calculate final metrics
202
- const finalMetrics = await this.calculateMetrics(improvedContent, filePath);
203
- this.metrics.get(_filePath).after = finalMetrics;
204
-
205
- // Calculate improvement score
206
- const improvementScore = this.calculateImprovementScore(initialMetrics, finalMetrics);
207
-
208
- return {
209
- _filePath,
210
- originalContent: content,
211
- improvedContent,
212
- improvements: appliedImprovements,
213
- metrics: {
214
- before: initialMetrics,
215
- after: finalMetrics,
216
- improvementScore
217
- },
218
- changed: content !== improvedContent
219
- };
220
-
221
- } catch (_error) {
222
- return {
223
- _filePath,
224
- improvements: [],
225
- error: error.message
226
- };
227
- }
228
- }
229
-
230
- /**
231
- * Calculate code metrics
232
- */
233
- async calculateMetrics(content, filePath) {
234
- const metrics = {
235
- lines: content.split('\n').length,
236
- complexity: 0,
237
- maintainability: 0,
238
- issues: 0,
239
- coverage: 0
240
- };
241
-
242
- try {
243
- // Linting issues
244
- if (!this.eslint) return metrics;
245
- const lintResults = await this.eslint.lintText(content, { _filePath });
246
- metrics.issues = lintResults[0]?.errorCount + lintResults[0]?.warningCount || 0;
247
-
248
- // Cyclomatic complexity (simplified)
249
- metrics.complexity = this.calculateCyclomaticComplexity(content);
250
-
251
- // Maintainability index (simplified)
252
- metrics.maintainability = this.calculateMaintainabilityIndex(content);
253
-
254
- // Documentation coverage
255
- metrics.coverage = this.calculateDocumentationCoverage(content);
256
-
257
- } catch (_error) {
258
- // Metrics calculation failed, use defaults
259
- }
260
-
261
- return metrics;
262
- }
263
-
264
- // Improvement functions
265
-
266
- async improveFormatting(content, _filePath, options) {
267
- try {
268
- if (!prettier) {
269
- return { improved: false, content, changes: [] };
270
- }
271
- const formatted = await prettier.format(content, {
272
- ...this.prettierConfig,
273
- filepath: _filePath
274
- });
275
-
276
- return {
277
- improved: formatted !== content,
278
- content: formatted,
279
- changes: formatted !== content ? ['Applied consistent formatting'] : [],
280
- improvements: [{
281
- type: 'formatting',
282
- description: 'Applied Prettier formatting',
283
- line: 0
284
- }]
285
- };
286
- } catch (_error) {
287
- return { improved: false, content, error: error.message };
288
- }
289
- }
290
-
291
- async improveLinting(content, _filePath, options) {
292
- try {
293
- if (!this.eslint) {
294
- return { improved: false, content, changes: [] };
295
- }
296
- const results = await this.eslint.lintText(content, { _filePath });
297
-
298
- if (results[0]?.output) {
299
- return {
300
- improved: true,
301
- content: results[0].output,
302
- changes: this.summarizeLintFixes(results[0]),
303
- improvements: results[0].messages.map(msg => ({
304
- type: 'linting',
305
- description: msg.message,
306
- line: msg.line,
307
- severity: msg.severity === 2 ? 'error' : 'warning'
308
- }))
309
- };
310
- }
311
-
312
- return { improved: false, content };
313
- } catch (_error) {
314
- return { improved: false, content, error: error.message };
315
- }
316
- }
317
-
318
- async upgradeToModernSyntax(content, _filePath, options) {
319
- const j = jscodeshift;
320
- let improved = false;
321
- const changes = [];
322
-
323
- try {
324
- // Convert var to let/const
325
- let ast = j(content);
326
- const _varToLetConst = ast
327
- .find(j.VariableDeclaration, { kind: 'var' })
328
- .forEach(path => {
329
- const isReassigned = this.isVariableReassigned(j, path);
330
- path.node.kind = isReassigned ? 'let' : 'const';
331
- improved = true;
332
- });
333
-
334
- if (improved) {
335
- changes.push('Converted var to let/const');
336
- }
337
-
338
- // Convert function expressions to arrow functions (where appropriate)
339
- ast.find(j.FunctionExpression)
340
- .filter(path => {
341
- // Don't convert if it uses 'this' or 'arguments'
342
- const usesThis = j(_path).find(j.ThisExpression).length > 0;
343
- const usesArguments = j(_path).find(j.Identifier, { name: 'arguments' }).length > 0;
344
- return !usesThis && !usesArguments && !path.node.id;
345
- })
346
- .forEach(path => {
347
- const arrowFunction = j.arrowFunctionExpression(
348
- path.node.params,
349
- path.node.body,
350
- path.node.body.type !== 'BlockStatement'
351
- );
352
- j(_path).replaceWith(arrowFunction);
353
- improved = true;
354
- });
355
-
356
- if (changes.length > 0) {
357
- changes.push('Converted function expressions to arrow functions');
358
- }
359
-
360
- // Template literals
361
- ast.find(j.BinaryExpression, { operator: '+' })
362
- .filter(path => {
363
- // Check if it's string concatenation
364
- return path.node.left.type === 'Literal' || path.node.right.type === 'Literal';
365
- })
366
- .forEach(path => {
367
- // Convert to template literal (simplified)
368
- improved = true;
369
- });
370
-
371
- const result = ast.toSource();
372
-
373
- return {
374
- improved,
375
- content: improved ? result : content,
376
- changes,
377
- improvements: changes.map(change => ({
378
- type: 'modern_syntax',
379
- description: change,
380
- line: 0
381
- }))
382
- };
383
-
384
- } catch (_error) {
385
- return { improved: false, content, error: error.message };
386
- }
387
- }
388
-
389
- async optimizeImports(content, _filePath, options) {
390
- const j = jscodeshift;
391
- let improved = false;
392
- const changes = [];
393
-
394
- try {
395
- const ast = j(content);
396
-
397
- // Group imports by source
398
- const imports = new Map();
399
-
400
- ast.find(j.ImportDeclaration)
401
- .forEach(path => {
402
- const source = path.node.source.value;
403
- if (!imports.has(source)) {
404
- imports.set(source, []);
405
- }
406
- imports.get(source).push(_path);
407
- });
408
-
409
- // Merge imports from same source
410
- for (const [source, importPaths] of imports) {
411
- if (importPaths.length > 1) {
412
- // Merge specifiers
413
- const allSpecifiers = [];
414
- importPaths.forEach(path => {
415
- allSpecifiers.push(...path.node.specifiers);
416
- });
417
-
418
- // Keep first import, remove others
419
- importPaths[0].node.specifiers = allSpecifiers;
420
- for (let i = 1; i < importPaths.length; i++) {
421
- j(importPaths[i]).remove();
422
- }
423
-
424
- improved = true;
425
- changes.push(`Merged imports from ${source}`);
426
- }
427
- }
428
-
429
- // Sort imports
430
- const importNodes = [];
431
- ast.find(j.ImportDeclaration)
432
- .forEach(path => {
433
- importNodes.push(path.node);
434
- j(_path).remove();
435
- });
436
-
437
- if (importNodes.length > 0) {
438
- // Sort by: external packages, internal absolute, internal relative
439
- importNodes.sort((a, b) => {
440
- const aSource = a.source.value;
441
- const bSource = b.source.value;
442
-
443
- const aExternal = !aSource.startsWith('.') && !aSource.startsWith('/');
444
- const bExternal = !bSource.startsWith('.') && !bSource.startsWith('/');
445
-
446
- if (aExternal && !bExternal) return -1;
447
- if (!aExternal && bExternal) return 1;
448
-
449
- return aSource.localeCompare(bSource);
450
- });
451
-
452
- // Re-insert sorted imports at the beginning
453
- const program = ast.find(j.Program);
454
- importNodes.reverse().forEach(node => {
455
- program.get('body').unshift(node);
456
- });
457
-
458
- improved = true;
459
- changes.push('Sorted imports');
460
- }
461
-
462
- const result = ast.toSource();
463
-
464
- return {
465
- improved,
466
- content: improved ? result : content,
467
- changes,
468
- improvements: changes.map(change => ({
469
- type: 'optimize_imports',
470
- description: change,
471
- line: 0
472
- }))
473
- };
474
-
475
- } catch (_error) {
476
- return { improved: false, content, error: error.message };
477
- }
478
- }
479
-
480
- async removeUnusedCode(content, _filePath, options) {
481
- const j = jscodeshift;
482
- let improved = false;
483
- const changes = [];
484
- const improvements = [];
485
-
486
- try {
487
- const ast = j(content);
488
-
489
- // Find all variable declarations and their usage
490
- const declaredVars = new Map();
491
- const usedVars = new Set();
492
-
493
- // Collect declarations
494
- ast.find(j.VariableDeclarator)
495
- .forEach(path => {
496
- if (path.node.id.type === 'Identifier') {
497
- declaredVars.set(path.node.id.name, path);
498
- }
499
- });
500
-
501
- // Collect usage
502
- ast.find(j.Identifier)
503
- .filter(path => {
504
- // Only count as used if it's not the declaration itself
505
- const parent = path.parent.node;
506
- return !(parent.type === 'VariableDeclarator' && parent.id === path.node);
507
- })
508
- .forEach(path => {
509
- usedVars.add(path.node.name);
510
- });
511
-
512
- // Remove unused variables
513
- for (const [varName, declaratorPath] of declaredVars) {
514
- if (!usedVars.has(varName) && !this.isExported(declaratorPath)) {
515
- const declaration = declaratorPath.parent;
516
-
517
- if (declaration.node.declarations.length === 1) {
518
- // Remove entire declaration
519
- j(declaration).remove();
520
- } else {
521
- // Remove just this declarator
522
- j(declaratorPath).remove();
523
- }
524
-
525
- improved = true;
526
- changes.push(`Removed unused variable: ${varName}`);
527
- improvements.push({
528
- type: 'remove_unused',
529
- description: `Removed unused variable: ${varName}`,
530
- line: declaratorPath.node.loc?.start.line || 0
531
- });
532
- }
533
- }
534
-
535
- // Find unused functions
536
- const declaredFunctions = new Map();
537
- const calledFunctions = new Set();
538
-
539
- ast.find(j.FunctionDeclaration)
540
- .forEach(path => {
541
- if (path.node.id) {
542
- declaredFunctions.set(path.node.id.name, path);
543
- }
544
- });
545
-
546
- ast.find(j.CallExpression)
547
- .forEach(path => {
548
- if (path.node.callee.type === 'Identifier') {
549
- calledFunctions.add(path.node.callee.name);
550
- }
551
- });
552
-
553
- // Remove unused functions
554
- for (const [funcName, funcPath] of declaredFunctions) {
555
- if (!calledFunctions.has(funcName) && !this.isExported(funcPath)) {
556
- j(funcPath).remove();
557
- improved = true;
558
- changes.push(`Removed unused function: ${funcName}`);
559
- improvements.push({
560
- type: 'remove_unused',
561
- description: `Removed unused function: ${funcName}`,
562
- line: funcPath.node.loc?.start.line || 0
563
- });
564
- }
565
- }
566
-
567
- const result = ast.toSource();
568
-
569
- return {
570
- improved,
571
- content: improved ? result : content,
572
- changes,
573
- improvements
574
- };
575
-
576
- } catch (_error) {
577
- return { improved: false, content, error: error.message };
578
- }
579
- }
580
-
581
- async improveNaming(content, _filePath, options) {
582
- const j = jscodeshift;
583
- let improved = false;
584
- const changes = [];
585
- const improvements = [];
586
-
587
- try {
588
- const ast = j(content);
589
-
590
- // Convert snake_case to camelCase for variables and functions
591
- ast.find(j.Identifier)
592
- .filter(path => {
593
- const name = path.node.name;
594
- return name.includes('_') &&
595
- (path.parent.node.type === 'VariableDeclarator' ||
596
- path.parent.node.type === 'FunctionDeclaration');
597
- })
598
- .forEach(path => {
599
- const oldName = path.node.name;
600
- const newName = this.snakeToCamel(oldName);
601
-
602
- // Rename all occurrences
603
- ast.find(j.Identifier, { name: oldName })
604
- .forEach(p => {
605
- p.node.name = newName;
606
- });
607
-
608
- improved = true;
609
- changes.push(`Renamed ${oldName} to ${newName}`);
610
- improvements.push({
611
- type: 'naming_conventions',
612
- description: `Renamed ${oldName} to ${newName}`,
613
- line: path.node.loc?.start.line || 0
614
- });
615
- });
616
-
617
- // Ensure classes start with uppercase
618
- ast.find(j.ClassDeclaration)
619
- .filter(path => {
620
- const name = path.node.id?.name;
621
- return name && name[0] !== name[0].toUpperCase();
622
- })
623
- .forEach(path => {
624
- const oldName = path.node.id.name;
625
- const newName = oldName[0].toUpperCase() + oldName.slice(1);
626
-
627
- // Rename all occurrences
628
- ast.find(j.Identifier, { name: oldName })
629
- .forEach(p => {
630
- p.node.name = newName;
631
- });
632
-
633
- improved = true;
634
- changes.push(`Renamed class ${oldName} to ${newName}`);
635
- improvements.push({
636
- type: 'naming_conventions',
637
- description: `Renamed class ${oldName} to ${newName}`,
638
- line: path.node.loc?.start.line || 0
639
- });
640
- });
641
-
642
- // Ensure constants are UPPER_SNAKE_CASE
643
- ast.find(j.VariableDeclaration, { kind: 'const' })
644
- .forEach(path => {
645
- path.node.declarations.forEach(declarator => {
646
- if (declarator.id.type === 'Identifier') {
647
- const name = declarator.id.name;
648
- // Check if it looks like a constant (all caps or should be)
649
- if (this.shouldBeConstantCase(declarator) && !this.isConstantCase(name)) {
650
- const oldName = name;
651
- const newName = this.toConstantCase(name);
652
-
653
- // Rename all occurrences
654
- ast.find(j.Identifier, { name: oldName })
655
- .forEach(p => {
656
- p.node.name = newName;
657
- });
658
-
659
- improved = true;
660
- changes.push(`Renamed constant ${oldName} to ${newName}`);
661
- improvements.push({
662
- type: 'naming_conventions',
663
- description: `Renamed constant ${oldName} to ${newName}`,
664
- line: declarator.loc?.start.line || 0
665
- });
666
- }
667
- }
668
- });
669
- });
670
-
671
- const result = ast.toSource();
672
-
673
- return {
674
- improved,
675
- content: improved ? result : content,
676
- changes,
677
- improvements
678
- };
679
-
680
- } catch (_error) {
681
- return { improved: false, content, error: error.message };
682
- }
683
- }
684
-
685
- async improveErrorHandling(content, _filePath, options) {
686
- const j = jscodeshift;
687
- let improved = false;
688
- const changes = [];
689
- const improvements = [];
690
-
691
- try {
692
- const ast = j(content);
693
-
694
- // Add try-catch to async functions without error handling
695
- ast.find(j.FunctionDeclaration)
696
- .filter(path => path.node.async)
697
- .forEach(path => {
698
- const hasErrorHandling = j(_path).find(j.TryStatement).length > 0;
699
-
700
- if (!hasErrorHandling && path.node.body.body.length > 0) {
701
- // Wrap body in try-catch
702
- const originalBody = path.node.body.body;
703
- const tryStatement = j.tryStatement(
704
- j.blockStatement(originalBody),
705
- j.catchClause(
706
- j.identifier('error'),
707
- j.blockStatement([
708
- j.expressionStatement(
709
- j.callExpression(
710
- j.memberExpression(
711
- j.identifier('console'),
712
- j.identifier('error')
713
- ),
714
- [j.identifier('error')]
715
- )
716
- ),
717
- j.throwStatement(j.identifier('error'))
718
- ])
719
- )
720
- );
721
-
722
- path.node.body.body = [tryStatement];
723
- improved = true;
724
-
725
- const funcName = path.node.id?.name || 'anonymous';
726
- changes.push(`Added error handling to ${funcName}`);
727
- improvements.push({
728
- type: 'error_handling',
729
- description: `Added try-catch to async function ${funcName}`,
730
- line: path.node.loc?.start.line || 0
731
- });
732
- }
733
- });
734
-
735
- // Improve catch blocks that swallow errors
736
- ast.find(j.CatchClause)
737
- .filter(path => {
738
- // Check if catch block is empty or only logs
739
- const body = path.node.body.body;
740
- return body.length === 0 ||
741
- (body.length === 1 && this.isOnlyConsoleLog(body[0]));
742
- })
743
- .forEach(path => {
744
- // Add proper error handling
745
- const errorParam = path.node.param || j.identifier('error');
746
-
747
- path.node.body.body = [
748
- j.expressionStatement(
749
- j.callExpression(
750
- j.memberExpression(
751
- j.identifier('console'),
752
- j.identifier('error')
753
- ),
754
- [j.literal('Error caught:'), errorParam]
755
- )
756
- ),
757
- j.throwStatement(errorParam)
758
- ];
759
-
760
- improved = true;
761
- changes.push('Improved catch block to properly handle errors');
762
- improvements.push({
763
- type: 'error_handling',
764
- description: 'Added proper error re-throwing in catch block',
765
- line: path.node.loc?.start.line || 0
766
- });
767
- });
768
-
769
- const result = ast.toSource();
770
-
771
- return {
772
- improved,
773
- content: improved ? result : content,
774
- changes,
775
- improvements
776
- };
777
-
778
- } catch (_error) {
779
- return { improved: false, content, error: error.message };
780
- }
781
- }
782
-
783
- async convertToAsyncAwait(content, _filePath, options) {
784
- const j = jscodeshift;
785
- let improved = false;
786
- const changes = [];
787
- const improvements = [];
788
-
789
- try {
790
- const ast = j(content);
791
-
792
- // Convert .then().catch() chains to async/await
793
- ast.find(j.CallExpression)
794
- .filter(path => {
795
- return path.node.callee.type === 'MemberExpression' &&
796
- path.node.callee.property.name === 'then';
797
- })
798
- .forEach(path => {
799
- // Find the containing function
800
- const containingFunction = j(_path).closest(j.Function);
801
-
802
- if (containingFunction.length > 0) {
803
- const func = containingFunction.get();
804
-
805
- // Make function async if not already
806
- if (!func.node.async) {
807
- func.node.async = true;
808
- }
809
-
810
- // Convert promise chain to await
811
- // This is simplified - real implementation would be more complex
812
- improved = true;
813
- changes.push('Converted promise chain to async/await');
814
- improvements.push({
815
- type: 'async_await',
816
- description: 'Converted .then() chain to async/await',
817
- line: path.node.loc?.start.line || 0
818
- });
819
- }
820
- });
821
-
822
- // Convert Promise callbacks to async functions
823
- ast.find(j.NewExpression)
824
- .filter(path => {
825
- return path.node.callee.name === 'Promise' &&
826
- path.node.arguments.length > 0 &&
827
- path.node.arguments[0].type === 'FunctionExpression';
828
- })
829
- .forEach(path => {
830
- const promiseCallback = path.node.arguments[0];
831
-
832
- // Convert to async function
833
- const asyncFunction = j.functionExpression(
834
- promiseCallback.id,
835
- promiseCallback.params,
836
- promiseCallback.body,
837
- promiseCallback.generator,
838
- true // async
839
- );
840
-
841
- path.node.arguments[0] = asyncFunction;
842
- improved = true;
843
- changes.push('Converted Promise constructor to async function');
844
- improvements.push({
845
- type: 'async_await',
846
- description: 'Made Promise callback async',
847
- line: path.node.loc?.start.line || 0
848
- });
849
- });
850
-
851
- const result = ast.toSource();
852
-
853
- return {
854
- improved,
855
- content: improved ? result : content,
856
- changes,
857
- improvements
858
- };
859
-
860
- } catch (_error) {
861
- return { improved: false, content, error: error.message };
862
- }
863
- }
864
-
865
- async improveTypeSafety(content, _filePath, options) {
866
- const j = jscodeshift;
867
- let improved = false;
868
- const changes = [];
869
- const improvements = [];
870
-
871
- try {
872
- const ast = j(content);
873
-
874
- // Add parameter validation to functions
875
- ast.find(j.FunctionDeclaration)
876
- .forEach(path => {
877
- const params = path.node.params;
878
- if (params.length > 0) {
879
- const validationStatements = [];
880
-
881
- params.forEach(param => {
882
- if (param.type === 'Identifier') {
883
- // Add basic validation
884
- validationStatements.push(
885
- j.ifStatement(
886
- j.binaryExpression(
887
- '==',
888
- param,
889
- j.identifier('undefined')
890
- ),
891
- j.throwStatement(
892
- j.newExpression(
893
- j.identifier('Error'),
894
- [j.literal(`Parameter '${param.name}' is required`)]
895
- )
896
- )
897
- )
898
- );
899
- }
900
- });
901
-
902
- if (validationStatements.length > 0) {
903
- // Insert at beginning of function body
904
- path.node.body.body.unshift(...validationStatements);
905
- improved = true;
906
-
907
- const funcName = path.node.id?.name || 'anonymous';
908
- changes.push(`Added parameter validation to ${funcName}`);
909
- improvements.push({
910
- type: 'type_safety',
911
- description: `Added parameter validation to function ${funcName}`,
912
- line: path.node.loc?.start.line || 0
913
- });
914
- }
915
- }
916
- });
917
-
918
- // Add null checks before property access
919
- ast.find(j.MemberExpression)
920
- .filter(path => {
921
- // Check if it's a chain that could throw
922
- return path.node.object.type === 'MemberExpression' ||
923
- (path.node.object.type === 'Identifier' &&
924
- !this.isKnownSafeObject(path.node.object.name));
925
- })
926
- .forEach(path => {
927
- // Convert to optional chaining if not already
928
- if (!path.node.optional) {
929
- path.node.optional = true;
930
- improved = true;
931
- improvements.push({
932
- type: 'type_safety',
933
- description: 'Added optional chaining for safer property access',
934
- line: path.node.loc?.start.line || 0
935
- });
936
- }
937
- });
938
-
939
- if (improvements.length > 0) {
940
- changes.push('Added type safety improvements');
941
- }
942
-
943
- const result = ast.toSource();
944
-
945
- return {
946
- improved,
947
- content: improved ? result : content,
948
- changes,
949
- improvements
950
- };
951
-
952
- } catch (_error) {
953
- return { improved: false, content, error: error.message };
954
- }
955
- }
956
-
957
- async generateDocumentation(content, _filePath, options) {
958
- const j = jscodeshift;
959
- let improved = false;
960
- const changes = [];
961
- const improvements = [];
962
-
963
- try {
964
- const ast = j(content);
965
-
966
- // Add JSDoc to functions without documentation
967
- ast.find(j.FunctionDeclaration)
968
- .filter(path => {
969
- // Check if function already has JSDoc
970
- const comments = path.node.leadingComments || [];
971
- return !comments.some(c => c.type === 'CommentBlock' && c.value.includes('*'));
972
- })
973
- .forEach(path => {
974
- const funcName = path.node.id?.name || 'anonymous';
975
- const params = path.node.params;
976
- const isAsync = path.node.async;
977
-
978
- // Generate JSDoc
979
- let jsdoc = '/**\n';
980
- jsdoc += ` * ${this.generateFunctionDescription(funcName)}\n`;
981
-
982
- params.forEach(param => {
983
- const paramName = param.type === 'Identifier' ? param.name : 'param';
984
- jsdoc += ` * @param {*} ${paramName} - ${this.generateParamDescription(paramName)}\n`;
985
- });
986
-
987
- jsdoc += ` * @returns {${isAsync ? 'Promise<*>' : '*'}} ${this.generateReturnDescription(funcName)}\n`;
988
- jsdoc += ' */';
989
-
990
- // Add JSDoc comment
991
- path.node.leadingComments = [
992
- j.commentBlock(jsdoc.replace('/**', '*').replace('*/', ''), true)
993
- ];
994
-
995
- improved = true;
996
- changes.push(`Added JSDoc to ${funcName}`);
997
- improvements.push({
998
- type: 'documentation',
999
- description: `Generated JSDoc for function ${funcName}`,
1000
- line: path.node.loc?.start.line || 0
1001
- });
1002
- });
1003
-
1004
- // Add JSDoc to classes
1005
- ast.find(j.ClassDeclaration)
1006
- .filter(path => {
1007
- const comments = path.node.leadingComments || [];
1008
- return !comments.some(c => c.type === 'CommentBlock' && c.value.includes('*'));
1009
- })
1010
- .forEach(path => {
1011
- const className = path.node.id?.name || 'Class';
1012
-
1013
- let jsdoc = '/**\n';
1014
- jsdoc += ` * ${this.generateClassDescription(className)}\n`;
1015
- jsdoc += ' */';
1016
-
1017
- path.node.leadingComments = [
1018
- j.commentBlock(jsdoc.replace('/**', '*').replace('*/', ''), true)
1019
- ];
1020
-
1021
- improved = true;
1022
- changes.push(`Added JSDoc to class ${className}`);
1023
- improvements.push({
1024
- type: 'documentation',
1025
- description: `Generated JSDoc for class ${className}`,
1026
- line: path.node.loc?.start.line || 0
1027
- });
1028
- });
1029
-
1030
- const result = ast.toSource();
1031
-
1032
- return {
1033
- improved,
1034
- content: improved ? result : content,
1035
- changes,
1036
- improvements
1037
- };
1038
-
1039
- } catch (_error) {
1040
- return { improved: false, content, error: error.message };
1041
- }
1042
- }
1043
-
1044
- // Helper methods
1045
-
1046
- async loadESLintConfig() {
1047
- try {
1048
- const configPath = path.join(this.rootPath, '.eslintrc.json');
1049
- const content = await fs.readFile(configPath, 'utf-8');
1050
- return JSON.parse(content);
1051
- } catch (_error) {
1052
- // Return default config
1053
- return {
1054
- env: {
1055
- es2021: true,
1056
- node: true
1057
- },
1058
- extends: ['eslint:recommended'],
1059
- parserOptions: {
1060
- ecmaVersion: 12,
1061
- sourceType: 'module'
1062
- },
1063
- rules: {
1064
- 'no-unused-vars': 'error',
1065
- 'no-console': 'warn',
1066
- 'semi': ['error', 'always'],
1067
- 'quotes': ['error', 'single']
1068
- }
1069
- };
1070
- }
1071
- }
1072
-
1073
- async loadPrettierConfig() {
1074
- try {
1075
- const configPath = path.join(this.rootPath, '.prettierrc');
1076
- const content = await fs.readFile(configPath, 'utf-8');
1077
- return JSON.parse(content);
1078
- } catch (_error) {
1079
- // Return default config
1080
- return {
1081
- semi: true,
1082
- singleQuote: true,
1083
- tabWidth: 2,
1084
- trailingComma: 'es5',
1085
- printWidth: 80
1086
- };
1087
- }
1088
- }
1089
-
1090
- calculateCyclomaticComplexity(content) {
1091
- // Simplified complexity calculation
1092
- let complexity = 1;
1093
-
1094
- const complexityPatterns = [
1095
- /\bif\s*\(/g,
1096
- /\belse\s+if\s*\(/g,
1097
- /\bwhile\s*\(/g,
1098
- /\bfor\s*\(/g,
1099
- /\bcase\s+/g,
1100
- /\bcatch\s*\(/g,
1101
- /\?\s*[^:]+\s*:/g, // ternary
1102
- /\|\|/g,
1103
- /&&/g
1104
- ];
1105
-
1106
- complexityPatterns.forEach(pattern => {
1107
- const matches = content.match(pattern);
1108
- if (matches) {
1109
- complexity += matches.length;
1110
- }
1111
- });
1112
-
1113
- return complexity;
1114
- }
1115
-
1116
- calculateMaintainabilityIndex(content) {
1117
- // Simplified maintainability index (0-100)
1118
- const lines = content.split('\n').length;
1119
- const complexity = this.calculateCyclomaticComplexity(content);
1120
- const comments = (content.match(/\/\//g) || []).length +
1121
- (content.match(/\/\*/g) || []).length;
1122
-
1123
- // Simple formula
1124
- const commentRatio = comments / lines;
1125
- const complexityRatio = complexity / lines;
1126
-
1127
- const maintainability = Math.min(100, Math.max(0,
1128
- 100 - (complexityRatio * 50) + (commentRatio * 20)
1129
- ));
1130
-
1131
- return Math.round(maintainability);
1132
- }
1133
-
1134
- calculateDocumentationCoverage(content) {
1135
- // Calculate percentage of documented functions/classes
1136
- const functionMatches = content.match(/function\s+\w+|class\s+\w+/g) || [];
1137
- const jsdocMatches = content.match(/\/\*\*[\s\S]*?\*\//g) || [];
1138
-
1139
- if (functionMatches.length === 0) return 100;
1140
-
1141
- const coverage = (jsdocMatches.length / functionMatches.length) * 100;
1142
- return Math.min(100, Math.round(coverage));
1143
- }
1144
-
1145
- calculateImprovementScore(before, after) {
1146
- const improvements = {
1147
- issues: Math.max(0, before.issues - after.issues),
1148
- complexity: Math.max(0, before.complexity - after.complexity),
1149
- maintainability: Math.max(0, after.maintainability - before.maintainability),
1150
- coverage: Math.max(0, after.coverage - before.coverage)
1151
- };
1152
-
1153
- // Calculate weighted score
1154
- const score = (
1155
- improvements.issues * 3 +
1156
- improvements.complexity * 2 +
1157
- improvements.maintainability +
1158
- improvements.coverage * 0.5
1159
- ) / 6.5;
1160
-
1161
- return Math.round(score * 10) / 10;
1162
- }
1163
-
1164
- summarizeLintFixes(lintResult) {
1165
- const fixedRules = new Map();
1166
-
1167
- lintResult.messages.forEach(message => {
1168
- if (message.fix) {
1169
- const count = fixedRules.get(message.ruleId) || 0;
1170
- fixedRules.set(message.ruleId, count + 1);
1171
- }
1172
- });
1173
-
1174
- return Array.from(fixedRules.entries()).map(([rule, count]) =>
1175
- `Fixed ${count} ${rule} issue${count > 1 ? 's' : ''}`
1176
- );
1177
- }
1178
-
1179
- isVariableReassigned(j, variableDeclarator) {
1180
- const varName = variableDeclarator.node.id.name;
1181
- const scope = variableDeclarator.scope;
1182
-
1183
- let reassigned = false;
1184
-
1185
- j(scope.path).find(j.AssignmentExpression)
1186
- .filter(path => {
1187
- return path.node.left.type === 'Identifier' &&
1188
- path.node.left.name === varName;
1189
- })
1190
- .forEach(() => {
1191
- reassigned = true;
1192
- });
1193
-
1194
- return reassigned;
1195
- }
1196
-
1197
- isExported(_path) {
1198
- // Check if the declaration is exported
1199
- const parent = path.parent;
1200
-
1201
- return parent.node.type === 'ExportNamedDeclaration' ||
1202
- parent.node.type === 'ExportDefaultDeclaration' ||
1203
- (parent.node.type === 'AssignmentExpression' &&
1204
- parent.node.left.type === 'MemberExpression' &&
1205
- parent.node.left.object.name === 'module' &&
1206
- parent.node.left.property.name === 'exports');
1207
- }
1208
-
1209
- isOnlyConsoleLog(statement) {
1210
- return statement.type === 'ExpressionStatement' &&
1211
- statement.expression.type === 'CallExpression' &&
1212
- statement.expression.callee.type === 'MemberExpression' &&
1213
- statement.expression.callee.object.name === 'console';
1214
- }
1215
-
1216
- isKnownSafeObject(name) {
1217
- const safeObjects = ['console', 'Math', 'JSON', 'Object', 'Array', 'String', 'Number'];
1218
- return safeObjects.includes(name);
1219
- }
1220
-
1221
- snakeToCamel(str) {
1222
- return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
1223
- }
1224
-
1225
- shouldBeConstantCase(declarator) {
1226
- // Check if the value is a literal or simple value
1227
- const init = declarator.init;
1228
- if (!init) return false;
1229
-
1230
- return init.type === 'Literal' ||
1231
- init.type === 'UnaryExpression' ||
1232
- (init.type === 'Identifier' && init.name === init.name.toUpperCase());
1233
- }
1234
-
1235
- isConstantCase(name) {
1236
- return /^[A-Z_]+$/.test(name);
1237
- }
1238
-
1239
- toConstantCase(name) {
1240
- // Convert camelCase or snake_case to CONSTANT_CASE
1241
- return name
1242
- .replace(/([a-z])([A-Z])/g, '$1_$2')
1243
- .replace(/[_-]+/g, '_')
1244
- .toUpperCase();
1245
- }
1246
-
1247
- generateFunctionDescription(funcName) {
1248
- // Generate meaningful description based on function name
1249
- const words = funcName.split(/(?=[A-Z])/);
1250
- return words.map(w => w.toLowerCase()).join(' ').replace(/^\w/, c => c.toUpperCase());
1251
- }
1252
-
1253
- generateParamDescription(paramName) {
1254
- // Generate parameter description
1255
- return `The ${paramName} parameter`;
1256
- }
1257
-
1258
- generateReturnDescription(funcName) {
1259
- // Generate return description
1260
- if (funcName.startsWith('get')) return 'The requested value';
1261
- if (funcName.startsWith('is')) return 'True if condition is met, false otherwise';
1262
- if (funcName.startsWith('has')) return 'True if exists, false otherwise';
1263
- return 'The result of the operation';
1264
- }
1265
-
1266
- generateClassDescription(className) {
1267
- // Generate class description
1268
- const words = className.split(/(?=[A-Z])/);
1269
- return `${words.join(' ')} class`;
1270
- }
1271
-
1272
- /**
1273
- * Apply improvements to file
1274
- */
1275
- async applyImprovements(_filePath, improvedContent, backup = true) {
1276
- try {
1277
- if (backup) {
1278
- // Create backup
1279
- const backupPath = `${_filePath}.backup.${Date.now()}`;
1280
- const originalContent = await fs.readFile(_filePath, 'utf-8');
1281
- await fs.writeFile(backupPath, originalContent);
1282
- console.log(chalk.gray(`Backup created: ${backupPath}`));
1283
- }
1284
-
1285
- // Write improved content
1286
- await fs.writeFile(_filePath, improvedContent);
1287
- console.log(chalk.green(`✅ Improvements applied to: ${_filePath}`));
1288
-
1289
- return { success: true };
1290
- } catch (_error) {
1291
- console.error(chalk.red(`Failed to apply improvements: ${error.message}`));
1292
- return { success: false, error: error.message };
1293
- }
1294
- }
1295
-
1296
- /**
1297
- * Get improvement statistics
1298
- */
1299
- getStatistics() {
1300
- const stats = {
1301
- filesAnalyzed: this.metrics.size,
1302
- totalImprovements: 0,
1303
- byType: {},
1304
- averageScore: 0
1305
- };
1306
-
1307
- let totalScore = 0;
1308
-
1309
- for (const [file, metrics] of this.metrics) {
1310
- if (metrics.after) {
1311
- const score = this.calculateImprovementScore(metrics.before, metrics.after);
1312
- totalScore += score;
1313
- }
1314
- }
1315
-
1316
- stats.averageScore = this.metrics.size > 0 ?
1317
- (totalScore / this.metrics.size).toFixed(2) : 0;
1318
-
1319
- // Count improvements by type
1320
- for (const improvement of this.improvements) {
1321
- stats.byType[improvement.type] = (stats.byType[improvement.type] || 0) + 1;
1322
- stats.totalImprovements++;
1323
- }
1324
-
1325
- return stats;
1326
- }
1327
- }
1328
-
1329
- module.exports = CodeQualityImprover;