@mocoto/mahoraga 0.14.1 → 0.14.3

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 (306) hide show
  1. package/README.md +0 -34
  2. package/dist/analysts/architects/analyst-structure.js +20 -20
  3. package/dist/analysts/architects/archetypes-custom.js +16 -19
  4. package/dist/analysts/architects/detector-archetypes.js +43 -36
  5. package/dist/analysts/architects/orchestrator-archetypes.js +3 -3
  6. package/dist/analysts/architects/signals-project-advanced.js +26 -28
  7. package/dist/analysts/architects/signals-project.js +2 -2
  8. package/dist/analysts/architects/strategist-structure.js +47 -66
  9. package/dist/analysts/azure-pipelines/analysts/analyst-azure.js +41 -35
  10. package/dist/analysts/azure-pipelines/corrections/correction-azure.js +22 -19
  11. package/dist/analysts/azure-pipelines/detectors/detector-azure-performance.js +21 -18
  12. package/dist/analysts/azure-pipelines/detectors/detector-azure-security.js +25 -20
  13. package/dist/analysts/azure-pipelines/detectors/detector-azure-structure.js +39 -40
  14. package/dist/analysts/azure-pipelines/scorers/scorer-azure.js +10 -7
  15. package/dist/analysts/circleci/analysts/analyst-circleci.js +33 -27
  16. package/dist/analysts/circleci/corrections/correction-circleci.js +22 -20
  17. package/dist/analysts/circleci/detectors/detector-circleci-performance.js +23 -19
  18. package/dist/analysts/circleci/detectors/detector-circleci-security.js +78 -82
  19. package/dist/analysts/circleci/detectors/detector-circleci-structure.js +22 -22
  20. package/dist/analysts/converters/convert-registry.js +1 -1
  21. package/dist/analysts/converters/engines/converter-gha-to-gitlab.js +17 -15
  22. package/dist/analysts/converters/index.js +1 -1
  23. package/dist/analysts/corrections/analyst-quick-fixes.js +25 -28
  24. package/dist/analysts/corrections/analyst-scoring.js +24 -21
  25. package/dist/analysts/corrections/auto-fix-engine.js +1 -1
  26. package/dist/analysts/corrections/corrector-structure.js +43 -42
  27. package/dist/analysts/corrections/fix-alias-imports.js +10 -6
  28. package/dist/analysts/corrections/fix-md-fences.js +23 -23
  29. package/dist/analysts/corrections/map-reversion.js +56 -53
  30. package/dist/analysts/corrections/pruning.js +19 -16
  31. package/dist/analysts/corrections/quick-fixes/fix-any-to-proper-type.js +57 -61
  32. package/dist/analysts/corrections/quick-fixes/fix-unknown-to-specific-type.js +30 -30
  33. package/dist/analysts/corrections/reorganize-barrels.js +13 -13
  34. package/dist/analysts/corrections/rewrite-testes-aliases.js +23 -22
  35. package/dist/analysts/corrections/scoring-shared.js +19 -18
  36. package/dist/analysts/corrections/type-safety/context-analyzer.js +15 -10
  37. package/dist/analysts/corrections/type-safety/type-analyzer.js +3 -3
  38. package/dist/analysts/corrections/type-safety/type-validator.js +4 -3
  39. package/dist/analysts/corrections/type-safety/usage-analyzer.js +39 -42
  40. package/dist/analysts/css/analysts/analyst-css.js +42 -42
  41. package/dist/analysts/css/corrections/correction-css.js +19 -11
  42. package/dist/analysts/css/detectors/detector-css-best-practices.js +129 -118
  43. package/dist/analysts/css/scorers/scorer-css.js +23 -18
  44. package/dist/analysts/css-in-js/analysts/analyst-css-in-js.js +24 -17
  45. package/dist/analysts/css-in-js/corrections/correction-css-in-js.js +31 -16
  46. package/dist/analysts/css-in-js/detectors/detector-css-in-js-best-practices.js +28 -30
  47. package/dist/analysts/css-in-js/scorers/scorer-css-in-js.js +79 -54
  48. package/dist/analysts/css-in-js/shared.js +7 -0
  49. package/dist/analysts/detectors/detector-architecture.js +91 -85
  50. package/dist/analysts/detectors/detector-bugs-ml.js +29 -27
  51. package/dist/analysts/detectors/detector-code-fragile.js +41 -36
  52. package/dist/analysts/detectors/detector-dependencies.js +5 -5
  53. package/dist/analysts/detectors/detector-duplications.js +26 -26
  54. package/dist/analysts/detectors/detector-monorepo.js +51 -45
  55. package/dist/analysts/detectors/detector-performance.js +24 -17
  56. package/dist/analysts/detectors/detector-recommendation-architecture.js +40 -36
  57. package/dist/analysts/detectors/detector-security.js +43 -42
  58. package/dist/analysts/detectors/detector-structure.js +31 -28
  59. package/dist/analysts/github-actions/analysts/analyst-github-actions.js +5 -8
  60. package/dist/analysts/github-actions/detectors/detector-workflow-accessibility.js +1 -9
  61. package/dist/analysts/github-actions/detectors/detector-workflow-structure.js +1 -4
  62. package/dist/analysts/github-actions/detectors/detector-workflow-trigger-unsafe.js +6 -5
  63. package/dist/analysts/gitlab-ci/analysts/analyst-gitlab-ci.js +2 -2
  64. package/dist/analysts/gitlab-ci/detectors/detector-gitlab-ci-structure.js +0 -3
  65. package/dist/analysts/go/analysts/analyst-best-practices.js +2 -2
  66. package/dist/analysts/go/analysts/analyst-concurrency.js +1 -1
  67. package/dist/analysts/go/analysts/analyst-security.js +1 -1
  68. package/dist/analysts/go/detectors/detector-conventions.js +1 -1
  69. package/dist/analysts/html/analysts/analyst-html.js +10 -12
  70. package/dist/analysts/html/detectors/detector-html.js +3 -3
  71. package/dist/analysts/js-ts/analysts/analyst-commands-cli.js +22 -22
  72. package/dist/analysts/js-ts/analysts/analyst-functions-long.js +5 -5
  73. package/dist/analysts/js-ts/analysts/analyst-patterns-usage.js +6 -2
  74. package/dist/analysts/js-ts/detectors/detector-anti-patterns-async.js +84 -9
  75. package/dist/analysts/js-ts/detectors/detector-constructions-syntactic.js +33 -10
  76. package/dist/analysts/js-ts/detectors/detector-context-smart.js +6 -6
  77. package/dist/analysts/js-ts/detectors/detector-leaks-memory.js +1 -1
  78. package/dist/analysts/js-ts/detectors/detector-types-unsafe.js +33 -2
  79. package/dist/analysts/php/analysts/analyst-php.js +3 -3
  80. package/dist/analysts/php/detectors/detector-php-best-practices.js +5 -5
  81. package/dist/analysts/php/detectors/detector-php-security.js +5 -5
  82. package/dist/analysts/php/scorers/scorer-php.js +2 -2
  83. package/dist/analysts/plugins/detector-documentation.js +6 -6
  84. package/dist/analysts/plugins/detector-markdown.js +7 -7
  85. package/dist/analysts/python/analysts/analyst-python.js +2 -5
  86. package/dist/analysts/react/analysts/analyst-react-hooks.js +66 -9
  87. package/dist/analysts/react/analysts/analyst-react.js +46 -2
  88. package/dist/analysts/react/corrections/correction-react.js +41 -1
  89. package/dist/analysts/react/detectors/detector-react-best-practices.js +5 -5
  90. package/dist/analysts/react/scorers/scorer-react.js +36 -1
  91. package/dist/analysts/registry/autodiscovery.js +2 -2
  92. package/dist/analysts/rust/analysts/analyst-best-practices.js +42 -3
  93. package/dist/analysts/rust/analysts/analyst-memory.js +2 -2
  94. package/dist/analysts/rust/analysts/analyst-rust.js +52 -5
  95. package/dist/analysts/rust/analysts/analyst-security.js +29 -1
  96. package/dist/analysts/scorers/scorer.js +5 -5
  97. package/dist/analysts/shell/analysts/analyst-shell.js +81 -5
  98. package/dist/analysts/shell/corrections/correction-shell.js +34 -1
  99. package/dist/analysts/shell/detectors/detector-shell-security.js +88 -0
  100. package/dist/analysts/shell/scorers/scorer-shell.js +58 -1
  101. package/dist/analysts/strategists/operator-structure.js +5 -7
  102. package/dist/analysts/strategists/suggestions-contextuais.js +5 -2
  103. package/dist/analysts/svg/analysts/analyst-svg.js +1 -0
  104. package/dist/analysts/tailwind/analysts/analyst-tailwind.js +79 -55
  105. package/dist/analysts/tailwind/corrections/correction-tailwind.js +108 -9
  106. package/dist/analysts/tailwind/detectors/detector-tailwind-best-practices.js +122 -7
  107. package/dist/analysts/tailwind/scorers/scorer-tailwind.js +62 -11
  108. package/dist/analysts/xml/analysts/analyst-xml.js +2 -2
  109. package/dist/app/index.js +1 -0
  110. package/dist/bin/cli-bootstrap.js +6 -4
  111. package/dist/bin/index.js +6 -4
  112. package/dist/caretakers/scoring.js +1 -0
  113. package/dist/cli/commands/command-analysts.js +4 -3
  114. package/dist/cli/commands/command-azure.js +1 -1
  115. package/dist/cli/commands/command-circleci.js +1 -1
  116. package/dist/cli/commands/command-compliance.js +1 -1
  117. package/dist/cli/commands/command-diagnose.js +10 -13
  118. package/dist/cli/commands/command-fix-types.js +9 -32
  119. package/dist/cli/commands/command-formatters.js +2 -2
  120. package/dist/cli/commands/command-github-actions.js +1 -1
  121. package/dist/cli/commands/command-gitlab-ci.js +1 -1
  122. package/dist/cli/commands/command-guardian.js +1 -1
  123. package/dist/cli/commands/command-imports.js +6 -6
  124. package/dist/cli/commands/command-jenkins.js +1 -1
  125. package/dist/cli/commands/command-licenses.js +1 -1
  126. package/dist/cli/commands/command-marketplace.js +7 -7
  127. package/dist/cli/commands/command-names.js +3 -8
  128. package/dist/cli/commands/command-perf.js +7 -9
  129. package/dist/cli/commands/command-plugins.js +4 -4
  130. package/dist/cli/diagnostic/auto-fix.js +2 -2
  131. package/dist/cli/diagnostic/exporters/json-exporter.js +1 -1
  132. package/dist/cli/diagnostic/exporters/sharded-exporter.js +0 -3
  133. package/dist/cli/diagnostic/exporters/svg-optimization-exporter.js +1 -1
  134. package/dist/cli/diagnostic/filters.js +9 -9
  135. package/dist/cli/diagnostic/handlers/archetype-handler.js +3 -6
  136. package/dist/cli/diagnostic/handlers/auto-fix-handler.js +4 -4
  137. package/dist/cli/diagnostic/handlers/guardian-handler.js +1 -1
  138. package/dist/cli/diagnostic/processing-diagnostic.js +31 -35
  139. package/dist/cli/diagnostic/processing-helpers.js +2 -2
  140. package/dist/cli/handlers/fix-types-exporter.js +1 -4
  141. package/dist/cli/helpers/display-frame.js +5 -5
  142. package/dist/core/config/auto/auto-fix-config.js +0 -6
  143. package/dist/core/config/chalk-safe.js +6 -6
  144. package/dist/core/config/config.js +11 -13
  145. package/dist/core/config/conventions.js +1 -1
  146. package/dist/core/config/security.js +2 -2
  147. package/dist/core/execution/analysis-cache.js +5 -8
  148. package/dist/core/execution/ast-cache.js +1 -3
  149. package/dist/core/execution/executor.js +8 -21
  150. package/dist/core/execution/inquisitor.js +24 -21
  151. package/dist/core/execution/results.js +1 -0
  152. package/dist/core/execution/scanner.js +4 -4
  153. package/dist/core/messages/en/analysts/analyst-github-actions-messages.js +1 -1
  154. package/dist/core/messages/en/analysts/analyst-patterns-usage-messages.js +1 -0
  155. package/dist/core/messages/en/analysts/analyst-shell-messages.js +15 -0
  156. package/dist/core/messages/en/analysts/detector-constructions-syntactic-messages.js +6 -0
  157. package/dist/core/messages/en/analysts/detector-js-ts-messages.js +27 -0
  158. package/dist/core/messages/en/analysts/detector-react-messages.js +8 -0
  159. package/dist/core/messages/en/analysts/detector-shell-messages.js +17 -0
  160. package/dist/core/messages/en/analysts/detector-tailwind-messages.js +3 -3
  161. package/dist/core/messages/en/analysts/report-circleci-messages.js +7 -7
  162. package/dist/core/messages/en/caretakers/caretaker-messages.js +1 -7
  163. package/dist/core/messages/en/core/plugin-messages.js +31 -3
  164. package/dist/core/messages/en/log/log.js +4 -4
  165. package/dist/core/messages/en/ui/filter-config.js +1 -5
  166. package/dist/core/messages/i18n-system.js +3 -3
  167. package/dist/core/messages/index.js +3 -3
  168. package/dist/core/messages/ja/analysts/analyst-github-actions-messages.js +1 -1
  169. package/dist/core/messages/ja/analysts/analyst-patterns-usage-messages.js +1 -0
  170. package/dist/core/messages/ja/analysts/analyst-shell-messages.js +15 -0
  171. package/dist/core/messages/ja/analysts/detector-constructions-syntactic-messages.js +6 -0
  172. package/dist/core/messages/ja/analysts/detector-js-ts-messages.js +27 -0
  173. package/dist/core/messages/ja/analysts/detector-react-messages.js +8 -0
  174. package/dist/core/messages/ja/analysts/detector-shell-messages.js +17 -0
  175. package/dist/core/messages/ja/analysts/detector-tailwind-messages.js +3 -3
  176. package/dist/core/messages/ja/analysts/report-circleci-messages.js +7 -7
  177. package/dist/core/messages/ja/caretakers/caretaker-messages.js +1 -7
  178. package/dist/core/messages/ja/core/plugin-messages.js +31 -3
  179. package/dist/core/messages/ja/log/log.js +4 -4
  180. package/dist/core/messages/ja/ui/filter-config.js +1 -1
  181. package/dist/core/messages/pt/analysts/analyst-github-actions-messages.js +1 -1
  182. package/dist/core/messages/pt/analysts/analyst-patterns-usage-messages.js +1 -0
  183. package/dist/core/messages/pt/analysts/analyst-shell-messages.js +15 -0
  184. package/dist/core/messages/pt/analysts/detector-constructions-syntactic-messages.js +6 -0
  185. package/dist/core/messages/pt/analysts/detector-js-ts-messages.js +27 -0
  186. package/dist/core/messages/pt/analysts/detector-react-messages.js +8 -0
  187. package/dist/core/messages/pt/analysts/detector-shell-messages.js +17 -0
  188. package/dist/core/messages/pt/analysts/detector-tailwind-messages.js +3 -3
  189. package/dist/core/messages/pt/analysts/report-circleci-messages.js +7 -7
  190. package/dist/core/messages/pt/caretakers/caretaker-messages.js +1 -7
  191. package/dist/core/messages/pt/core/plugin-messages.js +31 -3
  192. package/dist/core/messages/pt/log/log-engine.js +6 -6
  193. package/dist/core/messages/pt/log/log.js +3 -3
  194. package/dist/core/messages/pt/ui/filter-config.js +1 -1
  195. package/dist/core/messages/shared/icons.js +3 -3
  196. package/dist/core/messages/zh/analysts/analyst-github-actions-messages.js +1 -1
  197. package/dist/core/messages/zh/analysts/analyst-patterns-usage-messages.js +1 -0
  198. package/dist/core/messages/zh/analysts/analyst-shell-messages.js +15 -0
  199. package/dist/core/messages/zh/analysts/detector-constructions-syntactic-messages.js +6 -0
  200. package/dist/core/messages/zh/analysts/detector-js-ts-messages.js +27 -0
  201. package/dist/core/messages/zh/analysts/detector-react-messages.js +8 -0
  202. package/dist/core/messages/zh/analysts/detector-shell-messages.js +17 -0
  203. package/dist/core/messages/zh/analysts/detector-tailwind-messages.js +3 -3
  204. package/dist/core/messages/zh/analysts/report-circleci-messages.js +7 -7
  205. package/dist/core/messages/zh/caretakers/caretaker-messages.js +1 -7
  206. package/dist/core/messages/zh/core/plugin-messages.js +31 -3
  207. package/dist/core/messages/zh/log/log.js +3 -3
  208. package/dist/core/messages/zh/ui/filter-config.js +1 -5
  209. package/dist/core/parsing/filters.js +3 -3
  210. package/dist/core/parsing/langs/json.js +1 -1
  211. package/dist/core/parsing/langs/python.js +1 -1
  212. package/dist/core/parsing/langs/typescript.js +1 -1
  213. package/dist/core/parsing/parser.js +3 -4
  214. package/dist/core/parsing/utils.js +1 -0
  215. package/dist/core/registry/file-registry.js +3 -2
  216. package/dist/core/registry/paths.js +3 -3
  217. package/dist/core/reporting/default-reporter.js +2 -2
  218. package/dist/core/schema/version.js +6 -6
  219. package/dist/core/workers/worker-executor.js +3 -3
  220. package/dist/core/workers/worker-pool.js +0 -0
  221. package/dist/guardian/baseline.js +1 -1
  222. package/dist/guardian/gpg.js +3 -1
  223. package/dist/guardian/integrity.js +2 -7
  224. package/dist/guardian/records.js +7 -1
  225. package/dist/guardian/result.js +1 -1
  226. package/dist/guardian/sentinel.js +7 -1
  227. package/dist/guardian/watcher-hidden.js +6 -1
  228. package/dist/licenses/fs-utils.js +5 -1
  229. package/dist/licenses/generate-notices.js +1 -1
  230. package/dist/licenses/index.js +1 -0
  231. package/dist/licenses/normalizer.js +10 -9
  232. package/dist/node.loader.js +224 -4
  233. package/dist/reports/analise-async-patterns.js +1 -1
  234. package/dist/reports/filter-smart.js +2 -5
  235. package/dist/reports/generator-report.js +7 -7
  236. package/dist/reports/report-archetypes.js +10 -10
  237. package/dist/reports/report-caretaker-health.js +2 -1
  238. package/dist/reports/report-patterns-usage.js +1 -1
  239. package/dist/sdk/analyzer.js +1 -1
  240. package/dist/shared/data-processing/fragment-report.js +11 -11
  241. package/dist/shared/data-processing/json.js +1 -1
  242. package/dist/shared/data-processing/occurrences.js +3 -2
  243. package/dist/shared/formatters/code-min-formatter.js +1 -1
  244. package/dist/shared/formatters/engines/prettier.js +1 -1
  245. package/dist/shared/formatters/engines/stylelint.js +43 -40
  246. package/dist/shared/formatters/formatter.js +8 -8
  247. package/dist/shared/formatters/formatters/code.js +3 -3
  248. package/dist/shared/formatters/formatters/css.js +2 -10
  249. package/dist/shared/formatters/formatters/dotfiles.js +1 -1
  250. package/dist/shared/formatters/formatters/html.js +1 -5
  251. package/dist/shared/formatters/formatters/json.js +0 -3
  252. package/dist/shared/formatters/formatters/markdown.js +19 -24
  253. package/dist/shared/formatters/formatters/properties.js +2 -2
  254. package/dist/shared/formatters/formatters/shell.js +1 -4
  255. package/dist/shared/formatters/formatters/sql.js +0 -3
  256. package/dist/shared/formatters/formatters/xml.js +5 -7
  257. package/dist/shared/formatters/formatters/yaml.js +2 -7
  258. package/dist/shared/formatters/index.js +1 -1
  259. package/dist/shared/helpers/framework-detector.js +6 -2
  260. package/dist/shared/helpers/json.js +1 -1
  261. package/dist/shared/helpers/magic-constants-whitelist.js +1 -1
  262. package/dist/shared/helpers/masking.js +17 -17
  263. package/dist/shared/helpers/reader-report.js +0 -12
  264. package/dist/shared/helpers/structural-hash.js +3 -2
  265. package/dist/shared/helpers/structure.js +1 -1
  266. package/dist/shared/marketplace/registry.js +1 -1
  267. package/dist/shared/marketplace/remote.js +4 -4
  268. package/dist/shared/persistence/persistence.js +13 -6
  269. package/dist/shared/plugins/core-plugin.js +5 -1
  270. package/dist/shared/plugins/registry.js +3 -2
  271. package/dist/types/analysts/tailwind-correction.js +2 -0
  272. package/dist/types/caretakers/imports-barrel.js +1 -0
  273. package/dist/types/caretakers/index.js +4 -0
  274. package/dist/types/caretakers/map-reversion.js +1 -0
  275. package/dist/types/caretakers/pruning.js +1 -0
  276. package/dist/types/caretakers/scoring.js +1 -0
  277. package/dist/types/common/analysts.js +1 -1
  278. package/dist/types/core/config/filters.js +1 -0
  279. package/dist/types/core/config/index.js +2 -0
  280. package/dist/types/core/execution/ambiente.js +1 -0
  281. package/dist/types/core/execution/linguagens.js +1 -0
  282. package/dist/types/core/execution/parse-errors.js +1 -0
  283. package/dist/types/core/execution/results.js +1 -0
  284. package/dist/types/core/execution/structure-json.js +1 -0
  285. package/dist/types/core/index.js +1 -0
  286. package/dist/types/core/messages/index.js +1 -0
  287. package/dist/types/core/messages/log.js +1 -0
  288. package/dist/types/core/parsing/babel-narrow.js +1 -0
  289. package/dist/types/core/parsing/index.js +1 -0
  290. package/dist/types/core/runtime.js +1 -0
  291. package/dist/types/guardian/index.js +2 -0
  292. package/dist/types/guardian/integrity.js +7 -0
  293. package/dist/types/guardian/snapshot.js +1 -0
  294. package/dist/types/index.js +4 -4
  295. package/dist/types/licenses/index.js +2 -0
  296. package/dist/types/processing/display.js +16 -13
  297. package/dist/types/processing/filters.js +8 -11
  298. package/dist/types/reports/compliance.js +1 -0
  299. package/dist/types/reports/streaming.js +1 -0
  300. package/dist/types/scripts/index.js +1 -0
  301. package/dist/types/scripts/migrar-aliases.js +1 -0
  302. package/dist/types/sdk/index.js +1 -0
  303. package/dist/types/shared/index.js +2 -0
  304. package/dist/types/vulnerabilities/index.js +2 -0
  305. package/dist/vulnerabilities/scanner.js +3 -2
  306. package/package.json +14 -20
@@ -20,7 +20,6 @@ function collectGeneralRustIssues(src, relPath) {
20
20
  const ocorrencias = [];
21
21
  const lineOf = createLineLookup(src).lineAt;
22
22
  const scan = maskRustComments(src);
23
- // Missing module-level comment
24
23
  const firstItem = scan.match(/^\s*(?:pub\s+)?(?:fn|mod|struct|enum|trait|impl)\s+\w+/m);
25
24
  if (firstItem) {
26
25
  const srcBefore = src.slice(0, firstItem.index ?? 0);
@@ -29,7 +28,6 @@ function collectGeneralRustIssues(src, relPath) {
29
28
  ocorrencias.push(warn('Module or crate missing documentation comment (//! or /*! */)', relPath, line, messages.SeverityNiveis.suggestion));
30
29
  }
31
30
  }
32
- // Snake case convention for functions
33
31
  for (const match of scan.matchAll(/^\s*(?:pub\s+)?fn\s+(\w+)\s*\(/gm)) {
34
32
  const fnName = match[1];
35
33
  if (/[A-Z]/.test(fnName)) {
@@ -37,7 +35,6 @@ function collectGeneralRustIssues(src, relPath) {
37
35
  ocorrencias.push(warn(`Function '${fnName}' should follow snake_case convention`, relPath, line, messages.SeverityNiveis.suggestion));
38
36
  }
39
37
  }
40
- // PascalCase for types
41
38
  for (const match of scan.matchAll(/^\s*(?:pub\s+)?(?:struct|enum|trait|type)\s+(\w+)/gm)) {
42
39
  const typeName = match[1];
43
40
  if (/^[a-z_]/.test(typeName)) {
@@ -45,7 +42,6 @@ function collectGeneralRustIssues(src, relPath) {
45
42
  ocorrencias.push(warn(`Type '${typeName}' should follow PascalCase convention`, relPath, line, messages.SeverityNiveis.suggestion));
46
43
  }
47
44
  }
48
- // Deep nesting
49
45
  let maxDepth = 0;
50
46
  const lines = src.split('\n');
51
47
  for (const line of lines) {
@@ -56,12 +52,63 @@ function collectGeneralRustIssues(src, relPath) {
56
52
  if (maxDepth > 8) {
57
53
  ocorrencias.push(warn(`Deep nesting detected (${maxDepth} levels); consider refactoring`, relPath, 1, messages.SeverityNiveis.suggestion));
58
54
  }
55
+ // detect Lazy/OnceCell from once_cell crate -> suggest std::sync::LazyLock (Rust 1.80+)
56
+ for (const match of scan.matchAll(/\b(once_cell::sync::Lazy|once_cell::sync::OnceCell)\b/g)) {
57
+ const line = lineOf(match.index);
58
+ const isLazy = match[1].includes('Lazy');
59
+ ocorrencias.push(warn(isLazy
60
+ ? `'once_cell::sync::Lazy' detected; use std::sync::LazyLock (stable since Rust 1.80)`
61
+ : `'once_cell::sync::OnceCell' detected; use std::sync::OnceLock (stable since Rust 1.70)`, relPath, line, messages.SeverityNiveis.suggestion));
62
+ }
63
+ // detect manual offset calculation -> suggest std::mem::offset_of! (Rust 1.77+)
64
+ for (const match of scan.matchAll(/offset_of!\(/g)) {
65
+ const line = lineOf(match.index);
66
+ ocorrencias.push(warn('offset_of! macro usage is correct for Rust 1.77+', relPath, line, messages.SeverityNiveis.info));
67
+ }
68
+ // detect manual transmute-like offset patterns
69
+ for (const match of scan.matchAll(/(\w+) as \*const u8\)\.offset\((\d+)\)/g)) {
70
+ const line = lineOf(match.index);
71
+ ocorrencias.push(warn('Manual pointer offset for field access; consider std::mem::offset_of! (Rust 1.77+)', relPath, line, messages.SeverityNiveis.suggestion));
72
+ }
73
+ // detect assert!(matches!(...)) -> suggest assert_matches! (Rust 1.81+)
74
+ for (const match of scan.matchAll(/assert!\(matches!\(/g)) {
75
+ const line = lineOf(match.index);
76
+ ocorrencias.push(warn('assert!(matches!(...)) pattern; consider assert_matches!(...) (unstable, nightly only)', relPath, line, messages.SeverityNiveis.info));
77
+ }
78
+ // detect if let ... && let ... (let_chains, stable since Rust 1.78)
79
+ for (const match of scan.matchAll(/if\s+let\s+\w+\s*=\s*\w+\s*&&\s*let\s+/g)) {
80
+ const line = lineOf(match.index);
81
+ ocorrencias.push(warn('let_chains pattern detected (stable since Rust 1.78)', relPath, line, messages.SeverityNiveis.info));
82
+ }
83
+ // detect is_some_and / is_ok_and (stable since Rust 1.70)
84
+ for (const match of scan.matchAll(/\.is_some\(\)\s*&&\s*\w+\s*==/g)) {
85
+ const line = lineOf(match.index);
86
+ ocorrencias.push(warn('.is_some() && predicate pattern; consider .is_some_and(|x| ...) (Rust 1.70+)', relPath, line, messages.SeverityNiveis.suggestion));
87
+ }
88
+ for (const match of scan.matchAll(/\.is_ok\(\)\s*&&\s*\w+\s*==/g)) {
89
+ const line = lineOf(match.index);
90
+ ocorrencias.push(warn('.is_ok() && predicate pattern; consider .is_ok_and(|x| ...) (Rust 1.70+)', relPath, line, messages.SeverityNiveis.suggestion));
91
+ }
92
+ // detect Option::inspect / Result::inspect (stable since Rust 1.76)
93
+ for (const match of scan.matchAll(/\.map\(.*\|x\|.*\{[\s\S]{0,100}println!.*\}\)/g)) {
94
+ const line = lineOf(match.index);
95
+ ocorrencias.push(warn('map() with side-effect closure; consider .inspect() (Rust 1.76+)', relPath, line, messages.SeverityNiveis.suggestion));
96
+ }
97
+ // detect string interpolation for format args (Rust 1.80+)
98
+ for (const match of scan.matchAll(/format!\(["']\{[\w:?]*\}["'],\s*(\w+)\)/g)) {
99
+ const line = lineOf(match.index);
100
+ const varName = match[1];
101
+ if (varName !== match[0].match(/\{(\w+)\}/)?.[1]) {
102
+ // suggest captured identifier format
103
+ ocorrencias.push(warn(`format!("{varName}") could be simplified to format!("{varName}") using captured identifiers (Rust 1.80+)`, relPath, line, messages.SeverityNiveis.info));
104
+ }
105
+ }
59
106
  return ocorrencias;
60
107
  }
61
108
  export const analistaRust = criarAnalista({
62
109
  nome: 'analista-rust',
63
110
  categoria: 'linguagem',
64
- descricao: 'Analisa código Rust em busca de convenções de nomenclatura e organização.',
111
+ descricao: 'Analisa código Rust: convenções, nomenclatura, padrões modernos (edition 2024).',
65
112
  global: false,
66
113
  test: (relPath) => isRustFile(relPath),
67
114
  aplicar: (src, relPath) => {
@@ -51,12 +51,40 @@ function collectSecurityIssues(src, relPath) {
51
51
  const line = lineOf(match.index);
52
52
  ocorrencias.push(warn(`Unsafe ${match[1]} declaration; document safety invariants with // SAFETY:`, relPath, line, messages.SeverityNiveis.error));
53
53
  }
54
+ // pointer::cast instead of `as` pointer cast (Rust 1.72+)
55
+ for (const match of scan.matchAll(/\b(\w+)\s+as\s+\*const\s+\w+/g)) {
56
+ const line = lineOf(match.index);
57
+ if (!match[0].includes('as *const u8')) {
58
+ ocorrencias.push(warn('Using `as` for pointer cast; consider .pointer::cast::<T>() or .cast() (Rust 1.72+)', relPath, line, messages.SeverityNiveis.suggestion));
59
+ }
60
+ }
61
+ // Command::new with shell injection risk
62
+ for (const match of scan.matchAll(/Command::new\(["'](sh|bash|cmd|powershell)["']\)/g)) {
63
+ const line = lineOf(match.index);
64
+ const argsMatch = src.slice(match.index, match.index + 200).match(/\.arg\(/);
65
+ if (argsMatch) {
66
+ ocorrencias.push(warn('Shell invocation via Command; ensure no injection via user input', relPath, line, messages.SeverityNiveis.error));
67
+ }
68
+ }
69
+ // detect .ok()?.unwrap() antipattern
70
+ for (const match of scan.matchAll(/\.ok\(\)\?\.unwrap\(\)/g)) {
71
+ const line = lineOf(match.index);
72
+ ocorrencias.push(warn('.ok()?.unwrap() antipattern; use ? directly on Result instead', relPath, line, messages.SeverityNiveis.warning));
73
+ }
74
+ // detect splitn / split_once with manual index access instead of destructuring (Rust 1.62+ split_once stable)
75
+ for (const match of scan.matchAll(/\.splitn\(2,\s*/g)) {
76
+ const line = lineOf(match.index);
77
+ const afterSplit = src.slice(match.index, match.index + 100);
78
+ if (afterSplit.includes('[0]') || afterSplit.includes('[1]')) {
79
+ ocorrencias.push(warn('splitn(2, ...) with index access; consider .split_once() for cleaner destructuring (Rust 1.62+)', relPath, line, messages.SeverityNiveis.suggestion));
80
+ }
81
+ }
54
82
  return ocorrencias;
55
83
  }
56
84
  export const analistaRustSeguranca = criarAnalista({
57
85
  nome: 'analista-rust-seguranca',
58
86
  categoria: 'seguranca',
59
- descricao: 'Detecta problemas de segurança e unsafe em código Rust.',
87
+ descricao: 'Detecta problemas de segurança e unsafe em Rust (edition 2024).',
60
88
  global: false,
61
89
  test: (relPath) => /\.(rs)$/i.test(relPath),
62
90
  aplicar: (src, relPath) => {
@@ -166,7 +166,7 @@ export function pontuarTodos(arquivos) {
166
166
  const resultado = scoreArquetipo(def, arquivos);
167
167
  resultados.push(resultado);
168
168
  if (resultado.candidatoExtra) {
169
- const extra = ARQUETIPOS.find((arquivo) => arquivo.nome === resultado.candidatoExtra);
169
+ const extra = ARQUETIPOS?.find((arquivo) => arquivo.nome === resultado.candidatoExtra);
170
170
  if (extra) {
171
171
  const extraResultado = scoreArquetipo(extra, arquivos);
172
172
  if (!resultados.some(x => x.nome === extraResultado.nome)) {
@@ -189,9 +189,9 @@ export function scoreArquetipoAvancado(def, arquivos, sinaisAvancados) {
189
189
  // Clona o resultado base para adicionar análises avançadas
190
190
  let score = resultadoBase.score;
191
191
  let explicacao = resultadoBase.explicacaoSimilaridade ?? '';
192
- const frameworks = sinaisAvancados.frameworksDetectados || [];
193
- const deps = sinaisAvancados.dependencias || [];
194
- const scripts = sinaisAvancados.scripts || [];
192
+ const frameworks = sinaisAvancados.frameworksDetectados;
193
+ const deps = sinaisAvancados.dependencias;
194
+ const scripts = sinaisAvancados.scripts;
195
195
  const detalhes = sinaisAvancados.detalhes ?? {};
196
196
  // BONUS INTELIGENTE: Considerar sinais avançados para pontuação contextual
197
197
  score += calcularBonusContextual(def, sinaisAvancados);
@@ -602,7 +602,7 @@ export function pontuarTodosAvancado(arquivos, sinaisAvancados) {
602
602
  const resultado = scoreArquetipoAvancado(def, arquivos, sinaisAvancados);
603
603
  resultados.push(resultado);
604
604
  if (resultado.candidatoExtra) {
605
- const extra = ARQUETIPOS.find((arquivo) => arquivo.nome === resultado.candidatoExtra);
605
+ const extra = ARQUETIPOS?.find((arquivo) => arquivo.nome === resultado.candidatoExtra);
606
606
  if (extra) {
607
607
  const extraResultado = scoreArquetipoAvancado(extra, arquivos, sinaisAvancados);
608
608
  if (!resultados.some(x => x.nome === extraResultado.nome)) {
@@ -24,7 +24,7 @@ export const analistaShell = criarAnalista({
24
24
  sugestao: messages.AnalistaShellMensagens.missingShebangSugestao
25
25
  }));
26
26
  }
27
- // 2. Verificar 'set -e' ou 'set -o pipefail' (Tratamento de Erros)
27
+ // 2. Verificar 'set -euo pipefail' (Tratamento de Erros + strict mode)
28
28
  const srcCompleto = src.toLowerCase();
29
29
  if (!srcCompleto.includes('set -e') && !srcCompleto.includes('set -o pipefail')) {
30
30
  ocorrencias.push(criarOcorrencia({
@@ -36,6 +36,84 @@ export const analistaShell = criarAnalista({
36
36
  sugestao: messages.AnalistaShellMensagens.missingSetESugestao
37
37
  }));
38
38
  }
39
+ // 2b. Verificar 'set -u'
40
+ if (!srcCompleto.includes('set -u')) {
41
+ ocorrencias.push(criarOcorrencia({
42
+ tipo: 'codigo-fragil',
43
+ nivel: 'info',
44
+ mensagem: messages.AnalistaShellMensagens.missingSetU,
45
+ relPath,
46
+ linha: 1,
47
+ sugestao: messages.AnalistaShellMensagens.missingSetUSugestao
48
+ }));
49
+ }
50
+ // 2c. Verificar IFS=$'\n\t'
51
+ if (!src.includes('IFS=')) {
52
+ ocorrencias.push(criarOcorrencia({
53
+ tipo: 'codigo-fragil',
54
+ nivel: 'info',
55
+ mensagem: messages.AnalistaShellMensagens.missingIso,
56
+ relPath,
57
+ linha: 1,
58
+ sugestao: messages.AnalistaShellMensagens.missingIsoSugestao
59
+ }));
60
+ }
61
+ // 2d. Verificar trap handler
62
+ if (!src.includes('trap ')) {
63
+ ocorrencias.push(criarOcorrencia({
64
+ tipo: 'boa-pratica-ausente',
65
+ nivel: 'info',
66
+ mensagem: messages.AnalistaShellMensagens.missingTrap,
67
+ relPath,
68
+ linha: 1,
69
+ sugestao: messages.AnalistaShellMensagens.missingTrapSugestao
70
+ }));
71
+ }
72
+ // 2e. Verificar main function pattern
73
+ if (!src.includes('main()') && !src.includes('main ()')) {
74
+ ocorrencias.push(criarOcorrencia({
75
+ tipo: 'boa-pratica-ausente',
76
+ nivel: 'info',
77
+ mensagem: messages.AnalistaShellMensagens.missingMainFn,
78
+ relPath,
79
+ linha: linhas.length,
80
+ sugestao: messages.AnalistaShellMensagens.missingMainFnSugestao
81
+ }));
82
+ }
83
+ // 2f. Verificar command -v usage for hardcoded paths
84
+ if (/(\/usr\/bin\/|\/bin\/|\/usr\/local\/bin\/)/.test(src) && !src.includes('command -v')) {
85
+ ocorrencias.push(criarOcorrencia({
86
+ tipo: 'boa-pratica-ausente',
87
+ nivel: 'info',
88
+ mensagem: messages.AnalistaShellMensagens.missingCommandV,
89
+ relPath,
90
+ linha: 1,
91
+ sugestao: messages.AnalistaShellMensagens.missingCommandVSugestao
92
+ }));
93
+ }
94
+ // 2g. Verificar DEBUG mode
95
+ if (!src.includes('${DEBUG:-}') && !src.includes('$DEBUG')) {
96
+ ocorrencias.push(criarOcorrencia({
97
+ tipo: 'boa-pratica-ausente',
98
+ nivel: 'info',
99
+ mensagem: messages.AnalistaShellMensagens.missingDebugMode,
100
+ relPath,
101
+ linha: 1,
102
+ sugestao: messages.AnalistaShellMensagens.missingDebugModeSugestao
103
+ }));
104
+ }
105
+ // 2h. Verificar input validation
106
+ const hasUsageCheck = /\[\[ -z "\$[0-9*@]/.test(src) || /\[ -z "\$[0-9*@]/.test(src) || src.includes('Usage:') || src.includes('usage:');
107
+ if (!hasUsageCheck && /\$[0-9]/.test(src)) {
108
+ ocorrencias.push(criarOcorrencia({
109
+ tipo: 'boa-pratica-ausente',
110
+ nivel: 'info',
111
+ mensagem: messages.AnalistaShellMensagens.missingInputValidation,
112
+ relPath,
113
+ linha: 1,
114
+ sugestao: messages.AnalistaShellMensagens.missingInputValidationSugestao
115
+ }));
116
+ }
39
117
  linhas.forEach((linha, index) => {
40
118
  const numeroLinha = index + 1;
41
119
  const linhaTrim = linha.trim();
@@ -55,9 +133,7 @@ export const analistaShell = criarAnalista({
55
133
  }));
56
134
  }
57
135
  // 4. Variáveis não aspeadas (Fragilidade)
58
- // Detecta patterns como $VAR sem aspas (ex: echo $USER, mas ignora em loops/condicionais complexas)
59
136
  if (/\$(\w+)\b/.test(linha) && !/["'].*\$\w+.*["']/.test(linha) && !/\$\(.*\)/.test(linha) && !/^\s*(for|while|if|case|read)\s+/.test(linhaTrim)) {
60
- // Heurística simples: se a variável aparece sozinha ou em comando comum
61
137
  if (/\b(echo|ls|cd|rm|cp|mv)\s+.*\$\w+/.test(linhaTrim)) {
62
138
  ocorrencias.push(criarOcorrencia({
63
139
  tipo: 'codigo-fragil',
@@ -73,7 +149,7 @@ export const analistaShell = criarAnalista({
73
149
  if (/\brm\s+-rf\s+\/(\s|$|['"`])/.test(linha)) {
74
150
  ocorrencias.push(criarOcorrencia({
75
151
  tipo: 'vulnerabilidade-seguranca',
76
- nivel: 'critica',
152
+ nivel: 'erro',
77
153
  mensagem: messages.AnalistaShellMensagens.rmRfRoot,
78
154
  relPath,
79
155
  linha: numeroLinha,
@@ -84,7 +160,7 @@ export const analistaShell = criarAnalista({
84
160
  if (/(curl|wget).*(|\s)sh(\s|$)/.test(linha)) {
85
161
  ocorrencias.push(criarOcorrencia({
86
162
  tipo: 'vulnerabilidade-seguranca',
87
- nivel: 'alta',
163
+ nivel: 'erro',
88
164
  mensagem: messages.AnalistaShellMensagens.curlPipeSh,
89
165
  relPath,
90
166
  linha: numeroLinha,
@@ -25,12 +25,45 @@ export function detectarCorrecoesShell(src, _relPath) {
25
25
  if (!/set\s+(-e|-o\s+pipefail)/.test(src)) {
26
26
  correcoes.push({
27
27
  tipo: 'shell-add-set-e',
28
- original: 'Sem set -e',
28
+ original: 'Sem set -euo pipefail',
29
29
  sugerido: 'set -euo pipefail',
30
30
  linha: 2,
31
31
  confianca: 90
32
32
  });
33
33
  }
34
+ // Add set -u if missing
35
+ if (!/set\s+-u/.test(src)) {
36
+ const linhaSetE = src.match(/set\s+(-e\b)/);
37
+ const sugestao = linhaSetE ? 'set -euo pipefail' : 'set -u';
38
+ const linha = linhaSetE ? 2 : 1;
39
+ correcoes.push({
40
+ tipo: 'shell-add-set-u',
41
+ original: 'Sem set -u',
42
+ sugerido: sugestao,
43
+ linha,
44
+ confianca: 85
45
+ });
46
+ }
47
+ // Add IFS if missing
48
+ if (!/IFS=/.test(src)) {
49
+ correcoes.push({
50
+ tipo: 'shell-add-ifs',
51
+ original: 'Sem IFS',
52
+ sugerido: "IFS=$'\\n\\t'",
53
+ linha: 3,
54
+ confianca: 80
55
+ });
56
+ }
57
+ // Add trap if missing
58
+ if (!/\btrap\s+/.test(src) && linhas.length > 5) {
59
+ correcoes.push({
60
+ tipo: 'shell-add-trap',
61
+ original: 'Sem trap handler',
62
+ sugerido: 'trap "cleanup" EXIT INT TERM',
63
+ linha: linhas.length + 1,
64
+ confianca: 75
65
+ });
66
+ }
34
67
  linhas.forEach((linha, index) => {
35
68
  const numeroLinha = index + 1;
36
69
  if (/\b(echo|ls|cd|rm|cp|mv)\s+.*\$\w+/.test(linha) && !/["'].*\$\w+.*["']/.test(linha)) {
@@ -57,6 +57,94 @@ export const detectorShellSecurity = {
57
57
  sugestao: messages.DetectorShellMensagens.unsafePipefailSugestao
58
58
  }));
59
59
  }
60
+ // set -u (treat unset variables as error)
61
+ if (!/set\s+-u/.test(src)) {
62
+ ocorrencias.push(criarOcorrencia({
63
+ tipo: 'shell-missing-set-u',
64
+ nivel: 'info',
65
+ mensagem: messages.DetectorShellMensagens.missingSetU,
66
+ relPath,
67
+ linha: 1,
68
+ sugestao: messages.DetectorShellMensagens.missingSetUSugestao
69
+ }));
70
+ }
71
+ // IFS=$'\n\t'
72
+ if (!/IFS=/.test(src)) {
73
+ ocorrencias.push(criarOcorrencia({
74
+ tipo: 'shell-missing-ifs',
75
+ nivel: 'info',
76
+ mensagem: messages.DetectorShellMensagens.missingIso,
77
+ relPath,
78
+ linha: 1,
79
+ sugestao: messages.DetectorShellMensagens.missingIsoSugestao
80
+ }));
81
+ }
82
+ // Trap handler
83
+ if (!/\btrap\s+/.test(src)) {
84
+ ocorrencias.push(criarOcorrencia({
85
+ tipo: 'shell-missing-trap',
86
+ nivel: 'info',
87
+ mensagem: messages.DetectorShellMensagens.missingTrap,
88
+ relPath,
89
+ linha: 1,
90
+ sugestao: messages.DetectorShellMensagens.missingTrapSugestao
91
+ }));
92
+ }
93
+ // Main function pattern
94
+ if (!/main\s*\(\s*\)/.test(src) && !/^main\s*\(/m.test(src)) {
95
+ ocorrencias.push(criarOcorrencia({
96
+ tipo: 'shell-missing-main-fn',
97
+ nivel: 'info',
98
+ mensagem: messages.DetectorShellMensagens.missingMainFn,
99
+ relPath,
100
+ linha: linhas.length,
101
+ sugestao: messages.DetectorShellMensagens.missingMainFnSugestao
102
+ }));
103
+ }
104
+ // Hardcoded paths without command -v
105
+ if (/(\/usr\/bin\/|\/bin\/|\/usr\/local\/bin\/)/.test(src) && !/command\s+-v/.test(src)) {
106
+ ocorrencias.push(criarOcorrencia({
107
+ tipo: 'shell-missing-command-v',
108
+ nivel: 'info',
109
+ mensagem: messages.DetectorShellMensagens.missingCommandV,
110
+ relPath,
111
+ linha: 1,
112
+ sugestao: messages.DetectorShellMensagens.missingCommandVSugestao
113
+ }));
114
+ }
115
+ // DEBUG mode
116
+ if (!/\$\{DEBUG[^}]*\}/.test(src) && !/\$DEBUG\b/.test(src)) {
117
+ ocorrencias.push(criarOcorrencia({
118
+ tipo: 'shell-missing-debug-mode',
119
+ nivel: 'info',
120
+ mensagem: messages.DetectorShellMensagens.missingDebugMode,
121
+ relPath,
122
+ linha: 1,
123
+ sugestao: messages.DetectorShellMensagens.missingDebugModeSugestao
124
+ }));
125
+ }
126
+ // Input validation
127
+ if (/\$[0-9@*]/.test(src) && !/\[\[ -z "\$[0-9@*]/.test(src) && !/\[ -z "\$[0-9@*]/.test(src)) {
128
+ ocorrencias.push(criarOcorrencia({
129
+ tipo: 'shell-missing-input-validation',
130
+ nivel: 'info',
131
+ mensagem: messages.DetectorShellMensagens.missingInputValidation,
132
+ relPath,
133
+ linha: 1,
134
+ sugestao: messages.DetectorShellMensagens.missingInputValidationSugestao
135
+ }));
136
+ }
137
+ // ShellCheck recommendation (only if script is non-trivial)
138
+ if (linhas.length > 10 && !src.includes('shellcheck')) {
139
+ ocorrencias.push(criarOcorrencia({
140
+ tipo: 'shellcheck-recommended',
141
+ nivel: 'info',
142
+ mensagem: messages.DetectorShellMensagens.shellCheckRecommended,
143
+ relPath,
144
+ linha: 1,
145
+ sugestao: messages.DetectorShellMensagens.shellCheckRecommendedSugestao
146
+ }));
147
+ }
60
148
  const isSh = /\/bin\/sh(\s|$)/.test(shebang);
61
149
  linhas.forEach((linha, index) => {
62
150
  const numeroLinha = index + 1;
@@ -12,7 +12,7 @@
12
12
  import { splitLines } from '../../../shared/helpers/index.js';
13
13
  export function pontuarShell(src, _relPath) {
14
14
  let score = 0;
15
- const maxScore = 200;
15
+ const maxScore = 280;
16
16
  const issues = [];
17
17
  const strengths = [];
18
18
  const linhas = splitLines(src);
@@ -33,6 +33,30 @@ export function pontuarShell(src, _relPath) {
33
33
  else {
34
34
  issues.push('Sem set -e / pipefail');
35
35
  }
36
+ // set -u (10 pontos)
37
+ if (/set\s+-u/.test(srcCompleto)) {
38
+ score += 10;
39
+ strengths.push('Strict mode (set -u)');
40
+ }
41
+ else {
42
+ issues.push('Sem set -u');
43
+ }
44
+ // IFS (5 pontos)
45
+ if (/IFS=/.test(srcCompleto)) {
46
+ score += 5;
47
+ strengths.push('IFS configurado');
48
+ }
49
+ else {
50
+ issues.push('Sem IFS');
51
+ }
52
+ // trap handler (10 pontos)
53
+ if (/\btrap\s+/.test(srcCompleto)) {
54
+ score += 10;
55
+ strengths.push('Cleanup handler presente');
56
+ }
57
+ else {
58
+ issues.push('Sem trap handler');
59
+ }
36
60
  // No eval (15 pontos)
37
61
  if (!/\beval\s+/.test(srcCompleto)) {
38
62
  score += 15;
@@ -218,6 +242,39 @@ export function pontuarShell(src, _relPath) {
218
242
  else {
219
243
  issues.push('sudo detectado');
220
244
  }
245
+ // ── Modern Bash (2026) ──────────────────────────────────────────
246
+ // main function pattern (5 pontos)
247
+ if (/main\s*\(\s*\)/.test(srcCompleto)) {
248
+ score += 5;
249
+ strengths.push('Função main presente');
250
+ }
251
+ else {
252
+ issues.push('Sem padrão de função main');
253
+ }
254
+ // command -v usage (5 pontos)
255
+ if (hardPaths === 0 || /command\s+-v/.test(srcCompleto)) {
256
+ score += 5;
257
+ strengths.push('Uso de command -v');
258
+ }
259
+ else {
260
+ issues.push('Caminhos fixos sem command -v');
261
+ }
262
+ // DEBUG mode (5 pontos)
263
+ if (/\$\{DEBUG[^}]*\}/.test(srcCompleto) || /\$DEBUG\b/.test(srcCompleto)) {
264
+ score += 5;
265
+ strengths.push('Modo debug presente');
266
+ }
267
+ else {
268
+ issues.push('Sem modo debug');
269
+ }
270
+ // Input validation (5 pontos)
271
+ if (/\[\[ -z "\$[0-9@*]/.test(srcCompleto) || /\[ -z "\$[0-9@*]/.test(srcCompleto)) {
272
+ score += 5;
273
+ strengths.push('Validação de input');
274
+ }
275
+ else if (/\$[0-9]/.test(srcCompleto)) {
276
+ issues.push('Sem validação de argumentos');
277
+ }
221
278
  return {
222
279
  score,
223
280
  maxScore,
@@ -55,12 +55,10 @@ export const OperarioEstrutura = {
55
55
  } : {})
56
56
  }, sinaisAvancados // Passar sinais avançados para inteligência contextual
57
57
  );
58
- if (planoAlt && Array.isArray(planoAlt.mover)) {
59
- return {
60
- plano: planoAlt,
61
- origem: 'estrategista'
62
- };
63
- }
58
+ return {
59
+ plano: planoAlt,
60
+ origem: 'estrategista'
61
+ };
64
62
  }
65
63
  catch (erro) {
66
64
  log.aviso(MENSAGENS_ARQUETIPOS_HANDLER.falhaEstrategista);
@@ -109,7 +107,7 @@ export const OperarioEstrutura = {
109
107
  return mapa;
110
108
  }
111
109
  for (const occ of ocorrencias) {
112
- const rel = occ.relPath ?? occ.arquivo ?? 'arquivo desconhecido';
110
+ const rel = occ.relPath;
113
111
  mapa.push({
114
112
  arquivo: rel,
115
113
  ideal: null,
@@ -29,7 +29,7 @@ export const analistaSugestoesContextuais = {
29
29
  // Obter package.json se disponível
30
30
  let packageJson;
31
31
  try {
32
- const pkgArquivo = contexto.arquivos.find(arquivo => arquivo.relPath === 'package.json');
32
+ const pkgArquivo = contexto.arquivos?.find(arquivo => arquivo.relPath === 'package.json');
33
33
  if (pkgArquivo?.content) {
34
34
  packageJson = JSON.parse(pkgArquivo.content);
35
35
  }
@@ -112,9 +112,12 @@ export const analistaSugestoesContextuais = {
112
112
  case 'estrutura':
113
113
  mensagem = messages.SugestoesContextuaisMensagens.evidenciaEstrutura(evidencia.valor, melhorResultado.tecnologia);
114
114
  break;
115
+ case 'export':
116
+ case 'config':
117
+ case 'script':
118
+ continue;
115
119
  default:
116
120
  continue;
117
- // Pular outros tipos menos relevantes
118
121
  }
119
122
  ocorrencias.push({
120
123
  tipo: 'evidencia_contextual',
@@ -1,3 +1,4 @@
1
+ // SPDX-License-Identifier: MIT
1
2
  import { messages } from '../../../core/messages/index.js';
2
3
  import { otimizarSvgLikeSvgo, shouldSugerirOtimizacaoSvg } from '../../../shared/formatters/index.js';
3
4
  import { criarAnalista, criarOcorrencia } from '../../../types/index.js';