srcly 0.1.30__tar.gz → 0.1.32__tar.gz

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 (314) hide show
  1. {srcly-0.1.30 → srcly-0.1.32}/PKG-INFO +1 -1
  2. {srcly-0.1.30 → srcly-0.1.32}/app/run.py +54 -3
  3. {srcly-0.1.30 → srcly-0.1.32}/app/services/analysis.py +27 -19
  4. {srcly-0.1.30 → srcly-0.1.32}/app/services/reporting.py +164 -12
  5. srcly-0.1.30/app/static/assets/index-Bn6hDYiR.js → srcly-0.1.32/app/static/assets/index--Q3ju03c.js +3 -3
  6. srcly-0.1.32/app/static/assets/index-DOSG0br7.css +1 -0
  7. {srcly-0.1.30 → srcly-0.1.32}/app/static/index.html +2 -2
  8. {srcly-0.1.30 → srcly-0.1.32}/pyproject.toml +1 -1
  9. srcly-0.1.30/app/static/assets/index-DK1czI50.css +0 -1
  10. {srcly-0.1.30 → srcly-0.1.32}/.gitignore +0 -0
  11. {srcly-0.1.30 → srcly-0.1.32}/README.md +0 -0
  12. {srcly-0.1.30 → srcly-0.1.32}/app/.gitignore +0 -0
  13. {srcly-0.1.30 → srcly-0.1.32}/app/__init__.py +0 -0
  14. {srcly-0.1.30 → srcly-0.1.32}/app/config.py +0 -0
  15. {srcly-0.1.30 → srcly-0.1.32}/app/main.py +0 -0
  16. {srcly-0.1.30 → srcly-0.1.32}/app/models.py +0 -0
  17. {srcly-0.1.30 → srcly-0.1.32}/app/routers/analysis.py +0 -0
  18. {srcly-0.1.30 → srcly-0.1.32}/app/routers/files.py +0 -0
  19. {srcly-0.1.30 → srcly-0.1.32}/app/services/analysis_types.py +0 -0
  20. {srcly-0.1.30 → srcly-0.1.32}/app/services/cache.py +0 -0
  21. {srcly-0.1.30 → srcly-0.1.32}/app/services/css/css_analysis.py +0 -0
  22. {srcly-0.1.30 → srcly-0.1.32}/app/services/data_flow_analysis.py +0 -0
  23. {srcly-0.1.30 → srcly-0.1.32}/app/services/focus_overlay.py +0 -0
  24. {srcly-0.1.30 → srcly-0.1.32}/app/services/ipynb/ipynb_analysis.py +0 -0
  25. {srcly-0.1.30 → srcly-0.1.32}/app/services/markdown/markdown_analysis.py +0 -0
  26. {srcly-0.1.30 → srcly-0.1.32}/app/services/python/python_analysis.py +0 -0
  27. {srcly-0.1.30 → srcly-0.1.32}/app/services/typescript/typescript_analysis.py +0 -0
  28. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/abap-BdImnpbu.js +0 -0
  29. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/actionscript-3-CfeIJUat.js +0 -0
  30. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ada-bCR0ucgS.js +0 -0
  31. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/andromeeda-C-Jbm3Hp.js +0 -0
  32. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/angular-html-CU67Zn6k.js +0 -0
  33. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/angular-ts-BwZT4LLn.js +0 -0
  34. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/apache-Pmp26Uib.js +0 -0
  35. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/apex-DhZLUxFE.js +0 -0
  36. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/apl-dKokRX4l.js +0 -0
  37. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/applescript-Co6uUVPk.js +0 -0
  38. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ara-BRHolxvo.js +0 -0
  39. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/asciidoc-Dv7Oe6Be.js +0 -0
  40. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/asm-D_Q5rh1f.js +0 -0
  41. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/astro-CbQHKStN.js +0 -0
  42. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/aurora-x-D-2ljcwZ.js +0 -0
  43. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/awk-DMzUqQB5.js +0 -0
  44. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ayu-dark-Cv9koXgw.js +0 -0
  45. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ballerina-BFfxhgS-.js +0 -0
  46. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/bat-BkioyH1T.js +0 -0
  47. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/beancount-k_qm7-4y.js +0 -0
  48. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/berry-D08WgyRC.js +0 -0
  49. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/bibtex-CHM0blh-.js +0 -0
  50. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/bicep-Bmn6On1c.js +0 -0
  51. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/blade-DVc8C-J4.js +0 -0
  52. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/bsl-BO_Y6i37.js +0 -0
  53. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/c-BIGW1oBm.js +0 -0
  54. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cadence-Bv_4Rxtq.js +0 -0
  55. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cairo-KRGpt6FW.js +0 -0
  56. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/catppuccin-frappe-DFWUc33u.js +0 -0
  57. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/catppuccin-latte-C9dUb6Cb.js +0 -0
  58. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/catppuccin-macchiato-DQyhUUbL.js +0 -0
  59. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/catppuccin-mocha-D87Tk5Gz.js +0 -0
  60. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/clarity-D53aC0YG.js +0 -0
  61. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/clojure-P80f7IUj.js +0 -0
  62. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cmake-D1j8_8rp.js +0 -0
  63. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cobol-nwyudZeR.js +0 -0
  64. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/codeowners-Bp6g37R7.js +0 -0
  65. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/codeql-DsOJ9woJ.js +0 -0
  66. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/coffee-Ch7k5sss.js +0 -0
  67. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/common-lisp-Cg-RD9OK.js +0 -0
  68. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/coq-DkFqJrB1.js +0 -0
  69. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cpp-CofmeUqb.js +0 -0
  70. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/crystal-tKQVLTB8.js +0 -0
  71. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/csharp-CX12Zw3r.js +0 -0
  72. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/css-DPfMkruS.js +0 -0
  73. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/csv-fuZLfV_i.js +0 -0
  74. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cue-D82EKSYY.js +0 -0
  75. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/cypher-COkxafJQ.js +0 -0
  76. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/d-85-TOEBH.js +0 -0
  77. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dark-plus-eOWES_5F.js +0 -0
  78. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dart-CF10PKvl.js +0 -0
  79. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dax-CEL-wOlO.js +0 -0
  80. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/desktop-BmXAJ9_W.js +0 -0
  81. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/diff-D97Zzqfu.js +0 -0
  82. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/docker-BcOcwvcX.js +0 -0
  83. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dotenv-Da5cRb03.js +0 -0
  84. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dracula-BzJJZx-M.js +0 -0
  85. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dracula-soft-BXkSAIEj.js +0 -0
  86. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/dream-maker-BtqSS_iP.js +0 -0
  87. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/edge-BkV0erSs.js +0 -0
  88. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/elixir-CDX3lj18.js +0 -0
  89. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/elm-DbKCFpqz.js +0 -0
  90. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/emacs-lisp-C9XAeP06.js +0 -0
  91. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/erb-BOJIQeun.js +0 -0
  92. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/erlang-DsQrWhSR.js +0 -0
  93. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/everforest-dark-BgDCqdQA.js +0 -0
  94. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/everforest-light-C8M2exoo.js +0 -0
  95. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/fennel-BYunw83y.js +0 -0
  96. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/fish-BvzEVeQv.js +0 -0
  97. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/fluent-C4IJs8-o.js +0 -0
  98. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/fortran-fixed-form-BZjJHVRy.js +0 -0
  99. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/fortran-free-form-D22FLkUw.js +0 -0
  100. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/fsharp-CXgrBDvD.js +0 -0
  101. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gdresource-B7Tvp0Sc.js +0 -0
  102. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gdscript-DTMYz4Jt.js +0 -0
  103. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gdshader-DkwncUOv.js +0 -0
  104. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/genie-D0YGMca9.js +0 -0
  105. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gherkin-DyxjwDmM.js +0 -0
  106. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/git-commit-F4YmCXRG.js +0 -0
  107. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/git-rebase-r7XF79zn.js +0 -0
  108. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-dark-DHJKELXO.js +0 -0
  109. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-dark-default-Cuk6v7N8.js +0 -0
  110. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-dark-dimmed-DH5Ifo-i.js +0 -0
  111. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-dark-high-contrast-E3gJ1_iC.js +0 -0
  112. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-light-DAi9KRSo.js +0 -0
  113. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-light-default-D7oLnXFd.js +0 -0
  114. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/github-light-high-contrast-BfjtVDDH.js +0 -0
  115. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gleam-BspZqrRM.js +0 -0
  116. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/glimmer-js-Rg0-pVw9.js +0 -0
  117. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/glimmer-ts-U6CK756n.js +0 -0
  118. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/glsl-DplSGwfg.js +0 -0
  119. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gnuplot-DdkO51Og.js +0 -0
  120. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/go-Dn2_MT6a.js +0 -0
  121. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/graphql-ChdNCCLP.js +0 -0
  122. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/groovy-gcz8RCvz.js +0 -0
  123. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gruvbox-dark-hard-CFHQjOhq.js +0 -0
  124. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gruvbox-dark-medium-GsRaNv29.js +0 -0
  125. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gruvbox-dark-soft-CVdnzihN.js +0 -0
  126. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gruvbox-light-hard-CH1njM8p.js +0 -0
  127. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gruvbox-light-medium-DRw_LuNl.js +0 -0
  128. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/gruvbox-light-soft-hJgmCMqR.js +0 -0
  129. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hack-CaT9iCJl.js +0 -0
  130. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/haml-B8DHNrY2.js +0 -0
  131. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/handlebars-BL8al0AC.js +0 -0
  132. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/haskell-Df6bDoY_.js +0 -0
  133. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/haxe-CzTSHFRz.js +0 -0
  134. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hcl-BWvSN4gD.js +0 -0
  135. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hjson-D5-asLiD.js +0 -0
  136. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hlsl-D3lLCCz7.js +0 -0
  137. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/houston-DnULxvSX.js +0 -0
  138. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/html-GMplVEZG.js +0 -0
  139. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/html-derivative-BFtXZ54Q.js +0 -0
  140. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/http-jrhK8wxY.js +0 -0
  141. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hurl-irOxFIW8.js +0 -0
  142. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hxml-Bvhsp5Yf.js +0 -0
  143. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/hy-DFXneXwc.js +0 -0
  144. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/imba-DGztddWO.js +0 -0
  145. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ini-BEwlwnbL.js +0 -0
  146. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/java-CylS5w8V.js +0 -0
  147. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/javascript-wDzz0qaB.js +0 -0
  148. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jinja-4LBKfQ-Z.js +0 -0
  149. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jison-wvAkD_A8.js +0 -0
  150. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/json-Cp-IABpG.js +0 -0
  151. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/json5-C9tS-k6U.js +0 -0
  152. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jsonc-Des-eS-w.js +0 -0
  153. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jsonl-DcaNXYhu.js +0 -0
  154. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jsonnet-DFQXde-d.js +0 -0
  155. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jssm-C2t-YnRu.js +0 -0
  156. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/jsx-g9-lgVsj.js +0 -0
  157. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/julia-C8NyazO9.js +0 -0
  158. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/kanagawa-dragon-CkXjmgJE.js +0 -0
  159. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/kanagawa-lotus-CfQXZHmo.js +0 -0
  160. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/kanagawa-wave-DWedfzmr.js +0 -0
  161. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/kdl-DV7GczEv.js +0 -0
  162. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/kotlin-BdnUsdx6.js +0 -0
  163. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/kusto-BvAqAH-y.js +0 -0
  164. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/laserwave-DUszq2jm.js +0 -0
  165. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/latex-BUKiar2Z.js +0 -0
  166. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/lean-DP1Csr6i.js +0 -0
  167. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/less-B1dDrJ26.js +0 -0
  168. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/light-plus-B7mTdjB0.js +0 -0
  169. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/liquid-DYVedYrR.js +0 -0
  170. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/llvm-BtvRca6l.js +0 -0
  171. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/log-2UxHyX5q.js +0 -0
  172. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/logo-BtOb2qkB.js +0 -0
  173. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/lua-BbnMAYS6.js +0 -0
  174. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/luau-CXu1NL6O.js +0 -0
  175. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/make-CHLpvVh8.js +0 -0
  176. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/markdown-Cvjx9yec.js +0 -0
  177. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/marko-CPi9NSCl.js +0 -0
  178. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/material-theme-D5KoaKCx.js +0 -0
  179. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/material-theme-darker-BfHTSMKl.js +0 -0
  180. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/material-theme-lighter-B0m2ddpp.js +0 -0
  181. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/material-theme-ocean-CyktbL80.js +0 -0
  182. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/material-theme-palenight-Csfq5Kiy.js +0 -0
  183. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/matlab-D7o27uSR.js +0 -0
  184. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/mdc-DUICxH0z.js +0 -0
  185. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/mdx-Cmh6b_Ma.js +0 -0
  186. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/mermaid-DKYwYmdq.js +0 -0
  187. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/min-dark-CafNBF8u.js +0 -0
  188. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/min-light-CTRr51gU.js +0 -0
  189. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/mipsasm-CKIfxQSi.js +0 -0
  190. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/mojo-1DNp92w6.js +0 -0
  191. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/monokai-D4h5O-jR.js +0 -0
  192. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/move-Bu9oaDYs.js +0 -0
  193. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/narrat-DRg8JJMk.js +0 -0
  194. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/nextflow-CUEJCptM.js +0 -0
  195. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/nginx-DknmC5AR.js +0 -0
  196. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/night-owl-C39BiMTA.js +0 -0
  197. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/nim-CVrawwO9.js +0 -0
  198. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/nix-BbRYJGeE.js +0 -0
  199. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/nord-Ddv68eIx.js +0 -0
  200. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/nushell-C-sUppwS.js +0 -0
  201. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/objective-c-DXmwc3jG.js +0 -0
  202. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/objective-cpp-CLxacb5B.js +0 -0
  203. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ocaml-C0hk2d4L.js +0 -0
  204. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/one-dark-pro-DVMEJ2y_.js +0 -0
  205. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/one-light-PoHY5YXO.js +0 -0
  206. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/pascal-D93ZcfNL.js +0 -0
  207. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/perl-C0TMdlhV.js +0 -0
  208. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/php-CDn_0X-4.js +0 -0
  209. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/pkl-u5AG7uiY.js +0 -0
  210. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/plastic-3e1v2bzS.js +0 -0
  211. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/plsql-ChMvpjG-.js +0 -0
  212. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/po-BTJTHyun.js +0 -0
  213. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/poimandres-CS3Unz2-.js +0 -0
  214. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/polar-C0HS_06l.js +0 -0
  215. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/postcss-CXtECtnM.js +0 -0
  216. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/powerquery-CEu0bR-o.js +0 -0
  217. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/powershell-Dpen1YoG.js +0 -0
  218. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/prisma-Dd19v3D-.js +0 -0
  219. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/prolog-CbFg5uaA.js +0 -0
  220. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/proto-DyJlTyXw.js +0 -0
  221. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/pug-CGlum2m_.js +0 -0
  222. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/puppet-BMWR74SV.js +0 -0
  223. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/purescript-CklMAg4u.js +0 -0
  224. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/python-B6aJPvgy.js +0 -0
  225. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/qml-3beO22l8.js +0 -0
  226. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/qmldir-C8lEn-DE.js +0 -0
  227. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/qss-IeuSbFQv.js +0 -0
  228. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/r-DiinP2Uv.js +0 -0
  229. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/racket-BqYA7rlc.js +0 -0
  230. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/raku-DXvB9xmW.js +0 -0
  231. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/razor-WgofotgN.js +0 -0
  232. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/red-bN70gL4F.js +0 -0
  233. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/reg-C-SQnVFl.js +0 -0
  234. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/regexp-CDVJQ6XC.js +0 -0
  235. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rel-C3B-1QV4.js +0 -0
  236. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/riscv-BM1_JUlF.js +0 -0
  237. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rose-pine-BHrmToEH.js +0 -0
  238. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rose-pine-dawn-CnK8MTSM.js +0 -0
  239. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rose-pine-moon-NleAzG8P.js +0 -0
  240. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rosmsg-BJDFO7_C.js +0 -0
  241. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rst-B0xPkSld.js +0 -0
  242. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ruby-BvKwtOVI.js +0 -0
  243. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/rust-B1yitclQ.js +0 -0
  244. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/sas-cz2c8ADy.js +0 -0
  245. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/sass-Cj5Yp3dK.js +0 -0
  246. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/scala-C151Ov-r.js +0 -0
  247. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/scheme-C98Dy4si.js +0 -0
  248. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/scss-OYdSNvt2.js +0 -0
  249. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/sdbl-DVxCFoDh.js +0 -0
  250. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/shaderlab-Dg9Lc6iA.js +0 -0
  251. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/shellscript-Yzrsuije.js +0 -0
  252. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/shellsession-BADoaaVG.js +0 -0
  253. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/slack-dark-BthQWCQV.js +0 -0
  254. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/slack-ochin-DqwNpetd.js +0 -0
  255. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/smalltalk-BERRCDM3.js +0 -0
  256. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/snazzy-light-Bw305WKR.js +0 -0
  257. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/solarized-dark-DXbdFlpD.js +0 -0
  258. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/solarized-light-L9t79GZl.js +0 -0
  259. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/solidity-BbcW6ACK.js +0 -0
  260. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/soy-Brmx7dQM.js +0 -0
  261. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/sparql-rVzFXLq3.js +0 -0
  262. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/splunk-BtCnVYZw.js +0 -0
  263. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/sql-BLtJtn59.js +0 -0
  264. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ssh-config-_ykCGR6B.js +0 -0
  265. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/stata-BH5u7GGu.js +0 -0
  266. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/stylus-BEDo0Tqx.js +0 -0
  267. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/svelte-3Dk4HxPD.js +0 -0
  268. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/swift-Dg5xB15N.js +0 -0
  269. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/synthwave-84-CbfX1IO0.js +0 -0
  270. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/system-verilog-CnnmHF94.js +0 -0
  271. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/systemd-4A_iFExJ.js +0 -0
  272. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/talonscript-CkByrt1z.js +0 -0
  273. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/tasl-QIJgUcNo.js +0 -0
  274. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/tcl-dwOrl1Do.js +0 -0
  275. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/templ-W15q3VgB.js +0 -0
  276. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/terraform-BETggiCN.js +0 -0
  277. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/tex-Cppo0RY3.js +0 -0
  278. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/tokyo-night-hegEt444.js +0 -0
  279. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/toml-vGWfd6FD.js +0 -0
  280. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/ts-tags-zn1MmPIZ.js +0 -0
  281. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/tsv-B_m7g4N7.js +0 -0
  282. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/tsx-COt5Ahok.js +0 -0
  283. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/turtle-BsS91CYL.js +0 -0
  284. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/twig-CO9l9SDP.js +0 -0
  285. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/typescript-BPQ3VLAy.js +0 -0
  286. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/typespec-Df68jz8_.js +0 -0
  287. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/typst-DHCkPAjA.js +0 -0
  288. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/v-BcVCzyr7.js +0 -0
  289. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vala-CsfeWuGM.js +0 -0
  290. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vb-D17OF-Vu.js +0 -0
  291. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/verilog-BQ8w6xss.js +0 -0
  292. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vesper-DU1UobuO.js +0 -0
  293. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vhdl-CeAyd5Ju.js +0 -0
  294. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/viml-CJc9bBzg.js +0 -0
  295. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vitesse-black-Bkuqu6BP.js +0 -0
  296. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vitesse-dark-D0r3Knsf.js +0 -0
  297. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vitesse-light-CVO1_9PV.js +0 -0
  298. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vue-CCoi5OLL.js +0 -0
  299. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vue-html-DAAvJJDi.js +0 -0
  300. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vue-vine-_Ih-lPRR.js +0 -0
  301. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/vyper-CDx5xZoG.js +0 -0
  302. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wasm-CG6Dc4jp.js +0 -0
  303. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wasm-MzD3tlZU.js +0 -0
  304. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wenyan-BV7otONQ.js +0 -0
  305. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wgsl-Dx-B1_4e.js +0 -0
  306. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wikitext-BhOHFoWU.js +0 -0
  307. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wit-5i3qLPDT.js +0 -0
  308. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/wolfram-lXgVvXCa.js +0 -0
  309. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/xml-sdJ4AIDG.js +0 -0
  310. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/xsl-CtQFsRM5.js +0 -0
  311. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/yaml-Buea-lGh.js +0 -0
  312. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/zenscript-DVFEvuxE.js +0 -0
  313. {srcly-0.1.30 → srcly-0.1.32}/app/static/assets/zig-VOosw3JB.js +0 -0
  314. {srcly-0.1.30 → srcly-0.1.32}/app/static/vite.svg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: srcly
3
- Version: 0.1.30
3
+ Version: 0.1.32
4
4
  Summary: Interactive codebase treemap and metrics viewer.
5
5
  Requires-Python: >=3.13
6
6
  Requires-Dist: fastapi>=0.121.3
@@ -170,6 +170,33 @@ def _run_headless(argv: list[str]) -> None:
170
170
  )
171
171
  report_parser.add_argument("--refresh", action="store_true", help="Ignore cache when cache support is available.")
172
172
  report_parser.add_argument("--limit", type=int, default=50, help="Maximum ranked findings to emit.")
173
+ report_parser.add_argument(
174
+ "--verbose",
175
+ action="store_true",
176
+ help="Print per-file scan progress to stderr. Reports are quiet by default.",
177
+ )
178
+ report_parser.add_argument(
179
+ "--agent-compact",
180
+ action="store_true",
181
+ help="Expand compact agent artifacts from the default top 10 findings to the top 20.",
182
+ )
183
+ report_parser.add_argument(
184
+ "--focus",
185
+ action="append",
186
+ default=None,
187
+ help="Path prefix to promote in report ranking. May be repeated.",
188
+ )
189
+ report_parser.add_argument(
190
+ "--deprioritize",
191
+ action="append",
192
+ default=None,
193
+ help="Path prefix to lower in report ranking. May be repeated. Defaults include .agents and docs/idea.",
194
+ )
195
+ report_parser.add_argument(
196
+ "--no-default-deprioritize",
197
+ action="store_true",
198
+ help="Disable default report deprioritization for agent docs, vendored, and generated-like paths.",
199
+ )
173
200
  report_parser.add_argument(
174
201
  "--profile",
175
202
  choices=["general", "frontend", "backend", "typescript", "python", "docs"],
@@ -234,6 +261,11 @@ def _run_headless(argv: list[str]) -> None:
234
261
  tree_top=args.tree_top,
235
262
  include_tree=args.include_tree,
236
263
  include_dependencies=args.include_dependencies,
264
+ focus_paths=args.focus,
265
+ deprioritize_paths=_deprioritize_paths(args),
266
+ agent_compact=args.agent_compact,
267
+ verbose=args.verbose,
268
+ output_format=args.format,
237
269
  )
238
270
  print(reporting._json_dumps(payload))
239
271
  else:
@@ -250,10 +282,17 @@ def _run_headless(argv: list[str]) -> None:
250
282
  tree_top=args.tree_top,
251
283
  include_tree=args.include_tree,
252
284
  include_dependencies=args.include_dependencies,
285
+ focus_paths=args.focus,
286
+ deprioritize_paths=_deprioritize_paths(args),
287
+ agent_compact=args.agent_compact,
288
+ verbose=args.verbose,
253
289
  )
254
- print(f"Wrote Srcly report artifacts to {out_dir}")
255
- for path in written.values():
256
- print(f"- {path}")
290
+ if args.verbose:
291
+ print(f"Wrote Srcly report artifacts to {out_dir}")
292
+ for path in written.values():
293
+ print(f"- {path}")
294
+ else:
295
+ print(_format_quiet_report_summary(out_dir, written))
257
296
  if args.fail_on != "none":
258
297
  if args.stdout:
259
298
  _enforce_fail_on_payload(payload["findings"], args.fail_on)
@@ -295,6 +334,18 @@ def _profile_from_metrics(metrics: list[str] | None) -> str:
295
334
  return "_custom"
296
335
 
297
336
 
337
+ def _deprioritize_paths(args) -> tuple[str, ...]:
338
+ if args.no_default_deprioritize:
339
+ return tuple(args.deprioritize or ())
340
+ return tuple(reporting.DEFAULT_DEPRIORITIZED_PATHS) + tuple(args.deprioritize or ())
341
+
342
+
343
+ def _format_quiet_report_summary(out_dir: Path, written: dict[str, Path]) -> str:
344
+ names = ", ".join(path.name for path in written.values())
345
+ read_first = out_dir / "report.md"
346
+ return f"Wrote {len(written)} Srcly artifacts to {out_dir}: {names}\nRead first: {read_first}"
347
+
348
+
298
349
  def _enforce_fail_on(findings_path: Path, fail_on: str) -> None:
299
350
  import json
300
351
 
@@ -481,6 +481,8 @@ def _run_file_analyses_with_hard_timeouts(
481
481
  files_to_scan: list[str],
482
482
  timeout_seconds: float,
483
483
  max_workers: int,
484
+ *,
485
+ verbose: bool = True,
484
486
  ) -> list:
485
487
  """
486
488
  Analyze files with a *hard* per-file timeout by running each file in its own
@@ -508,7 +510,8 @@ def _run_file_analyses_with_hard_timeouts(
508
510
 
509
511
  # Log every file *before* it is processed so we can identify the
510
512
  # last-started file if analysis hangs or crashes.
511
- print(f"➡️ [{next_index}/{total_count}] Starting analysis: {file_path}", file=sys.stderr, flush=True)
513
+ if verbose:
514
+ print(f"➡️ [{next_index}/{total_count}] Starting analysis: {file_path}", file=sys.stderr, flush=True)
512
515
 
513
516
  recv_conn, send_conn = ctx.Pipe(duplex=False)
514
517
  proc = ctx.Process(
@@ -540,11 +543,12 @@ def _run_file_analyses_with_hard_timeouts(
540
543
  # Either finished, or timed out.
541
544
  if proc.is_alive() and elapsed > timeout_seconds:
542
545
  completed_count += 1
543
- print(
544
- f"❌ [{completed_count}/{total_count}] Timeout analyzing {file_path} after {elapsed:.2f}s (terminated)",
545
- file=sys.stderr,
546
- flush=True,
547
- )
546
+ if verbose:
547
+ print(
548
+ f"❌ [{completed_count}/{total_count}] Timeout analyzing {file_path} after {elapsed:.2f}s (terminated)",
549
+ file=sys.stderr,
550
+ flush=True,
551
+ )
548
552
  try:
549
553
  proc.terminate()
550
554
  except Exception:
@@ -579,13 +583,14 @@ def _run_file_analyses_with_hard_timeouts(
579
583
  pass
580
584
 
581
585
  if isinstance(result, dict) and "error" in result:
582
- print(
583
- f"❌ [{completed_count}/{total_count}] Error analyzing {file_path}: {result.get('error')}",
584
- file=sys.stderr,
585
- flush=True,
586
- )
586
+ if verbose:
587
+ print(
588
+ f"❌ [{completed_count}/{total_count}] Error analyzing {file_path}: {result.get('error')}",
589
+ file=sys.stderr,
590
+ flush=True,
591
+ )
587
592
  else:
588
- if _should_log_file_progress(completed_count, total_count):
593
+ if verbose and _should_log_file_progress(completed_count, total_count):
589
594
  print(f"✅ [{completed_count}/{total_count}] Analyzed {file_path}", file=sys.stderr, flush=True)
590
595
  results.append(result)
591
596
 
@@ -598,8 +603,9 @@ def _run_file_analyses_with_hard_timeouts(
598
603
  return results
599
604
 
600
605
 
601
- def scan_codebase(root_path: Path) -> Node:
602
- print(f"🔍 Scanning: {root_path}", file=sys.stderr, flush=True)
606
+ def scan_codebase(root_path: Path, *, verbose: bool = True) -> Node:
607
+ if verbose:
608
+ print(f"🔍 Scanning: {root_path}", file=sys.stderr, flush=True)
603
609
 
604
610
  # Load .gitignore spec (repo-wide, with nested .gitignore support)
605
611
  ignore_root, gitignore_spec = _load_gitignore_spec(root_path)
@@ -641,16 +647,18 @@ def scan_codebase(root_path: Path) -> Node:
641
647
  if current_ignored_count > 0:
642
648
  ignored_counts[str(root_dir_path)] = current_ignored_count
643
649
 
644
- print(
645
- f"📂 Analyzing {len(files_to_scan)} source files... (workers={MAX_ANALYSIS_WORKERS}, timeout={PER_FILE_ANALYSIS_TIMEOUT_SECONDS}s)",
646
- file=sys.stderr,
647
- flush=True,
648
- )
650
+ if verbose:
651
+ print(
652
+ f"📂 Analyzing {len(files_to_scan)} source files... (workers={MAX_ANALYSIS_WORKERS}, timeout={PER_FILE_ANALYSIS_TIMEOUT_SECONDS}s)",
653
+ file=sys.stderr,
654
+ flush=True,
655
+ )
649
656
 
650
657
  analysis_results = _run_file_analyses_with_hard_timeouts(
651
658
  files_to_scan=files_to_scan,
652
659
  timeout_seconds=PER_FILE_ANALYSIS_TIMEOUT_SECONDS,
653
660
  max_workers=MAX_ANALYSIS_WORKERS,
661
+ verbose=verbose,
654
662
  )
655
663
 
656
664
  tree_root = create_node("root", "folder", str(root_path))
@@ -16,6 +16,8 @@ ARTIFACT_VERSION = 1
16
16
  ProfileName = Literal["general", "frontend", "backend", "typescript", "python", "docs"]
17
17
  OutputFormat = Literal["markdown", "json", "both"]
18
18
 
19
+ DEFAULT_DEPRIORITIZED_PATHS = (".agents/", "docs/idea/", "vendor/", "vendors/", "node_modules/")
20
+
19
21
 
20
22
  @dataclass(frozen=True)
21
23
  class MetricDefinition:
@@ -114,8 +116,8 @@ PROFILE_WEIGHTS: dict[str, dict[str, float]] = {
114
116
  }
115
117
 
116
118
 
117
- def scan_tree(root_path: Path) -> Node:
118
- return analysis.scan_codebase(root_path)
119
+ def scan_tree(root_path: Path, *, verbose: bool = True) -> Node:
120
+ return analysis.scan_codebase(root_path, verbose=verbose)
119
121
 
120
122
 
121
123
  def write_scan(root_path: Path, out_path: Path, *, refresh: bool = False) -> Path:
@@ -139,22 +141,31 @@ def build_report_payload(
139
141
  tree_top: int = 6,
140
142
  include_tree: bool = False,
141
143
  include_dependencies: bool = False,
144
+ focus_paths: Iterable[str] | None = None,
145
+ deprioritize_paths: Iterable[str] | None = DEFAULT_DEPRIORITIZED_PATHS,
146
+ agent_compact: bool = False,
147
+ verbose: bool = True,
148
+ output_format: OutputFormat = "both",
142
149
  ) -> dict[str, Any]:
143
150
  del refresh # Cache support is currently a no-op in app.services.cache.
144
151
  if profile not in PROFILE_WEIGHTS:
145
152
  raise ValueError(f"Unknown profile: {profile}")
146
153
 
147
- tree = scan_tree(root_path)
148
- ranked = rank_nodes(tree, profile=profile)
154
+ tree = scan_tree(root_path, verbose=verbose)
155
+ ranked = rank_nodes(tree, profile=profile, root_path=root_path, focus_paths=focus_paths, deprioritize_paths=deprioritize_paths)
149
156
  findings = build_findings(ranked, limit=limit)
150
157
  summary_tree = summarize_tree(tree, ranked, root_path=root_path, max_depth=tree_depth, top_children=tree_top)
151
158
  manifest = build_manifest(root_path=root_path, profile=profile)
152
159
  metrics_schema = build_metrics_schema()
160
+ top_findings_limit = min(limit, 20 if agent_compact else 10)
161
+ top_findings = {"findings": findings[:top_findings_limit]}
162
+ action_plan_markdown = render_action_plan(findings=findings, profile=profile)
153
163
  payload = {
154
164
  "manifest": manifest,
155
165
  "tree_summary": summary_tree,
156
166
  "hotspots": {"rankings": [r for r in ranked[:limit]]},
157
167
  "findings": {"findings": findings},
168
+ "findings_top": top_findings,
158
169
  "metrics_schema": metrics_schema,
159
170
  "report_markdown": render_markdown_report(
160
171
  manifest=manifest,
@@ -162,13 +173,22 @@ def build_report_payload(
162
173
  ranked=ranked[:limit],
163
174
  summary_tree=summary_tree,
164
175
  profile=profile,
176
+ focus_paths=focus_paths,
177
+ deprioritize_paths=deprioritize_paths,
165
178
  ),
179
+ "action_plan_markdown": action_plan_markdown,
166
180
  "agent_skill_markdown": render_agent_skill(),
167
181
  }
168
182
  if include_tree:
169
183
  payload["tree"] = _node_to_json(tree)
170
184
  if include_dependencies:
171
185
  payload["dependencies"] = build_dependencies(root_path)
186
+ payload["manifest"] = enrich_manifest_with_artifacts(
187
+ payload,
188
+ output_format=output_format,
189
+ include_tree=include_tree,
190
+ include_dependencies=include_dependencies,
191
+ )
172
192
  return payload
173
193
 
174
194
 
@@ -184,6 +204,10 @@ def write_report(
184
204
  tree_top: int = 6,
185
205
  include_tree: bool = False,
186
206
  include_dependencies: bool = False,
207
+ focus_paths: Iterable[str] | None = None,
208
+ deprioritize_paths: Iterable[str] | None = DEFAULT_DEPRIORITIZED_PATHS,
209
+ agent_compact: bool = False,
210
+ verbose: bool = True,
187
211
  ) -> dict[str, Path]:
188
212
  payload = build_report_payload(
189
213
  root_path,
@@ -194,6 +218,11 @@ def write_report(
194
218
  tree_top=tree_top,
195
219
  include_tree=include_tree,
196
220
  include_dependencies=include_dependencies,
221
+ focus_paths=focus_paths,
222
+ deprioritize_paths=deprioritize_paths,
223
+ agent_compact=agent_compact,
224
+ verbose=verbose,
225
+ output_format=output_format,
197
226
  )
198
227
 
199
228
  out_dir.mkdir(parents=True, exist_ok=True)
@@ -204,6 +233,7 @@ def write_report(
204
233
  written["tree_summary"] = _write_json(out_dir / "tree.summary.json", payload["tree_summary"])
205
234
  written["hotspots"] = _write_json(out_dir / "hotspots.json", payload["hotspots"])
206
235
  written["findings"] = _write_json(out_dir / "findings.json", payload["findings"])
236
+ written["findings_top"] = _write_json(out_dir / "findings.top.json", payload["findings_top"])
207
237
  written["metrics_schema"] = _write_json(out_dir / "metrics.schema.json", payload["metrics_schema"])
208
238
  if include_tree:
209
239
  written["tree"] = _write_json(out_dir / "tree.json", payload["tree"])
@@ -212,15 +242,25 @@ def write_report(
212
242
 
213
243
  if output_format in ("markdown", "both"):
214
244
  written["report"] = _write_text(out_dir / "report.md", payload["report_markdown"])
245
+ written["action_plan"] = _write_text(out_dir / "action-plan.md", payload["action_plan_markdown"])
215
246
  written["agent_skill"] = _write_text(out_dir / "agent-skill.md", payload["agent_skill_markdown"])
216
247
 
217
248
  return written
218
249
 
219
250
 
220
- def rank_nodes(root: Node, *, profile: str = "general") -> list[dict[str, Any]]:
251
+ def rank_nodes(
252
+ root: Node,
253
+ *,
254
+ profile: str = "general",
255
+ root_path: Path | None = None,
256
+ focus_paths: Iterable[str] | None = None,
257
+ deprioritize_paths: Iterable[str] | None = DEFAULT_DEPRIORITIZED_PATHS,
258
+ ) -> list[dict[str, Any]]:
221
259
  weights = PROFILE_WEIGHTS.get(profile, PROFILE_WEIGHTS["general"])
222
260
  nodes = [node for node in iter_nodes(root) if node.type != "folder" and node.metrics is not None]
223
261
  maxima = _metric_maxima(nodes, weights.keys())
262
+ focus_prefixes = tuple(_normalize_path_filter(path) for path in (focus_paths or ()) if path)
263
+ deprioritize_prefixes = tuple(_normalize_path_filter(path) for path in (deprioritize_paths or ()) if path)
224
264
  ranked: list[dict[str, Any]] = []
225
265
 
226
266
  for node in nodes:
@@ -248,6 +288,9 @@ def rank_nodes(root: Node, *, profile: str = "general") -> list[dict[str, Any]]:
248
288
  continue
249
289
 
250
290
  score = weighted_sum / weight_sum
291
+ display_path = _display_path(node.path, root_path) if root_path is not None else node.path
292
+ path_priority = _path_priority(display_path, focus_prefixes=focus_prefixes, deprioritize_prefixes=deprioritize_prefixes)
293
+ adjusted_score = max(0.0, min(1.0, score * path_priority["multiplier"]))
251
294
  ranked.append(
252
295
  {
253
296
  "path": node.path,
@@ -255,7 +298,9 @@ def rank_nodes(root: Node, *, profile: str = "general") -> list[dict[str, Any]]:
255
298
  "node_type": node.type,
256
299
  "start_line": node.start_line,
257
300
  "end_line": node.end_line,
258
- "score": round(score, 4),
301
+ "score": round(adjusted_score, 4),
302
+ "raw_score": round(score, 4),
303
+ "path_priority": path_priority["label"],
259
304
  "drivers": sorted(drivers, key=lambda d: d["normalized"] * d["weight"], reverse=True)[:5],
260
305
  "metrics": _metrics_subset(node.metrics, weights.keys()),
261
306
  "reason": _reason_for_node(node),
@@ -294,9 +339,11 @@ def build_findings(ranked: list[dict[str, Any]], *, limit: int = 50) -> list[dic
294
339
  "start_line": item["start_line"],
295
340
  "end_line": item["end_line"],
296
341
  "score": item["score"],
342
+ "raw_score": item.get("raw_score", item["score"]),
343
+ "path_priority": item.get("path_priority", "neutral"),
297
344
  "title": title,
298
345
  "evidence": metrics,
299
- "suggested_action": _suggested_action(category),
346
+ "suggested_action": _suggested_action(category, item),
300
347
  "agent_prompt": _agent_prompt(category),
301
348
  }
302
349
  )
@@ -357,6 +404,8 @@ def render_markdown_report(
357
404
  ranked: list[dict[str, Any]],
358
405
  summary_tree: dict[str, Any],
359
406
  profile: str,
407
+ focus_paths: Iterable[str] | None = None,
408
+ deprioritize_paths: Iterable[str] | None = DEFAULT_DEPRIORITIZED_PATHS,
360
409
  ) -> str:
361
410
  high_count = sum(1 for finding in findings if finding["priority"] == "high")
362
411
  medium_count = sum(1 for finding in findings if finding["priority"] == "medium")
@@ -369,18 +418,22 @@ def render_markdown_report(
369
418
  f"- Profile: `{profile}`",
370
419
  f"- Ranked hotspots: {len(ranked)}",
371
420
  f"- Findings: {len(findings)} total, {high_count} high, {medium_count} medium.",
421
+ f"- Focus paths: `{', '.join(focus_paths or []) or 'none'}`",
422
+ f"- Deprioritized paths: `{', '.join(deprioritize_paths or []) or 'none'}`",
423
+ "",
424
+ "Read first: `report.md`, then `findings.top.json`, then `action-plan.md`. Load full JSON artifacts only when you need detail beyond the top findings.",
372
425
  "",
373
426
  "## Top Targets",
374
427
  "",
375
- "| Rank | Priority | Path | Why | Suggested next action |",
376
- "| --- | --- | --- | --- | --- |",
428
+ "| Rank | Priority | Path priority | Path | Why | Suggested next action |",
429
+ "| --- | --- | --- | --- | --- | --- |",
377
430
  ]
378
431
 
379
432
  for finding in findings[:10]:
380
433
  location = _format_location(finding)
381
434
  evidence = ", ".join(f"{key}={value}" for key, value in finding["evidence"].items() if value) or "metric signal"
382
435
  lines.append(
383
- f"| {finding['id']} | {finding['priority']} | `{location}` | {finding['title']} ({evidence}) | {finding['suggested_action']} |"
436
+ f"| {finding['id']} | {finding['priority']} | {finding.get('path_priority', 'neutral')} | `{location}` | {finding['title']} ({evidence}) | {finding['suggested_action']} |"
384
437
  )
385
438
 
386
439
  lines.extend(
@@ -416,6 +469,7 @@ Use this skill when asked to review, prioritize, or improve a codebase using Src
416
469
  4. For each selected finding, inspect the source file and nearby tests before proposing or making edits.
417
470
  5. Use `.srcly/tree.summary.json` to understand whether a target is an isolated hotspot or part of a broader subsystem.
418
471
  6. Use `uvx srcly scan . --out .srcly/tree.json` or `uvx srcly report . --include-tree` only when the compact summary is insufficient.
472
+ 7. Add `--verbose` to `uvx srcly report` only when per-file scan progress is useful; reports are quiet by default.
419
473
 
420
474
  ## Interpretation Rules
421
475
 
@@ -437,6 +491,33 @@ When reporting back, include:
437
491
  """
438
492
 
439
493
 
494
+ def render_action_plan(*, findings: list[dict[str, Any]], profile: str) -> str:
495
+ lines = [
496
+ "# Srcly Action Plan",
497
+ "",
498
+ f"Profile: `{profile}`",
499
+ "",
500
+ "## Suggested Work Queue",
501
+ "",
502
+ ]
503
+ for index, finding in enumerate(findings[:5], start=1):
504
+ location = _format_location(finding)
505
+ evidence = ", ".join(f"{key}={value}" for key, value in finding["evidence"].items() if value) or "metric signal"
506
+ lines.extend(
507
+ [
508
+ f"{index}. {finding['title']}",
509
+ f" Evidence: `{location}`; {evidence}; priority={finding['priority']}; path_priority={finding.get('path_priority', 'neutral')}.",
510
+ f" Safe first patch: {finding['suggested_action']}",
511
+ f" Verify: inspect nearby tests first, then run the narrowest type-check or test command for the touched package.",
512
+ "",
513
+ ]
514
+ )
515
+ if not findings:
516
+ lines.append("No findings were generated for this scan.")
517
+ lines.append("")
518
+ return "\n".join(lines)
519
+
520
+
440
521
  def render_tree_lines(summary_tree: dict[str, Any], *, indent: int = 0) -> list[str]:
441
522
  prefix = " " * indent
442
523
  name = summary_tree.get("path") or summary_tree.get("name") or "<unknown>"
@@ -465,6 +546,51 @@ def build_manifest(*, root_path: Path, profile: str) -> dict[str, Any]:
465
546
  }
466
547
 
467
548
 
549
+ def enrich_manifest_with_artifacts(
550
+ payload: dict[str, Any],
551
+ *,
552
+ output_format: OutputFormat,
553
+ include_tree: bool,
554
+ include_dependencies: bool,
555
+ ) -> dict[str, Any]:
556
+ manifest = dict(payload["manifest"])
557
+ artifact_specs: list[tuple[str, str, Any, int, str]] = []
558
+ if output_format in ("json", "both"):
559
+ artifact_specs.extend(
560
+ [
561
+ ("manifest", "manifest.json", manifest, 1, "full"),
562
+ ("tree_summary", "tree.summary.json", payload["tree_summary"], 4, "full"),
563
+ ("findings_top", "findings.top.json", payload["findings_top"], 2, "full"),
564
+ ("findings", "findings.json", payload["findings"], 5, "top_n"),
565
+ ("hotspots", "hotspots.json", payload["hotspots"], 6, "top_n"),
566
+ ("metrics_schema", "metrics.schema.json", payload["metrics_schema"], 7, "reference"),
567
+ ]
568
+ )
569
+ if include_tree:
570
+ artifact_specs.append(("tree", "tree.json", payload["tree"], 9, "avoid_full_load"))
571
+ if include_dependencies:
572
+ artifact_specs.append(("dependencies", "dependencies.json", payload["dependencies"], 8, "top_n"))
573
+ if output_format in ("markdown", "both"):
574
+ artifact_specs.extend(
575
+ [
576
+ ("report", "report.md", payload["report_markdown"], 1, "full"),
577
+ ("action_plan", "action-plan.md", payload["action_plan_markdown"], 3, "full"),
578
+ ("agent_skill", "agent-skill.md", payload["agent_skill_markdown"], 10, "reference"),
579
+ ]
580
+ )
581
+ manifest["artifacts"] = [
582
+ {
583
+ "name": name,
584
+ "path": path,
585
+ "bytes": len(_json_dumps(content).encode("utf-8")) if not isinstance(content, str) else len(content.encode("utf-8")),
586
+ "read_order": read_order,
587
+ "agent_load": agent_load,
588
+ }
589
+ for name, path, content, read_order, agent_load in sorted(artifact_specs, key=lambda item: (item[3], item[1]))
590
+ ]
591
+ return manifest
592
+
593
+
468
594
  def build_metrics_schema() -> dict[str, Any]:
469
595
  return {
470
596
  "artifact_version": ARTIFACT_VERSION,
@@ -572,9 +698,16 @@ def _title_for_category(category: str, item: dict[str, Any]) -> str:
572
698
  return labels.get(category, "Code quality hotspot") + f" in {item['name']}"
573
699
 
574
700
 
575
- def _suggested_action(category: str) -> str:
701
+ def _suggested_action(category: str, item: dict[str, Any] | None = None) -> str:
702
+ path = str((item or {}).get("path", ""))
703
+ is_tsx = path.endswith(".tsx") or "::" in path and ".tsx" in path
576
704
  actions = {
577
- "tsx": "Inspect rendering branches, state ownership, and extraction points; add focused UI tests before changing behavior.",
705
+ "tsx": (
706
+ "Look first for render-only child components, modal/dialog subtrees, action hooks, and derived selectors to extract; "
707
+ "verify with type-check and targeted UI coverage."
708
+ if is_tsx
709
+ else "Inspect rendering branches, state ownership, and extraction points; add focused UI tests before changing behavior."
710
+ ),
578
711
  "typing": "Review whether `any` or ignore directives can be replaced with precise types.",
579
712
  "coupling": "Inspect dependency boundaries and look for imports that can be inverted, localized, or simplified.",
580
713
  "docs": "Check whether large embedded data URLs should move to external assets.",
@@ -620,6 +753,25 @@ def _display_path(path: str, root_path: Path) -> str:
620
753
  return path
621
754
 
622
755
 
756
+ def _normalize_path_filter(path: str) -> str:
757
+ normalized = path.strip().replace("\\", "/").strip("/")
758
+ return f"{normalized}/" if normalized and not Path(normalized).suffix else normalized
759
+
760
+
761
+ def _path_priority(
762
+ display_path: str,
763
+ *,
764
+ focus_prefixes: tuple[str, ...],
765
+ deprioritize_prefixes: tuple[str, ...],
766
+ ) -> dict[str, Any]:
767
+ normalized = display_path.replace("\\", "/").lstrip("/")
768
+ if focus_prefixes and any(normalized == prefix.rstrip("/") or normalized.startswith(prefix) for prefix in focus_prefixes):
769
+ return {"label": "focused", "multiplier": 1.25}
770
+ if any(normalized == prefix.rstrip("/") or normalized.startswith(prefix) for prefix in deprioritize_prefixes):
771
+ return {"label": "deprioritized", "multiplier": 0.55}
772
+ return {"label": "neutral", "multiplier": 1.0}
773
+
774
+
623
775
  def _node_identity(path: str, start_line: int, end_line: int, node_type: str) -> str:
624
776
  return f"{path}|{node_type}|{start_line}|{end_line}"
625
777