octocode-cli 1.2.8 → 1.2.9

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 (282) hide show
  1. package/README.md +42 -35
  2. package/out/octocode-cli.js +36 -11767
  3. package/package.json +36 -36
  4. package/skills/README.md +42 -114
  5. package/skills/{octocode-code-engineer → octocode-engineer}/.claude/settings.local.json +2 -1
  6. package/skills/octocode-engineer/README.md +99 -0
  7. package/skills/octocode-engineer/SKILL.md +499 -0
  8. package/skills/octocode-engineer/build.mjs +29 -0
  9. package/skills/{octocode-code-engineer → octocode-engineer}/eslint.config.mjs +3 -13
  10. package/skills/{octocode-code-engineer → octocode-engineer}/package.json +28 -27
  11. package/skills/octocode-engineer/references/ast-reference.md +166 -0
  12. package/skills/{octocode-code-engineer → octocode-engineer}/references/cli-reference.md +80 -6
  13. package/skills/octocode-engineer/references/externals.md +86 -0
  14. package/skills/{octocode-code-engineer → octocode-engineer}/references/output-files.md +46 -6
  15. package/skills/octocode-engineer/references/quality-indicators.md +202 -0
  16. package/skills/octocode-engineer/references/tool-workflows.md +298 -0
  17. package/skills/octocode-engineer/references/validation-playbooks.md +99 -0
  18. package/skills/octocode-engineer/scripts/ast/search.js +45 -0
  19. package/skills/octocode-engineer/scripts/ast/tree-search.js +27 -0
  20. package/skills/octocode-engineer/scripts/index.js +173 -0
  21. package/skills/octocode-engineer/scripts/run.js +179 -0
  22. package/skills/octocode-engineer/src/analysis/dependencies.ts +378 -0
  23. package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/discovery.test.ts +57 -0
  24. package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/discovery.ts +43 -0
  25. package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/search.test.ts +113 -0
  26. package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/search.ts +64 -1
  27. package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-sitter.test.ts +118 -2
  28. package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-sitter.ts +65 -3
  29. package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/ts-analyzer.test.ts +281 -1
  30. package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/ts-analyzer.ts +173 -3
  31. package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/security.test.ts +73 -0
  32. package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/security.ts +62 -4
  33. package/skills/octocode-engineer/src/detector-gating.test.ts +59 -0
  34. package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/code-quality.ts +342 -0
  35. package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/index.ts +8 -0
  36. package/skills/{octocode-code-engineer → octocode-engineer}/src/index.test.ts +565 -11
  37. package/skills/octocode-engineer/src/index.ts +468 -0
  38. package/skills/octocode-engineer/src/pipeline/affected.test.ts +147 -0
  39. package/skills/octocode-engineer/src/pipeline/affected.ts +68 -0
  40. package/skills/octocode-engineer/src/pipeline/baseline.test.ts +276 -0
  41. package/skills/octocode-engineer/src/pipeline/baseline.ts +76 -0
  42. package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cli.test.ts +300 -53
  43. package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cli.ts +180 -36
  44. package/skills/octocode-engineer/src/pipeline/config-loader.test.ts +264 -0
  45. package/skills/octocode-engineer/src/pipeline/config-loader.ts +109 -0
  46. package/skills/octocode-engineer/src/pipeline/create-options.ts +55 -0
  47. package/skills/octocode-engineer/src/pipeline/health-score.test.ts +65 -0
  48. package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/main.ts +130 -17
  49. package/skills/octocode-engineer/src/pipeline/progress.ts +51 -0
  50. package/skills/octocode-engineer/src/pipeline/reporters.test.ts +155 -0
  51. package/skills/octocode-engineer/src/pipeline/reporters.ts +64 -0
  52. package/skills/octocode-engineer/src/reporting/graph-features.test.ts +279 -0
  53. package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/output-contract.test.ts +6 -0
  54. package/skills/octocode-engineer/src/reporting/summary-md.test.ts +1066 -0
  55. package/skills/octocode-engineer/src/reporting/summary-md.ts +1604 -0
  56. package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/writer.ts +136 -13
  57. package/skills/octocode-engineer/src/run.ts +78 -0
  58. package/skills/{octocode-code-engineer → octocode-engineer}/src/sanity.test.ts +1 -1
  59. package/skills/octocode-engineer/src/types/analysis.ts +25 -0
  60. package/skills/octocode-engineer/src/types/collectors.ts +134 -0
  61. package/skills/{octocode-code-engineer → octocode-engineer}/src/types/constants.ts +75 -41
  62. package/skills/octocode-engineer/src/types/core.ts +203 -0
  63. package/skills/octocode-engineer/src/types/dependency.ts +215 -0
  64. package/skills/octocode-engineer/src/types/file-entry.ts +108 -0
  65. package/skills/octocode-engineer/src/types/findings.ts +105 -0
  66. package/skills/{octocode-code-engineer → octocode-engineer}/src/types/index.ts +60 -30
  67. package/skills/octocode-engineer/src/types/tree-sitter.ts +38 -0
  68. package/skills/{octocode-code-engineer → octocode-engineer}/tsconfig.json +1 -0
  69. package/skills/octocode-research/.octocode/scan/.cache/analysis-cache.json +1 -0
  70. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/architecture.json +1 -0
  71. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/ast-trees.txt +5566 -0
  72. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/code-quality.json +1 -0
  73. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/dead-code.json +1 -0
  74. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/file-inventory.json +1 -0
  75. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/findings.json +1 -0
  76. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/graph.md +189 -0
  77. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/security.json +1 -0
  78. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/summary.json +1 -0
  79. package/skills/octocode-research/.octocode/scan/2026-03-22T10-32-27-073Z/summary.md +265 -0
  80. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/architecture.json +1 -0
  81. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/ast-trees.txt +5555 -0
  82. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/code-quality.json +1 -0
  83. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/dead-code.json +1 -0
  84. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/file-inventory.json +1 -0
  85. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/findings.json +1 -0
  86. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/graph.md +190 -0
  87. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/security.json +1 -0
  88. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/summary.json +1 -0
  89. package/skills/octocode-research/.octocode/scan/2026-03-22T10-40-10-469Z/summary.md +265 -0
  90. package/skills/octocode-research/CHANGELOG.md +60 -0
  91. package/skills/octocode-research/README.md +102 -388
  92. package/skills/octocode-research/SKILL.md +169 -498
  93. package/skills/octocode-research/package.json +19 -31
  94. package/skills/octocode-research/references/PARALLEL_AGENT_PROTOCOL.md +19 -0
  95. package/skills/octocode-research/references/SESSION_MANAGEMENT.md +38 -0
  96. package/skills/octocode-research/scripts/server-init.js +1 -1
  97. package/skills/octocode-research/scripts/server.d.ts +2 -1
  98. package/skills/octocode-research/scripts/server.js +329 -233
  99. package/skills/octocode-research/src/__tests__/integration/promptsRoutes.test.ts +180 -0
  100. package/skills/octocode-research/src/__tests__/integration/serverHttp.test.ts +221 -0
  101. package/skills/octocode-research/src/__tests__/integration/serverLifecycle.test.ts +194 -0
  102. package/skills/octocode-research/src/__tests__/integration/toolsRoutes.test.ts +501 -0
  103. package/skills/octocode-research/src/__tests__/unit/readiness.test.ts +61 -0
  104. package/skills/octocode-research/src/__tests__/unit/resilience.test.ts +192 -0
  105. package/skills/octocode-research/src/__tests__/unit/responseFactory.test.ts +172 -0
  106. package/skills/octocode-research/src/__tests__/unit/responseParser.test.ts +288 -0
  107. package/skills/octocode-research/src/__tests__/unit/schemas.test.ts +509 -0
  108. package/skills/octocode-research/src/index.ts +4 -124
  109. package/skills/octocode-research/src/middleware/queryParser.ts +0 -26
  110. package/skills/octocode-research/src/routes/lsp.ts +58 -59
  111. package/skills/octocode-research/src/routes/package.ts +35 -65
  112. package/skills/octocode-research/src/routes/prompts.ts +3 -3
  113. package/skills/octocode-research/src/routes/tools.ts +8 -20
  114. package/skills/octocode-research/src/server-init.ts +30 -237
  115. package/skills/octocode-research/src/server.ts +50 -23
  116. package/skills/octocode-research/src/types/errorGuards.ts +9 -80
  117. package/skills/octocode-research/src/types/guards.ts +0 -28
  118. package/skills/octocode-research/src/types/mcp.ts +11 -66
  119. package/skills/octocode-research/src/types/responses.ts +11 -129
  120. package/skills/octocode-research/src/utils/circuitBreaker.ts +0 -21
  121. package/skills/octocode-research/src/utils/logger.ts +1 -97
  122. package/skills/octocode-research/src/utils/resilience.ts +2 -12
  123. package/skills/octocode-research/src/utils/responseFactory.ts +0 -42
  124. package/skills/octocode-research/src/utils/responseParser.ts +3 -25
  125. package/skills/octocode-research/src/utils/retry.ts +0 -63
  126. package/skills/octocode-research/src/utils/routeFactory.ts +1 -1
  127. package/skills/octocode-research/src/validation/httpPreprocess.ts +0 -3
  128. package/skills/octocode-research/src/validation/index.ts +0 -1
  129. package/skills/octocode-research/src/validation/schemas.ts +0 -63
  130. package/skills/octocode-research/src/validation/toolCallSchema.ts +3 -3
  131. package/skills/octocode-research/tsdown.config.ts +4 -0
  132. package/skills/octocode-research/vitest.config.ts +3 -0
  133. package/skills/octocode-code-engineer/.plan/VALIDATED_PLAN.md +0 -223
  134. package/skills/octocode-code-engineer/README.md +0 -178
  135. package/skills/octocode-code-engineer/SKILL.md +0 -418
  136. package/skills/octocode-code-engineer/minify-scripts.mjs +0 -32
  137. package/skills/octocode-code-engineer/references/agent-ast-reading-rfc.md +0 -95
  138. package/skills/octocode-code-engineer/references/architecture-techniques.md +0 -121
  139. package/skills/octocode-code-engineer/references/ast-search.md +0 -210
  140. package/skills/octocode-code-engineer/references/ast-tree-search.md +0 -151
  141. package/skills/octocode-code-engineer/references/concepts.md +0 -107
  142. package/skills/octocode-code-engineer/references/finding-categories.md +0 -128
  143. package/skills/octocode-code-engineer/references/improvement-roadmap.md +0 -304
  144. package/skills/octocode-code-engineer/references/playbooks.md +0 -204
  145. package/skills/octocode-code-engineer/references/present-results.md +0 -136
  146. package/skills/octocode-code-engineer/references/tool-workflows.md +0 -566
  147. package/skills/octocode-code-engineer/references/validate-investigate.md +0 -225
  148. package/skills/octocode-code-engineer/scripts/analysis/dependencies.js +0 -1
  149. package/skills/octocode-code-engineer/scripts/analysis/dependency-summary.js +0 -1
  150. package/skills/octocode-code-engineer/scripts/analysis/discovery.js +0 -1
  151. package/skills/octocode-code-engineer/scripts/analysis/graph-analytics.js +0 -1
  152. package/skills/octocode-code-engineer/scripts/analysis/semantic.js +0 -1
  153. package/skills/octocode-code-engineer/scripts/ast/helpers.js +0 -1
  154. package/skills/octocode-code-engineer/scripts/ast/metrics.js +0 -1
  155. package/skills/octocode-code-engineer/scripts/ast/search.js +0 -2
  156. package/skills/octocode-code-engineer/scripts/ast/tree-search.js +0 -2
  157. package/skills/octocode-code-engineer/scripts/ast/tree-sitter.js +0 -1
  158. package/skills/octocode-code-engineer/scripts/ast/ts-analyzer.js +0 -1
  159. package/skills/octocode-code-engineer/scripts/collectors/chains.js +0 -1
  160. package/skills/octocode-code-engineer/scripts/collectors/effects.js +0 -1
  161. package/skills/octocode-code-engineer/scripts/collectors/input-sources.js +0 -1
  162. package/skills/octocode-code-engineer/scripts/collectors/performance.js +0 -1
  163. package/skills/octocode-code-engineer/scripts/collectors/prototype-pollution.js +0 -1
  164. package/skills/octocode-code-engineer/scripts/collectors/security.js +0 -1
  165. package/skills/octocode-code-engineer/scripts/collectors/test-profile.js +0 -1
  166. package/skills/octocode-code-engineer/scripts/common/is-direct-run.js +0 -1
  167. package/skills/octocode-code-engineer/scripts/common/utils.js +0 -1
  168. package/skills/octocode-code-engineer/scripts/detectors/code-quality.js +0 -1
  169. package/skills/octocode-code-engineer/scripts/detectors/cohesion.js +0 -1
  170. package/skills/octocode-code-engineer/scripts/detectors/coupling.js +0 -1
  171. package/skills/octocode-code-engineer/scripts/detectors/cycle.js +0 -1
  172. package/skills/octocode-code-engineer/scripts/detectors/dead-code.js +0 -1
  173. package/skills/octocode-code-engineer/scripts/detectors/import-style.js +0 -1
  174. package/skills/octocode-code-engineer/scripts/detectors/index.js +0 -1
  175. package/skills/octocode-code-engineer/scripts/detectors/security.js +0 -1
  176. package/skills/octocode-code-engineer/scripts/detectors/semantic.js +0 -1
  177. package/skills/octocode-code-engineer/scripts/detectors/shared.js +0 -1
  178. package/skills/octocode-code-engineer/scripts/detectors/test-quality.js +0 -1
  179. package/skills/octocode-code-engineer/scripts/index.js +0 -1
  180. package/skills/octocode-code-engineer/scripts/pipeline/cache.js +0 -1
  181. package/skills/octocode-code-engineer/scripts/pipeline/cli.js +0 -1
  182. package/skills/octocode-code-engineer/scripts/pipeline/main.js +0 -2
  183. package/skills/octocode-code-engineer/scripts/reporting/analysis.js +0 -1
  184. package/skills/octocode-code-engineer/scripts/reporting/summary-md.js +0 -1
  185. package/skills/octocode-code-engineer/scripts/reporting/writer.js +0 -1
  186. package/skills/octocode-code-engineer/scripts/types/constants.js +0 -1
  187. package/skills/octocode-code-engineer/scripts/types/index.js +0 -1
  188. package/skills/octocode-code-engineer/scripts/types/interfaces.js +0 -1
  189. package/skills/octocode-code-engineer/src/analysis/dependencies.ts +0 -406
  190. package/skills/octocode-code-engineer/src/index.ts +0 -403
  191. package/skills/octocode-code-engineer/src/reporting/summary-md.test.ts +0 -421
  192. package/skills/octocode-code-engineer/src/reporting/summary-md.ts +0 -714
  193. package/skills/octocode-code-engineer/src/types/interfaces.ts +0 -682
  194. package/skills/octocode-research/src/types/toolTypes.ts +0 -33
  195. package/skills/octocode-research/src/utils/logEmoji.ts +0 -103
  196. /package/skills/{octocode-code-engineer → octocode-engineer}/.octocode/rfc/RFC-code-engineer-weakness-fixes.md +0 -0
  197. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/architecture.ts.html +0 -0
  198. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/ast-helpers.ts.html +0 -0
  199. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/ast-search.ts.html +0 -0
  200. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/base.css +0 -0
  201. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/block-navigation.js +0 -0
  202. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/cache.ts.html +0 -0
  203. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/cli.ts.html +0 -0
  204. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/clover.xml +0 -0
  205. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-effects.ts.html +0 -0
  206. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-input-sources.ts.html +0 -0
  207. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-performance.ts.html +0 -0
  208. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-prototype-pollution.ts.html +0 -0
  209. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-security.ts.html +0 -0
  210. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/collect-test-profile.ts.html +0 -0
  211. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/coverage-final.json +0 -0
  212. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/dependencies.ts.html +0 -0
  213. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/dependency-summary.ts.html +0 -0
  214. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/discovery.ts.html +0 -0
  215. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/favicon.png +0 -0
  216. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/graph-analytics.ts.html +0 -0
  217. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/index.html +0 -0
  218. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/index.ts.html +0 -0
  219. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/metrics.ts.html +0 -0
  220. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/pipeline.ts.html +0 -0
  221. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/prettify.css +0 -0
  222. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/prettify.js +0 -0
  223. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/report-analysis.ts.html +0 -0
  224. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/report-writer.ts.html +0 -0
  225. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/security-detectors.ts.html +0 -0
  226. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/semantic-detectors.ts.html +0 -0
  227. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/semantic.ts.html +0 -0
  228. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/sort-arrow-sprite.png +0 -0
  229. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/sorter.js +0 -0
  230. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/summary-md.ts.html +0 -0
  231. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/test-quality-detectors.ts.html +0 -0
  232. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/tree-sitter-analyzer.ts.html +0 -0
  233. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/ts-analyzer.ts.html +0 -0
  234. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/types.ts.html +0 -0
  235. /package/skills/{octocode-code-engineer → octocode-engineer}/coverage/utils.ts.html +0 -0
  236. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/dependencies.test.ts +0 -0
  237. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/dependency-summary.test.ts +0 -0
  238. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/dependency-summary.ts +0 -0
  239. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/graph-analytics.test.ts +0 -0
  240. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/graph-analytics.ts +0 -0
  241. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/semantic.test.ts +0 -0
  242. /package/skills/{octocode-code-engineer → octocode-engineer}/src/analysis/semantic.ts +0 -0
  243. /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/helpers.test.ts +0 -0
  244. /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/helpers.ts +0 -0
  245. /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/metrics.test.ts +0 -0
  246. /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/metrics.ts +0 -0
  247. /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-search.test.ts +0 -0
  248. /package/skills/{octocode-code-engineer → octocode-engineer}/src/ast/tree-search.ts +0 -0
  249. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/chains.ts +0 -0
  250. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/effects.test.ts +0 -0
  251. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/effects.ts +0 -0
  252. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/input-sources.test.ts +0 -0
  253. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/input-sources.ts +0 -0
  254. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/performance.test.ts +0 -0
  255. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/performance.ts +0 -0
  256. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/prototype-pollution.test.ts +0 -0
  257. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/prototype-pollution.ts +0 -0
  258. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/test-profile.test.ts +0 -0
  259. /package/skills/{octocode-code-engineer → octocode-engineer}/src/collectors/test-profile.ts +0 -0
  260. /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/is-direct-run.test.ts +0 -0
  261. /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/is-direct-run.ts +0 -0
  262. /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/utils.test.ts +0 -0
  263. /package/skills/{octocode-code-engineer → octocode-engineer}/src/common/utils.ts +0 -0
  264. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/cohesion.ts +0 -0
  265. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/coupling.ts +0 -0
  266. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/cycle.ts +0 -0
  267. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/dead-code.ts +0 -0
  268. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/import-style.ts +0 -0
  269. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/index.test.ts +0 -0
  270. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/security.test.ts +0 -0
  271. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/security.ts +0 -0
  272. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/semantic.ts +0 -0
  273. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/shared.ts +0 -0
  274. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/test-quality.test.ts +0 -0
  275. /package/skills/{octocode-code-engineer → octocode-engineer}/src/detectors/test-quality.ts +0 -0
  276. /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cache.test.ts +0 -0
  277. /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/cache.ts +0 -0
  278. /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline/main.test.ts +0 -0
  279. /package/skills/{octocode-code-engineer → octocode-engineer}/src/pipeline.test.ts +0 -0
  280. /package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/analysis.test.ts +0 -0
  281. /package/skills/{octocode-code-engineer → octocode-engineer}/src/reporting/analysis.ts +0 -0
  282. /package/skills/{octocode-code-engineer → octocode-engineer}/vitest.config.ts +0 -0
@@ -1,714 +0,0 @@
1
- import fs from 'node:fs';
2
- import path from 'node:path';
3
-
4
- import { PILLAR_CATEGORIES, SEVERITY_ORDER } from '../types/index.js';
5
-
6
- import type { ReportAnalysisSummary } from './analysis.js';
7
- import type { Finding } from '../types/index.js';
8
-
9
- export function severityBreakdown(findings: Finding[]): Record<string, number> {
10
- const counts: Record<string, number> = {
11
- critical: 0,
12
- high: 0,
13
- medium: 0,
14
- low: 0,
15
- info: 0,
16
- };
17
- for (const f of findings) counts[f.severity] = (counts[f.severity] || 0) + 1;
18
- return counts;
19
- }
20
-
21
- export function categoryBreakdown(findings: Finding[]): Record<string, number> {
22
- const counts: Record<string, number> = {};
23
- for (const f of findings) counts[f.category] = (counts[f.category] || 0) + 1;
24
- return counts;
25
- }
26
-
27
- export function computeHealthScore(
28
- findings: Finding[],
29
- totalFiles: number
30
- ): number {
31
- return computeHealthScoreFromSeverityBreakdown(
32
- severityBreakdown(findings),
33
- totalFiles
34
- );
35
- }
36
-
37
- function computeHealthScoreFromSeverityBreakdown(
38
- breakdown: Record<string, number>,
39
- totalFiles: number
40
- ): number {
41
- if (totalFiles === 0) return 100;
42
- const weights = { critical: 25, high: 10, medium: 3, low: 1, info: 0 };
43
- let penalty = 0;
44
- for (const [severity, count] of Object.entries(breakdown)) {
45
- penalty += (weights[severity as keyof typeof weights] || 0) * count;
46
- }
47
- const weightedFindingsPerFile = penalty / totalFiles;
48
- return Math.max(
49
- 0,
50
- Math.min(100, Math.round(100 / (1 + weightedFindingsPerFile / 10)))
51
- );
52
- }
53
-
54
- export function collectTagCloud(
55
- findings: Finding[]
56
- ): { tag: string; count: number }[] {
57
- const tagCounts = new Map<string, number>();
58
- for (const f of findings) {
59
- if (!f.tags) continue;
60
- for (const tag of f.tags) {
61
- tagCounts.set(tag, (tagCounts.get(tag) || 0) + 1);
62
- }
63
- }
64
- return [...tagCounts.entries()]
65
- .map(([tag, count]) => ({ tag, count }))
66
- .sort((a, b) => b.count - a.count);
67
- }
68
-
69
- export function formatFileSize(bytes: number): string {
70
- if (bytes < 1024) return `${bytes} B`;
71
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
72
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
73
- }
74
-
75
- function summarizeActiveFeatures(activeFeatures: Set<string>): string[] {
76
- const remaining = new Set(activeFeatures);
77
- const labels: string[] = [];
78
-
79
- for (const [pillar, categories] of Object.entries(PILLAR_CATEGORIES)) {
80
- if (categories.length > 0 && categories.every(cat => remaining.has(cat))) {
81
- labels.push(pillar);
82
- for (const cat of categories) remaining.delete(cat);
83
- }
84
- }
85
-
86
- return [...labels, ...[...remaining].sort()];
87
- }
88
-
89
- function isPillarActive(
90
- pillarKey: string,
91
- activeFeatures: Set<string> | null
92
- ): boolean {
93
- if (!activeFeatures) return true;
94
- const pillarCats = PILLAR_CATEGORIES[pillarKey] || [];
95
- return pillarCats.some(cat => activeFeatures.has(cat));
96
- }
97
-
98
- type FindingLike = Omit<Finding, 'id'> & { id?: string };
99
-
100
- export function diversifyFindings<T extends FindingLike>(
101
- sorted: T[],
102
- limit: number
103
- ): T[] {
104
- if (!Number.isFinite(limit) || limit >= sorted.length) return sorted;
105
-
106
- const groups = new Map<string, T[]>();
107
- for (const f of sorted) {
108
- const cat = f.category;
109
- if (!groups.has(cat)) groups.set(cat, []);
110
- groups.get(cat)!.push(f);
111
- }
112
-
113
- const categoryOrder = [...groups.entries()].sort((a, b) => {
114
- const aTop = SEVERITY_ORDER[a[1][0].severity] ?? 0;
115
- const bTop = SEVERITY_ORDER[b[1][0].severity] ?? 0;
116
- return bTop - aTop;
117
- });
118
-
119
- const result: T[] = [];
120
- const cursors = new Map<string, number>();
121
- for (const [cat] of categoryOrder) cursors.set(cat, 0);
122
-
123
- while (result.length < limit) {
124
- let picked = false;
125
- for (const [cat, items] of categoryOrder) {
126
- if (result.length >= limit) break;
127
- const cursor = cursors.get(cat)!;
128
- if (cursor < items.length) {
129
- result.push(items[cursor]);
130
- cursors.set(cat, cursor + 1);
131
- picked = true;
132
- }
133
- }
134
- if (!picked) break;
135
- }
136
- return result;
137
- }
138
-
139
- export function diverseTopRecommendations(
140
- findings: Finding[],
141
- limit: number = 20,
142
- maxPerCategory: number = 2
143
- ): Finding[] {
144
- const result: Finding[] = [];
145
- const countByCategory = new Map<string, number>();
146
- for (const f of findings) {
147
- const catCount = countByCategory.get(f.category) || 0;
148
- if (catCount >= maxPerCategory) continue;
149
- result.push(f);
150
- countByCategory.set(f.category, catCount + 1);
151
- if (result.length >= limit) break;
152
- }
153
- return result;
154
- }
155
-
156
- export interface SummaryMdOptions {
157
- dir: string;
158
- report: import('./writer.js').FullReport;
159
- outputFiles: Record<string, string>;
160
- architectureFindings: Finding[];
161
- codeQualityFindings: Finding[];
162
- deadCodeFindings: Finding[];
163
- hotFiles?: import('../types/index.js').HotFile[];
164
- activeFeatures?: Set<string> | null;
165
- scope?: string[] | null;
166
- root?: string;
167
- scopeSymbols?: Map<string, string[]> | null;
168
- semanticEnabled?: boolean;
169
- securityFindings?: Finding[];
170
- testQualityFindings?: Finding[];
171
- reportAnalysis?: ReportAnalysisSummary;
172
- }
173
-
174
- function formatCliPath(filePath: string): string {
175
- return JSON.stringify(filePath.replace(/\\/g, '/'));
176
- }
177
-
178
- export function generateSummaryMd(opts: SummaryMdOptions): string {
179
- const {
180
- dir,
181
- report,
182
- outputFiles,
183
- architectureFindings,
184
- codeQualityFindings,
185
- deadCodeFindings,
186
- hotFiles = [],
187
- activeFeatures = null,
188
- scope = null,
189
- root = process.cwd(),
190
- scopeSymbols = null,
191
- semanticEnabled = false,
192
- securityFindings = [],
193
- testQualityFindings = [],
194
- reportAnalysis = null,
195
- } = opts;
196
- const allFindings = report.optimizationFindings || [];
197
- const summary = report.summary as Record<string, unknown>;
198
- const agentOutput = report.agentOutput as Record<string, unknown>;
199
- const findingStats = (agentOutput?.findingStats ??
200
- null) as
201
- | {
202
- overall?: {
203
- totalFindings: number;
204
- severityBreakdown: Record<string, number>;
205
- };
206
- pillars?: Record<
207
- string,
208
- {
209
- totalFindings: number;
210
- severityBreakdown: Record<string, number>;
211
- }
212
- >;
213
- }
214
- | null;
215
- const depGraph = report.dependencyGraph;
216
- const relativeScanDir = path.relative(root, dir) || '.';
217
- const exampleFileFilter = ((scope?.[0] ?? 'src/index').split(':')[0] || 'src/index')
218
- .replace(/\\/g, '/');
219
- const overallFindingStats = findingStats?.overall ?? {
220
- totalFindings: allFindings.length,
221
- severityBreakdown: severityBreakdown(allFindings),
222
- };
223
-
224
- const lines: string[] = [];
225
- lines.push('# Code Quality Scan Report\n');
226
- lines.push(`**Generated**: ${report.generatedAt} `);
227
- lines.push(`**Root**: \`${report.repoRoot}\`\n`);
228
-
229
- lines.push('## Scan Scope\n');
230
- lines.push(`| Metric | Count |`);
231
- lines.push(`|--------|-------|`);
232
- lines.push(`| Files analyzed | ${summary.totalFiles ?? '—'} |`);
233
- lines.push(`| Functions | ${summary.totalFunctions ?? '—'} |`);
234
- lines.push(`| Flow nodes | ${summary.totalFlows ?? '—'} |`);
235
- lines.push(`| Dependency files | ${summary.totalDependencyFiles ?? '—'} |`);
236
- lines.push(`| Packages | ${summary.totalPackages ?? '—'} |`);
237
- lines.push('');
238
-
239
- lines.push('## Findings Overview\n');
240
- lines.push(`| Severity | Count |`);
241
- lines.push(`|----------|-------|`);
242
- lines.push(`| Critical | ${overallFindingStats.severityBreakdown.critical ?? 0} |`);
243
- lines.push(`| High | ${overallFindingStats.severityBreakdown.high ?? 0} |`);
244
- lines.push(`| Medium | ${overallFindingStats.severityBreakdown.medium ?? 0} |`);
245
- lines.push(`| Low | ${overallFindingStats.severityBreakdown.low ?? 0} |`);
246
- lines.push(`| **Total** | **${overallFindingStats.totalFindings}** |`);
247
- lines.push('');
248
-
249
- const totalBefore = overallFindingStats.totalFindings || (agentOutput as Record<string, unknown>)
250
- ?.totalBeforeTruncation as number | undefined;
251
- const dropped = (agentOutput as Record<string, unknown>)
252
- ?.droppedCategories as string[] | undefined;
253
- if (totalBefore && totalBefore > allFindings.length) {
254
- lines.push(
255
- `> **Truncated**: Showing ${allFindings.length} of ${totalBefore} findings (\`--findings-limit ${allFindings.length}\`).`
256
- );
257
- if (dropped && dropped.length > 0) {
258
- lines.push(
259
- `> Dropped categories: ${dropped.map(c => `\`${c}\``).join(', ')}`
260
- );
261
- }
262
- lines.push('');
263
- }
264
-
265
- if (activeFeatures) {
266
- const featureLabels = summarizeActiveFeatures(activeFeatures);
267
- lines.push(
268
- `> **Features filter**: \`--features=${featureLabels.join(',')}\``
269
- );
270
- lines.push('');
271
- }
272
-
273
- if (scope && scope.length > 0) {
274
- const scopeDisplay = scope.map(s => path.relative(root, s)).filter(Boolean);
275
- if (scopeDisplay.length > 0) {
276
- let scopeLabel = scopeDisplay.map(p => `\`${p}\``).join(', ');
277
- if (scopeSymbols && scopeSymbols.size > 0) {
278
- const symParts: string[] = [];
279
- for (const [absFile, names] of scopeSymbols) {
280
- const rel = path.relative(root, absFile);
281
- symParts.push(...names.map(n => `\`${rel}:${n}\``));
282
- }
283
- scopeLabel = symParts.join(', ');
284
- }
285
- lines.push(`> **Scoped scan**: Only showing findings for: ${scopeLabel}`);
286
- lines.push('');
287
- }
288
- }
289
-
290
- if (semanticEnabled) {
291
- lines.push(
292
- '> **Semantic analysis**: TypeChecker + LanguageService enabled (14 additional categories)'
293
- );
294
- lines.push('');
295
- }
296
-
297
- const renderPillarCategories = (
298
- pillarKey: string,
299
- findings: Finding[]
300
- ): void => {
301
- const breakdown = categoryBreakdown(findings);
302
- const pillarCats = PILLAR_CATEGORIES[pillarKey] || [];
303
- const isFiltered = activeFeatures !== null;
304
- for (const cat of pillarCats) {
305
- const count = breakdown[cat] || 0;
306
- const skipped = isFiltered && !activeFeatures!.has(cat);
307
- if (skipped) {
308
- lines.push(`- \`${cat}\`: — *(skipped)*`);
309
- } else {
310
- lines.push(`- \`${cat}\`: ${count}`);
311
- }
312
- }
313
- lines.push('');
314
- };
315
-
316
- const totalFiles = (summary.totalFiles as number) || 1;
317
- const archStats = findingStats?.pillars?.['architecture'];
318
- const qualStats = findingStats?.pillars?.['code-quality'];
319
- const deadStats = findingStats?.pillars?.['dead-code'];
320
- const secStats = findingStats?.pillars?.['security'];
321
- const testStats = findingStats?.pillars?.['test-quality'];
322
- const overallHealth = computeHealthScoreFromSeverityBreakdown(
323
- overallFindingStats.severityBreakdown,
324
- totalFiles
325
- );
326
- const archHealth = computeHealthScoreFromSeverityBreakdown(
327
- archStats?.severityBreakdown ?? severityBreakdown(architectureFindings),
328
- totalFiles
329
- );
330
- const qualHealth = computeHealthScoreFromSeverityBreakdown(
331
- qualStats?.severityBreakdown ?? severityBreakdown(codeQualityFindings),
332
- totalFiles
333
- );
334
- const deadHealth = computeHealthScoreFromSeverityBreakdown(
335
- deadStats?.severityBreakdown ?? severityBreakdown(deadCodeFindings),
336
- totalFiles
337
- );
338
- const secHealth = computeHealthScoreFromSeverityBreakdown(
339
- secStats?.severityBreakdown ?? severityBreakdown(securityFindings),
340
- totalFiles
341
- );
342
- const testHealth = computeHealthScoreFromSeverityBreakdown(
343
- testStats?.severityBreakdown ?? severityBreakdown(testQualityFindings),
344
- totalFiles
345
- );
346
-
347
- lines.push('## Health Scores\n');
348
- lines.push('| Pillar | Score | Grade |');
349
- lines.push('|--------|-------|-------|');
350
- const grade = (s: number) =>
351
- s >= 80 ? 'A' : s >= 60 ? 'B' : s >= 40 ? 'C' : s >= 20 ? 'D' : 'F';
352
- const pushHealthRow = (label: string, pillarKey: string, score: number): void => {
353
- if (!isPillarActive(pillarKey, activeFeatures)) {
354
- lines.push(`| ${label} | — | skipped |`);
355
- return;
356
- }
357
- lines.push(`| ${label} | ${score}/100 | ${grade(score)} |`);
358
- };
359
- const pushPillarSummary = (
360
- pillarKey: string,
361
- findingsCount: number,
362
- score: number,
363
- artifactKey?: string,
364
- artifactName?: string
365
- ): void => {
366
- if (!isPillarActive(pillarKey, activeFeatures)) {
367
- lines.push('> skipped by feature filter\n');
368
- return;
369
- }
370
-
371
- if (artifactKey && outputFiles[artifactKey]) {
372
- lines.push(
373
- `> ${findingsCount} findings (score: ${score}/100) — see [\`${artifactName}\`](./${outputFiles[artifactKey]})\n`
374
- );
375
- return;
376
- }
377
-
378
- if (artifactName) {
379
- lines.push(
380
- `> ${findingsCount} findings (score: ${score}/100) — no \`${artifactName}\` written for this scan\n`
381
- );
382
- return;
383
- }
384
-
385
- lines.push(`> ${findingsCount} findings (score: ${score}/100)\n`);
386
- };
387
- lines.push(
388
- `| **Overall** | **${overallHealth}/100** | **${grade(overallHealth)}** |`
389
- );
390
- pushHealthRow('Architecture', 'architecture', archHealth);
391
- pushHealthRow('Code Quality', 'code-quality', qualHealth);
392
- pushHealthRow('Dead Code & Hygiene', 'dead-code', deadHealth);
393
- pushHealthRow('Security', 'security', secHealth);
394
- pushHealthRow('Test Quality', 'test-quality', testHealth);
395
- lines.push('');
396
-
397
- const tagCloud = collectTagCloud(allFindings);
398
- if (tagCloud.length > 0) {
399
- lines.push('## Top Concern Tags\n');
400
- lines.push(
401
- 'Searchable tags across all findings — use to filter `findings.json` with `jq`.\n'
402
- );
403
- for (const { tag, count } of tagCloud.slice(0, 12)) {
404
- lines.push(`- \`${tag}\`: ${count} findings`);
405
- }
406
- lines.push('');
407
- }
408
-
409
- if (reportAnalysis) {
410
- lines.push('## Analysis Signals\n');
411
- lines.push(
412
- `- **Graph Signal**: ${reportAnalysis.strongestGraphSignal?.summary || 'No dominant graph signal in this scan.'}`
413
- );
414
- lines.push(
415
- `- **AST Signal**: ${reportAnalysis.strongestAstSignal?.summary || 'No dominant AST signal in this scan.'}`
416
- );
417
- lines.push(
418
- `- **Combined Interpretation**: ${reportAnalysis.combinedInterpretation?.summary || 'No combined interpretation available yet.'}`
419
- );
420
- lines.push(
421
- `- **Confidence**: ${reportAnalysis.combinedInterpretation?.confidence || reportAnalysis.strongestGraphSignal?.confidence || reportAnalysis.strongestAstSignal?.confidence || 'low'}`
422
- );
423
- const validationSummary = reportAnalysis.recommendedValidation
424
- ? `${reportAnalysis.recommendedValidation.summary} (tools: ${reportAnalysis.recommendedValidation.tools.join(' -> ')})`
425
- : 'Use Octocode local tools to confirm the strongest signal before presenting it as fact.';
426
- lines.push(`- **Recommended Validation**: ${validationSummary}`);
427
- const megaFolderSignal = reportAnalysis.graphSignals.find(
428
- signal => signal.kind === 'mega-folder-cluster'
429
- );
430
- if (megaFolderSignal) {
431
- lines.push(`- **Structural Layout Alert**: ${megaFolderSignal.summary}`);
432
- }
433
- if (reportAnalysis.investigationPrompts.length > 0) {
434
- lines.push('');
435
- lines.push('**Investigation Prompts**');
436
- for (const prompt of reportAnalysis.investigationPrompts.slice(0, 4)) {
437
- lines.push(`- ${prompt}`);
438
- }
439
- }
440
- lines.push('');
441
- }
442
-
443
- lines.push('## Architecture Health\n');
444
- pushPillarSummary(
445
- 'architecture',
446
- archStats?.totalFindings ?? architectureFindings.length,
447
- archHealth,
448
- 'architecture',
449
- 'architecture.json'
450
- );
451
- if (depGraph) {
452
- lines.push(`| Metric | Value |`);
453
- lines.push(`|--------|-------|`);
454
- lines.push(`| Modules | ${depGraph.totalModules} |`);
455
- lines.push(`| Import edges | ${depGraph.totalEdges} |`);
456
- lines.push(`| Cycles | ${depGraph.cycles?.length ?? 0} |`);
457
- lines.push(`| Critical paths | ${depGraph.criticalPaths?.length ?? 0} |`);
458
- lines.push(`| Root modules | ${depGraph.rootsCount} |`);
459
- lines.push(`| Leaf modules | ${depGraph.leavesCount} |`);
460
- lines.push(
461
- `| Test-only modules | ${depGraph.testOnlyModules?.length ?? 0} |`
462
- );
463
- lines.push(`| Unresolved imports | ${depGraph.unresolvedEdgeCount} |`);
464
- lines.push('');
465
- }
466
- renderPillarCategories('architecture', architectureFindings);
467
-
468
- renderHotspots(lines, hotFiles);
469
-
470
- renderPillarSections(lines, {
471
- architectureFindings,
472
- codeQualityFindings,
473
- deadCodeFindings,
474
- securityFindings,
475
- testQualityFindings,
476
- archStats,
477
- qualStats,
478
- deadStats,
479
- secStats,
480
- testStats,
481
- archHealth,
482
- qualHealth,
483
- deadHealth,
484
- secHealth,
485
- testHealth,
486
- activeFeatures,
487
- outputFiles,
488
- renderPillarCategories,
489
- pushPillarSummary,
490
- });
491
-
492
- renderRecommendations(lines, agentOutput);
493
-
494
- if (outputFiles.astTrees) {
495
- renderAstTreesSection(lines, dir, outputFiles, root, relativeScanDir, exampleFileFilter);
496
- }
497
-
498
- renderOutputFilesTable(lines, dir, outputFiles);
499
-
500
- if (report.parseErrors?.length > 0) {
501
- lines.push('## Parse Errors\n');
502
- lines.push(`${report.parseErrors.length} file(s) failed to parse:\n`);
503
- for (const err of report.parseErrors.slice(0, 10)) {
504
- lines.push(`- \`${err.file}\`: ${err.message}`);
505
- }
506
- lines.push('');
507
- }
508
-
509
- return lines.join('\n');
510
- }
511
-
512
- function renderHotspots(
513
- lines: string[],
514
- hotFiles: SummaryMdOptions['hotFiles']
515
- ): void {
516
- if (!hotFiles || hotFiles.length === 0) return;
517
- lines.push('## Change Risk Hotspots\n');
518
- lines.push(
519
- 'Files most dangerous to change — high fan-in, complexity, or cycle membership.\n'
520
- );
521
- lines.push(
522
- '| File | Risk | Fan-In | Fan-Out | Complexity | Exports | Cycle | Critical Path |'
523
- );
524
- lines.push(
525
- '|------|------|--------|---------|------------|---------|-------|---------------|'
526
- );
527
- for (const hf of hotFiles.slice(0, 15)) {
528
- lines.push(
529
- `| \`${hf.file}\` | ${hf.riskScore} | ${hf.fanIn} | ${hf.fanOut} | ${hf.complexityScore} | ${hf.exportCount} | ${hf.inCycle ? 'Y' : '-'} | ${hf.onCriticalPath ? 'Y' : '-'} |`
530
- );
531
- }
532
- lines.push('');
533
- }
534
-
535
- function renderPillarSections(
536
- lines: string[],
537
- ctx: {
538
- architectureFindings: Finding[];
539
- codeQualityFindings: Finding[];
540
- deadCodeFindings: Finding[];
541
- securityFindings: Finding[];
542
- testQualityFindings: Finding[];
543
- archStats: { totalFindings: number; severityBreakdown: Record<string, number> } | undefined;
544
- qualStats: { totalFindings: number; severityBreakdown: Record<string, number> } | undefined;
545
- deadStats: { totalFindings: number; severityBreakdown: Record<string, number> } | undefined;
546
- secStats: { totalFindings: number; severityBreakdown: Record<string, number> } | undefined;
547
- testStats: { totalFindings: number; severityBreakdown: Record<string, number> } | undefined;
548
- archHealth: number;
549
- qualHealth: number;
550
- deadHealth: number;
551
- secHealth: number;
552
- testHealth: number;
553
- activeFeatures: Set<string> | null;
554
- outputFiles: Record<string, string>;
555
- renderPillarCategories: (pillarKey: string, findings: Finding[]) => void;
556
- pushPillarSummary: (pillarKey: string, count: number, score: number, artifactKey?: string, artifactName?: string) => void;
557
- }
558
- ): void {
559
- const { architectureFindings, codeQualityFindings, deadCodeFindings, securityFindings, testQualityFindings } = ctx;
560
- const { qualStats, deadStats, secStats, testStats } = ctx;
561
- const { qualHealth, deadHealth, secHealth, testHealth } = ctx;
562
- const { renderPillarCategories, pushPillarSummary } = ctx;
563
-
564
- lines.push('## Code Quality\n');
565
- pushPillarSummary(
566
- 'code-quality',
567
- qualStats?.totalFindings ?? codeQualityFindings.length,
568
- qualHealth,
569
- 'codeQuality',
570
- 'code-quality.json'
571
- );
572
- renderPillarCategories('code-quality', codeQualityFindings);
573
-
574
- lines.push('## Dead Code & Hygiene\n');
575
- pushPillarSummary(
576
- 'dead-code',
577
- deadStats?.totalFindings ?? deadCodeFindings.length,
578
- deadHealth,
579
- 'deadCode',
580
- 'dead-code.json'
581
- );
582
- renderPillarCategories('dead-code', deadCodeFindings);
583
-
584
- lines.push('## Security\n');
585
- pushPillarSummary(
586
- 'security',
587
- secStats?.totalFindings ?? securityFindings.length,
588
- secHealth,
589
- 'security',
590
- 'security.json'
591
- );
592
- renderPillarCategories('security', securityFindings);
593
-
594
- lines.push('## Test Quality\n');
595
- pushPillarSummary(
596
- 'test-quality',
597
- testStats?.totalFindings ?? testQualityFindings.length,
598
- testHealth,
599
- 'testQuality',
600
- 'test-quality.json'
601
- );
602
- renderPillarCategories('test-quality', testQualityFindings);
603
-
604
- const untestedCount = architectureFindings.filter(
605
- f => f.category === 'untested-critical-code'
606
- ).length;
607
- if (
608
- untestedCount > 0 &&
609
- (testStats?.totalFindings ?? testQualityFindings.length) === 0
610
- ) {
611
- lines.push(
612
- `> **Note**: Test Quality reflects analyzed test files only. ${untestedCount} modules flagged as \`untested-critical-code\` (architecture pillar) have no test coverage — use \`--include-tests\` for test-quality analysis.\n`
613
- );
614
- }
615
- }
616
-
617
- function renderRecommendations(
618
- lines: string[],
619
- agentOutput: Record<string, unknown>
620
- ): void {
621
- const topRecs = (agentOutput?.topRecommendations ?? []) as Array<{
622
- severity: string;
623
- title: string;
624
- file: string;
625
- category: string;
626
- }>;
627
- if (topRecs.length > 0) {
628
- lines.push('## Top Recommendations\n');
629
- for (const rec of topRecs.slice(0, 10)) {
630
- lines.push(
631
- `- **[${rec.severity.toUpperCase()}]** \`${rec.file}\` — ${rec.title} *(${rec.category})* `
632
- );
633
- }
634
- lines.push('');
635
- }
636
- }
637
-
638
- function renderAstTreesSection(
639
- lines: string[],
640
- dir: string,
641
- outputFiles: Record<string, string>,
642
- root: string,
643
- relativeScanDir: string,
644
- exampleFileFilter: string
645
- ): void {
646
- const astTreePath = path.resolve(dir, outputFiles.astTrees);
647
- const astTreeArg = formatCliPath(astTreePath);
648
- lines.push('## AST Trees (`ast-trees.txt`)\n');
649
- lines.push(
650
- 'Compact indented text format — each node is `Kind[startLine:endLine]`, nesting = indentation.\n'
651
- );
652
- lines.push(
653
- `Run these commands from the skill directory. Current scan: \`${relativeScanDir}\`.\n`
654
- );
655
- lines.push('```');
656
- lines.push('SourceFile[1:152]');
657
- lines.push(' ImportDeclaration[1]');
658
- lines.push(' FunctionDeclaration[3:20]');
659
- lines.push(' Block[4:19]');
660
- lines.push(' IfStatement[5:12] ...');
661
- lines.push('```\n');
662
- lines.push('**Smart navigation:**\n');
663
- lines.push(
664
- `- Find functions: \`node scripts/ast/tree-search.js -i ${astTreeArg} -k function_declaration --limit 25\``
665
- );
666
- lines.push(
667
- `- Find classes: \`node scripts/ast/tree-search.js -i ${astTreeArg} -k class_declaration --limit 25\``
668
- );
669
- lines.push(
670
- `- Find control flow: \`node scripts/ast/tree-search.js -i ${astTreeArg} -p 'IfStatement|SwitchStatement|ForStatement|WhileStatement' --limit 25\``
671
- );
672
- lines.push(
673
- `- Narrow to one file: \`node scripts/ast/tree-search.js -i ${astTreeArg} --file "${exampleFileFilter}" -k function_declaration --limit 10\``
674
- );
675
- lines.push(
676
- `- Raw text fallback: \`rg 'FunctionDeclaration|IfStatement' ${astTreeArg}\``
677
- );
678
- lines.push('');
679
- }
680
-
681
- function renderOutputFilesTable(
682
- lines: string[],
683
- dir: string,
684
- outputFiles: Record<string, string>
685
- ): void {
686
- lines.push('## Output Files\n');
687
- lines.push('| File | Size | Description |');
688
- lines.push('|------|------|-------------|');
689
- const descriptions: Record<string, string> = {
690
- summary: 'Scan metadata, agent output, parse errors',
691
- architecture:
692
- 'Dependency graph, cycles, critical paths, architecture findings',
693
- codeQuality: 'Duplicate detection, complexity, god modules/functions',
694
- deadCode: 'Dead files/exports/re-exports, unused deps, boundary violations',
695
- fileInventory: 'Per-file function/flow/dependency details',
696
- findings: 'All findings across all categories (master list)',
697
- graph: 'Mermaid dependency graph',
698
- astTrees:
699
- 'AST tree snapshots (compact indented text — grep/regex friendly)',
700
- summaryMd: 'This file — human-readable overview',
701
- };
702
- for (const [key, file] of Object.entries(outputFiles)) {
703
- let size = '—';
704
- try {
705
- size = formatFileSize(fs.statSync(path.join(dir, file)).size);
706
- } catch {
707
- size = '—';
708
- }
709
- lines.push(
710
- `| [\`${file}\`](./${file}) | ${size} | ${descriptions[key] || key} |`
711
- );
712
- }
713
- lines.push('');
714
- }