dotscope 1.2.0__tar.gz → 1.2.2__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 (424) hide show
  1. {dotscope-1.2.0 → dotscope-1.2.2}/.github/workflows/python-publish.yml +1 -1
  2. dotscope-1.2.2/CLAUDE.md +10 -0
  3. dotscope-1.2.2/PKG-INFO +83 -0
  4. dotscope-1.2.2/README.md +46 -0
  5. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/__init__.py +1 -1
  6. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/cli.py +7 -1
  7. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/constants.py +26 -2
  8. {dotscope-1.2.0 → dotscope-1.2.2}/dotscope/formatter.py +13 -1
  9. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/engine.py +2 -2
  10. dotscope-1.2.2/dotscope/ignore.py +59 -0
  11. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/ingest.py +51 -3
  12. {dotscope-1.2.0 → dotscope-1.2.2}/dotscope/mcp_server.py +121 -1
  13. {dotscope-1.2.0 → dotscope-1.2.2}/dotscope/models/core.py +4 -0
  14. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/graph_builder.py +13 -2
  15. {dotscope-1.2.0 → dotscope-1.2.2}/dotscope/scanner.py +18 -1
  16. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/retriever.py +21 -3
  17. {dotscope-1.2.0 → dotscope-1.2.2}/dotscope/search/synthesizer.py +17 -7
  18. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/claude_hooks.py +47 -0
  19. dotscope-1.2.2/dotscope/swarm/__init__.py +13 -0
  20. dotscope-1.2.2/dotscope/swarm/merge.py +161 -0
  21. dotscope-1.2.2/dotscope/swarm/partition.py +236 -0
  22. dotscope-1.2.2/dotscope/swarm/trace.py +251 -0
  23. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/pyproject.toml +1 -1
  24. dotscope-1.2.2/tests/test_ignore.py +64 -0
  25. dotscope-1.2.2/tests/test_swarm.py +300 -0
  26. dotscope-1.2.0/.claude/settings.local.json +0 -35
  27. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.claude/hooks/pre-commit-check.sh +0 -41
  28. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.claude/settings.json +0 -15
  29. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.claude/settings.local.json +0 -52
  30. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/.git +0 -1
  31. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/README.md +0 -90
  32. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/formatter.py +0 -157
  33. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/mcp_server.py +0 -1457
  34. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/models/core.py +0 -328
  35. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/scanner.py +0 -246
  36. dotscope-1.2.0/.claude/worktrees/hopeful-chatelet/dotscope/search/synthesizer.py +0 -292
  37. dotscope-1.2.0/.gitignore +0 -10
  38. dotscope-1.2.0/.mcp.json +0 -9
  39. dotscope-1.2.0/.scopes +0 -28
  40. dotscope-1.2.0/AGENT_INSTRUCTIONS.md +0 -129
  41. dotscope-1.2.0/LICENSE +0 -21
  42. dotscope-1.2.0/PKG-INFO +0 -127
  43. dotscope-1.2.0/README.md +0 -90
  44. dotscope-1.2.0/docs/architecture.md +0 -72
  45. dotscope-1.2.0/docs/cli-reference.md +0 -67
  46. dotscope-1.2.0/docs/how-it-works.md +0 -146
  47. dotscope-1.2.0/docs/mcp-setup.md +0 -255
  48. dotscope-1.2.0/docs/scope-file.md +0 -285
  49. dotscope-1.2.0/dotscope/.scope +0 -82
  50. dotscope-1.2.0/dotscope/__init__.py +0 -3
  51. dotscope-1.2.0/dotscope/absorber.py +0 -390
  52. dotscope-1.2.0/dotscope/assertions.py +0 -127
  53. dotscope-1.2.0/dotscope/ast_analyzer.py +0 -2
  54. dotscope-1.2.0/dotscope/backtest.py +0 -2
  55. dotscope-1.2.0/dotscope/bench.py +0 -141
  56. dotscope-1.2.0/dotscope/budget.py +0 -3
  57. dotscope-1.2.0/dotscope/cache.py +0 -2
  58. dotscope-1.2.0/dotscope/check/__init__.py +0 -1
  59. dotscope-1.2.0/dotscope/check/acknowledge.py +0 -2
  60. dotscope-1.2.0/dotscope/check/checker.py +0 -3
  61. dotscope-1.2.0/dotscope/check/checks/__init__.py +0 -1
  62. dotscope-1.2.0/dotscope/check/checks/antipattern.py +0 -2
  63. dotscope-1.2.0/dotscope/check/checks/boundary.py +0 -2
  64. dotscope-1.2.0/dotscope/check/checks/contracts.py +0 -3
  65. dotscope-1.2.0/dotscope/check/checks/direction.py +0 -2
  66. dotscope-1.2.0/dotscope/check/checks/intent.py +0 -2
  67. dotscope-1.2.0/dotscope/check/checks/stability.py +0 -2
  68. dotscope-1.2.0/dotscope/check/constraints.py +0 -2
  69. dotscope-1.2.0/dotscope/check/models.py +0 -15
  70. dotscope-1.2.0/dotscope/cli.py +0 -1561
  71. dotscope-1.2.0/dotscope/composer.py +0 -229
  72. dotscope-1.2.0/dotscope/constants.py +0 -45
  73. dotscope-1.2.0/dotscope/context.py +0 -60
  74. dotscope-1.2.0/dotscope/counterfactual.py +0 -180
  75. dotscope-1.2.0/dotscope/debug.py +0 -220
  76. dotscope-1.2.0/dotscope/discovery.py +0 -138
  77. dotscope-1.2.0/dotscope/eval/.scope +0 -27
  78. dotscope-1.2.0/dotscope/eval/__init__.py +0 -18
  79. dotscope-1.2.0/dotscope/eval/bootstrap.py +0 -231
  80. dotscope-1.2.0/dotscope/eval/compare.py +0 -147
  81. dotscope-1.2.0/dotscope/eval/corpus.py +0 -214
  82. dotscope-1.2.0/dotscope/eval/harness.py +0 -310
  83. dotscope-1.2.0/dotscope/eval/replay.py +0 -356
  84. dotscope-1.2.0/dotscope/generate/.scope +0 -24
  85. dotscope-1.2.0/dotscope/generate/__init__.py +0 -1
  86. dotscope-1.2.0/dotscope/generate/atlas.py +0 -341
  87. dotscope-1.2.0/dotscope/generate/contracts.py +0 -296
  88. dotscope-1.2.0/dotscope/generate/engine.py +0 -189
  89. dotscope-1.2.0/dotscope/generate/models.py +0 -27
  90. dotscope-1.2.0/dotscope/generate/network.py +0 -284
  91. dotscope-1.2.0/dotscope/graph.py +0 -3
  92. dotscope-1.2.0/dotscope/health.py +0 -272
  93. dotscope-1.2.0/dotscope/help.py +0 -218
  94. dotscope-1.2.0/dotscope/history.py +0 -6
  95. dotscope-1.2.0/dotscope/hooks.py +0 -2
  96. dotscope-1.2.0/dotscope/ingest.py +0 -972
  97. dotscope-1.2.0/dotscope/intent.py +0 -614
  98. dotscope-1.2.0/dotscope/lessons.py +0 -223
  99. dotscope-1.2.0/dotscope/matcher.py +0 -104
  100. dotscope-1.2.0/dotscope/merge/.scope +0 -34
  101. dotscope-1.2.0/dotscope/merge/__init__.py +0 -1
  102. dotscope-1.2.0/dotscope/merge/classifier.py +0 -83
  103. dotscope-1.2.0/dotscope/merge/composer.py +0 -210
  104. dotscope-1.2.0/dotscope/merge/differ.py +0 -178
  105. dotscope-1.2.0/dotscope/merge/driver.py +0 -147
  106. dotscope-1.2.0/dotscope/merge/imports.py +0 -114
  107. dotscope-1.2.0/dotscope/merge/models.py +0 -62
  108. dotscope-1.2.0/dotscope/merge/swarm.py +0 -336
  109. dotscope-1.2.0/dotscope/models/.scope +0 -45
  110. dotscope-1.2.0/dotscope/models/__init__.py +0 -8
  111. dotscope-1.2.0/dotscope/models/eval.py +0 -96
  112. dotscope-1.2.0/dotscope/models/history.py +0 -73
  113. dotscope-1.2.0/dotscope/models/intent.py +0 -214
  114. dotscope-1.2.0/dotscope/models/passes.py +0 -58
  115. dotscope-1.2.0/dotscope/models/state.py +0 -251
  116. dotscope-1.2.0/dotscope/models.py +0 -9
  117. dotscope-1.2.0/dotscope/near_miss.py +0 -3
  118. dotscope-1.2.0/dotscope/onboarding.py +0 -2
  119. dotscope-1.2.0/dotscope/parser.py +0 -395
  120. dotscope-1.2.0/dotscope/passes/.scope +0 -105
  121. dotscope-1.2.0/dotscope/passes/__init__.py +0 -1
  122. dotscope-1.2.0/dotscope/passes/ast_analyzer.py +0 -757
  123. dotscope-1.2.0/dotscope/passes/backtest.py +0 -198
  124. dotscope-1.2.0/dotscope/passes/budget_allocator.py +0 -343
  125. dotscope-1.2.0/dotscope/passes/convention_compliance.py +0 -40
  126. dotscope-1.2.0/dotscope/passes/convention_discovery.py +0 -345
  127. dotscope-1.2.0/dotscope/passes/convention_parser.py +0 -235
  128. dotscope-1.2.0/dotscope/passes/graph_builder.py +0 -437
  129. dotscope-1.2.0/dotscope/passes/hint_generator.py +0 -128
  130. dotscope-1.2.0/dotscope/passes/history_miner.py +0 -336
  131. dotscope-1.2.0/dotscope/passes/incremental.py +0 -221
  132. dotscope-1.2.0/dotscope/passes/lang/__init__.py +0 -38
  133. dotscope-1.2.0/dotscope/passes/lang/_base.py +0 -20
  134. dotscope-1.2.0/dotscope/passes/lang/_treesitter.py +0 -93
  135. dotscope-1.2.0/dotscope/passes/lang/go.py +0 -334
  136. dotscope-1.2.0/dotscope/passes/lang/javascript.py +0 -431
  137. dotscope-1.2.0/dotscope/passes/lazy.py +0 -177
  138. dotscope-1.2.0/dotscope/passes/preflight.py +0 -117
  139. dotscope-1.2.0/dotscope/passes/semantic_diff.py +0 -160
  140. dotscope-1.2.0/dotscope/passes/sentinel/__init__.py +0 -1
  141. dotscope-1.2.0/dotscope/passes/sentinel/acknowledge.py +0 -222
  142. dotscope-1.2.0/dotscope/passes/sentinel/checker.py +0 -428
  143. dotscope-1.2.0/dotscope/passes/sentinel/checks/__init__.py +0 -1
  144. dotscope-1.2.0/dotscope/passes/sentinel/checks/antipattern.py +0 -84
  145. dotscope-1.2.0/dotscope/passes/sentinel/checks/boundary.py +0 -46
  146. dotscope-1.2.0/dotscope/passes/sentinel/checks/contracts.py +0 -148
  147. dotscope-1.2.0/dotscope/passes/sentinel/checks/convention.py +0 -54
  148. dotscope-1.2.0/dotscope/passes/sentinel/checks/direction.py +0 -71
  149. dotscope-1.2.0/dotscope/passes/sentinel/checks/intent.py +0 -207
  150. dotscope-1.2.0/dotscope/passes/sentinel/checks/network.py +0 -91
  151. dotscope-1.2.0/dotscope/passes/sentinel/checks/spatial.py +0 -115
  152. dotscope-1.2.0/dotscope/passes/sentinel/checks/stability.py +0 -66
  153. dotscope-1.2.0/dotscope/passes/sentinel/checks/voice.py +0 -108
  154. dotscope-1.2.0/dotscope/passes/sentinel/constraints.py +0 -472
  155. dotscope-1.2.0/dotscope/passes/sentinel/line_filter.py +0 -88
  156. dotscope-1.2.0/dotscope/passes/sentinel/models.py +0 -15
  157. dotscope-1.2.0/dotscope/passes/spatial_autofix.py +0 -206
  158. dotscope-1.2.0/dotscope/passes/virtual.py +0 -247
  159. dotscope-1.2.0/dotscope/passes/voice.py +0 -161
  160. dotscope-1.2.0/dotscope/passes/voice_defaults.py +0 -68
  161. dotscope-1.2.0/dotscope/passes/voice_discovery.py +0 -245
  162. dotscope-1.2.0/dotscope/paths.py +0 -83
  163. dotscope-1.2.0/dotscope/progress.py +0 -44
  164. dotscope-1.2.0/dotscope/refresh.py +0 -543
  165. dotscope-1.2.0/dotscope/regression.py +0 -147
  166. dotscope-1.2.0/dotscope/resolver.py +0 -198
  167. dotscope-1.2.0/dotscope/runtime_overlay.py +0 -403
  168. dotscope-1.2.0/dotscope/search/.scope +0 -29
  169. dotscope-1.2.0/dotscope/search/__init__.py +0 -1
  170. dotscope-1.2.0/dotscope/search/chunker.py +0 -343
  171. dotscope-1.2.0/dotscope/search/expander.py +0 -129
  172. dotscope-1.2.0/dotscope/search/flattener.py +0 -187
  173. dotscope-1.2.0/dotscope/search/models.py +0 -70
  174. dotscope-1.2.0/dotscope/search/observation.py +0 -279
  175. dotscope-1.2.0/dotscope/search/reranker.py +0 -85
  176. dotscope-1.2.0/dotscope/search/retriever.py +0 -368
  177. dotscope-1.2.0/dotscope/sessions.py +0 -2
  178. dotscope-1.2.0/dotscope/storage/.scope +0 -64
  179. dotscope-1.2.0/dotscope/storage/__init__.py +0 -1
  180. dotscope-1.2.0/dotscope/storage/cache.py +0 -177
  181. dotscope-1.2.0/dotscope/storage/claude_hooks.py +0 -119
  182. dotscope-1.2.0/dotscope/storage/git_hooks.py +0 -500
  183. dotscope-1.2.0/dotscope/storage/incremental_state.py +0 -124
  184. dotscope-1.2.0/dotscope/storage/mcp_config.py +0 -98
  185. dotscope-1.2.0/dotscope/storage/near_miss.py +0 -183
  186. dotscope-1.2.0/dotscope/storage/onboarding.py +0 -150
  187. dotscope-1.2.0/dotscope/storage/session_manager.py +0 -195
  188. dotscope-1.2.0/dotscope/storage/swarm_state.py +0 -144
  189. dotscope-1.2.0/dotscope/storage/timing.py +0 -84
  190. dotscope-1.2.0/dotscope/textio.py +0 -122
  191. dotscope-1.2.0/dotscope/timing.py +0 -2
  192. dotscope-1.2.0/dotscope/tokens.py +0 -53
  193. dotscope-1.2.0/dotscope/utility.py +0 -123
  194. dotscope-1.2.0/dotscope/virtual.py +0 -3
  195. dotscope-1.2.0/dotscope/visibility.py +0 -687
  196. dotscope-1.2.0/logo.png +0 -0
  197. dotscope-1.2.0/pyproject.toml +0 -45
  198. dotscope-1.2.0/tests/.scope +0 -29
  199. dotscope-1.2.0/tests/__init__.py +0 -0
  200. dotscope-1.2.0/tests/conftest.py +0 -152
  201. dotscope-1.2.0/tests/test_absorber.py +0 -91
  202. dotscope-1.2.0/tests/test_ast_analyzer.py +0 -168
  203. dotscope-1.2.0/tests/test_backtest.py +0 -114
  204. dotscope-1.2.0/tests/test_budget.py +0 -124
  205. dotscope-1.2.0/tests/test_canonical_snippet.py +0 -70
  206. dotscope-1.2.0/tests/test_cli.py +0 -122
  207. dotscope-1.2.0/tests/test_composer.py +0 -125
  208. dotscope-1.2.0/tests/test_context.py +0 -52
  209. dotscope-1.2.0/tests/test_enforcement.py +0 -423
  210. dotscope-1.2.0/tests/test_eval_harness.py +0 -376
  211. dotscope-1.2.0/tests/test_experience.py +0 -237
  212. dotscope-1.2.0/tests/test_graph.py +0 -78
  213. dotscope-1.2.0/tests/test_health.py +0 -142
  214. dotscope-1.2.0/tests/test_history.py +0 -71
  215. dotscope-1.2.0/tests/test_ingest.py +0 -319
  216. dotscope-1.2.0/tests/test_lessons.py +0 -91
  217. dotscope-1.2.0/tests/test_line_filter.py +0 -67
  218. dotscope-1.2.0/tests/test_loop.py +0 -384
  219. dotscope-1.2.0/tests/test_matcher.py +0 -47
  220. dotscope-1.2.0/tests/test_near_miss.py +0 -161
  221. dotscope-1.2.0/tests/test_parser.py +0 -180
  222. dotscope-1.2.0/tests/test_refresh.py +0 -251
  223. dotscope-1.2.0/tests/test_resolver.py +0 -100
  224. dotscope-1.2.0/tests/test_rigor.py +0 -223
  225. dotscope-1.2.0/tests/test_routing.py +0 -207
  226. dotscope-1.2.0/tests/test_scanner.py +0 -54
  227. dotscope-1.2.0/tests/test_sessions.py +0 -122
  228. dotscope-1.2.0/tests/test_textio.py +0 -85
  229. dotscope-1.2.0/tests/test_treesitter.py +0 -359
  230. dotscope-1.2.0/tests/test_utility.py +0 -48
  231. dotscope-1.2.0/tests/test_virtual.py +0 -95
  232. dotscope-1.2.0/tests/test_visibility.py +0 -417
  233. dotscope-1.2.0/tests/test_voice_check.py +0 -123
  234. dotscope-1.2.0/tests/test_voice_discovery.py +0 -143
  235. dotscope-1.2.0/uv.lock +0 -2375
  236. {dotscope-1.2.0 → dotscope-1.2.2}/.claude/hooks/pre-commit-check.sh +0 -0
  237. {dotscope-1.2.0 → dotscope-1.2.2}/.claude/settings.json +0 -0
  238. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/.gitignore +0 -0
  239. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/.scopes +0 -0
  240. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/AGENT_INSTRUCTIONS.md +0 -0
  241. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/LICENSE +0 -0
  242. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/architecture.md +0 -0
  243. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/cli-reference.md +0 -0
  244. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/how-it-works.md +0 -0
  245. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/mcp-setup.md +0 -0
  246. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/scope-file.md +0 -0
  247. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/.scope +0 -0
  248. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/absorber.py +0 -0
  249. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/assertions.py +0 -0
  250. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/ast_analyzer.py +0 -0
  251. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/backtest.py +0 -0
  252. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/bench.py +0 -0
  253. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/budget.py +0 -0
  254. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/cache.py +0 -0
  255. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/__init__.py +0 -0
  256. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/acknowledge.py +0 -0
  257. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checker.py +0 -0
  258. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/__init__.py +0 -0
  259. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/antipattern.py +0 -0
  260. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/boundary.py +0 -0
  261. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/contracts.py +0 -0
  262. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/direction.py +0 -0
  263. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/intent.py +0 -0
  264. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/stability.py +0 -0
  265. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/constraints.py +0 -0
  266. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/models.py +0 -0
  267. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/composer.py +0 -0
  268. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/context.py +0 -0
  269. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/counterfactual.py +0 -0
  270. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/debug.py +0 -0
  271. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/discovery.py +0 -0
  272. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/.scope +0 -0
  273. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/__init__.py +0 -0
  274. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/bootstrap.py +0 -0
  275. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/compare.py +0 -0
  276. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/corpus.py +0 -0
  277. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/harness.py +0 -0
  278. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/replay.py +0 -0
  279. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/.scope +0 -0
  280. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/__init__.py +0 -0
  281. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/atlas.py +0 -0
  282. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/contracts.py +0 -0
  283. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/models.py +0 -0
  284. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/network.py +0 -0
  285. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/graph.py +0 -0
  286. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/health.py +0 -0
  287. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/help.py +0 -0
  288. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/history.py +0 -0
  289. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/hooks.py +0 -0
  290. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/intent.py +0 -0
  291. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/lessons.py +0 -0
  292. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/matcher.py +0 -0
  293. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/.scope +0 -0
  294. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/__init__.py +0 -0
  295. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/classifier.py +0 -0
  296. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/composer.py +0 -0
  297. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/differ.py +0 -0
  298. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/driver.py +0 -0
  299. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/imports.py +0 -0
  300. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/models.py +0 -0
  301. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/swarm.py +0 -0
  302. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/.scope +0 -0
  303. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/__init__.py +0 -0
  304. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/eval.py +0 -0
  305. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/history.py +0 -0
  306. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/intent.py +0 -0
  307. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/passes.py +0 -0
  308. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/state.py +0 -0
  309. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models.py +0 -0
  310. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/near_miss.py +0 -0
  311. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/onboarding.py +0 -0
  312. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/parser.py +0 -0
  313. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/.scope +0 -0
  314. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/__init__.py +0 -0
  315. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/ast_analyzer.py +0 -0
  316. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/backtest.py +0 -0
  317. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/budget_allocator.py +0 -0
  318. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/convention_compliance.py +0 -0
  319. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/convention_discovery.py +0 -0
  320. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/convention_parser.py +0 -0
  321. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/hint_generator.py +0 -0
  322. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/history_miner.py +0 -0
  323. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/incremental.py +0 -0
  324. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/__init__.py +0 -0
  325. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/_base.py +0 -0
  326. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/_treesitter.py +0 -0
  327. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/go.py +0 -0
  328. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/javascript.py +0 -0
  329. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lazy.py +0 -0
  330. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/preflight.py +0 -0
  331. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/semantic_diff.py +0 -0
  332. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/__init__.py +0 -0
  333. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/acknowledge.py +0 -0
  334. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checker.py +0 -0
  335. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/__init__.py +0 -0
  336. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/antipattern.py +0 -0
  337. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/boundary.py +0 -0
  338. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/contracts.py +0 -0
  339. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/convention.py +0 -0
  340. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/direction.py +0 -0
  341. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/intent.py +0 -0
  342. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/network.py +0 -0
  343. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/spatial.py +0 -0
  344. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/stability.py +0 -0
  345. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/voice.py +0 -0
  346. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/constraints.py +0 -0
  347. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/line_filter.py +0 -0
  348. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/models.py +0 -0
  349. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/spatial_autofix.py +0 -0
  350. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/virtual.py +0 -0
  351. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/voice.py +0 -0
  352. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/voice_defaults.py +0 -0
  353. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/voice_discovery.py +0 -0
  354. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/paths.py +0 -0
  355. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/progress.py +0 -0
  356. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/refresh.py +0 -0
  357. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/regression.py +0 -0
  358. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/resolver.py +0 -0
  359. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/runtime_overlay.py +0 -0
  360. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/.scope +0 -0
  361. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/__init__.py +0 -0
  362. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/chunker.py +0 -0
  363. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/expander.py +0 -0
  364. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/flattener.py +0 -0
  365. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/models.py +0 -0
  366. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/observation.py +0 -0
  367. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/reranker.py +0 -0
  368. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/sessions.py +0 -0
  369. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/.scope +0 -0
  370. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/__init__.py +0 -0
  371. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/cache.py +0 -0
  372. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/git_hooks.py +0 -0
  373. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/incremental_state.py +0 -0
  374. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/mcp_config.py +0 -0
  375. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/near_miss.py +0 -0
  376. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/onboarding.py +0 -0
  377. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/session_manager.py +0 -0
  378. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/swarm_state.py +0 -0
  379. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/timing.py +0 -0
  380. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/textio.py +0 -0
  381. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/timing.py +0 -0
  382. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/tokens.py +0 -0
  383. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/utility.py +0 -0
  384. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/virtual.py +0 -0
  385. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/visibility.py +0 -0
  386. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/logo.png +0 -0
  387. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/.scope +0 -0
  388. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/__init__.py +0 -0
  389. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/conftest.py +0 -0
  390. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_absorber.py +0 -0
  391. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_ast_analyzer.py +0 -0
  392. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_backtest.py +0 -0
  393. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_budget.py +0 -0
  394. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_canonical_snippet.py +0 -0
  395. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_cli.py +0 -0
  396. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_composer.py +0 -0
  397. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_context.py +0 -0
  398. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_enforcement.py +0 -0
  399. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_eval_harness.py +0 -0
  400. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_experience.py +0 -0
  401. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_graph.py +0 -0
  402. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_health.py +0 -0
  403. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_history.py +0 -0
  404. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_ingest.py +0 -0
  405. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_lessons.py +0 -0
  406. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_line_filter.py +0 -0
  407. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_loop.py +0 -0
  408. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_matcher.py +0 -0
  409. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_near_miss.py +0 -0
  410. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_parser.py +0 -0
  411. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_refresh.py +0 -0
  412. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_resolver.py +0 -0
  413. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_rigor.py +0 -0
  414. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_routing.py +0 -0
  415. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_scanner.py +0 -0
  416. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_sessions.py +0 -0
  417. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_textio.py +0 -0
  418. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_treesitter.py +0 -0
  419. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_utility.py +0 -0
  420. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_virtual.py +0 -0
  421. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_visibility.py +0 -0
  422. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_voice_check.py +0 -0
  423. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_voice_discovery.py +0 -0
  424. {dotscope-1.2.0/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/uv.lock +0 -0
@@ -49,7 +49,7 @@ jobs:
49
49
  # Dedicated environments with protections for publishing are strongly recommended.
50
50
  # For more information, see: https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#deployment-protection-rules
51
51
  environment:
52
- name: pypi
52
+ name: dotscope environment
53
53
  # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54
54
  # url: https://pypi.org/p/YOURPROJECT
55
55
  #
@@ -0,0 +1,10 @@
1
+ # CLAUDE.md
2
+
3
+ This repo uses dotscope. Before touching code:
4
+
5
+ 1. `codebase_search("your task description")` — not manual file reads
6
+ 2. `dotscope_check` before every commit
7
+ 3. If check returns HOLDs, fix them before committing
8
+
9
+ dotscope provides: dependency graph, implicit contracts, conventions,
10
+ and file locks. Use its tools instead of guessing.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.4
2
+ Name: dotscope
3
+ Version: 1.2.2
4
+ Summary: Agents see files. You see architecture. dotscope gives agents the architecture.
5
+ Author: Supremum
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Keywords: agents,ai,coding,context,mcp,scope
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Topic :: Software Development :: Libraries
14
+ Requires-Python: >=3.10
15
+ Requires-Dist: tree-sitter-go>=0.23.0
16
+ Requires-Dist: tree-sitter-javascript>=0.23.0
17
+ Requires-Dist: tree-sitter-typescript>=0.23.0
18
+ Requires-Dist: tree-sitter>=0.23.0
19
+ Provides-Extra: all
20
+ Requires-Dist: mcp>=1.2.0; extra == 'all'
21
+ Requires-Dist: numpy; extra == 'all'
22
+ Requires-Dist: sentence-transformers; extra == 'all'
23
+ Requires-Dist: tiktoken; extra == 'all'
24
+ Provides-Extra: dev
25
+ Requires-Dist: pytest; extra == 'dev'
26
+ Requires-Dist: ruff; extra == 'dev'
27
+ Provides-Extra: embeddings
28
+ Requires-Dist: sentence-transformers; extra == 'embeddings'
29
+ Provides-Extra: mcp
30
+ Requires-Dist: mcp>=1.2.0; extra == 'mcp'
31
+ Provides-Extra: search
32
+ Requires-Dist: numpy; extra == 'search'
33
+ Requires-Dist: sentence-transformers; extra == 'search'
34
+ Provides-Extra: tokens
35
+ Requires-Dist: tiktoken; extra == 'tokens'
36
+ Description-Content-Type: text/markdown
37
+
38
+ <p align="center">
39
+ <img src="logo.png" alt="dotscope" width="400">
40
+ </p>
41
+
42
+ Your agent writes code that compiles, passes tests, and breaks production.
43
+
44
+ It changed a backend endpoint without touching the frontend that calls it.
45
+ It put a file in `src/helpers/` instead of next to the module that uses it.
46
+ It ignored the convention every other file follows. Two agents working at
47
+ the same time silently overwrote each other.
48
+
49
+ The agent sees files. You see architecture. dotscope closes that gap.
50
+
51
+ ```
52
+ $ dotscope ingest
53
+
54
+ Analyzing dependency graph...
55
+ Mining git history...
56
+ Discovering conventions...
57
+
58
+ Discoveries:
59
+ - version.py and environment.prod.ts always change together
60
+ - workflow-edit-dialog.component.ts and models.py are tightly coupled
61
+
62
+ Validation (49 commits backtested):
63
+ - Overall recall: 78%
64
+ - Token reduction: 67% (1.3M → 437K avg)
65
+
66
+ Output: 3 .scope files written.
67
+ ```
68
+
69
+ One MCP tool call. The agent gets the relevant code, its dependency
70
+ neighborhood, implicit contracts from git history, convention rules,
71
+ swarm lock status, and action hints. One call, not five.
72
+
73
+ dotscope learns from every commit. Files agents consistently need get
74
+ ranked higher. Conventions that hold get enforced harder. Rules that
75
+ get overridden get quieter. Recall starts at 78% and climbs past 91%.
76
+
77
+ ```
78
+ pip install dotscope && dotscope init
79
+ ```
80
+
81
+ Zero dependencies. Python 3.9+ stdlib only. MIT.
82
+
83
+ [How It Works](docs/how-it-works.md) · [Scope Files](docs/scope-file.md) · [Agent Instructions](AGENT_INSTRUCTIONS.md) · [MIT](LICENSE)
@@ -0,0 +1,46 @@
1
+ <p align="center">
2
+ <img src="logo.png" alt="dotscope" width="400">
3
+ </p>
4
+
5
+ Your agent writes code that compiles, passes tests, and breaks production.
6
+
7
+ It changed a backend endpoint without touching the frontend that calls it.
8
+ It put a file in `src/helpers/` instead of next to the module that uses it.
9
+ It ignored the convention every other file follows. Two agents working at
10
+ the same time silently overwrote each other.
11
+
12
+ The agent sees files. You see architecture. dotscope closes that gap.
13
+
14
+ ```
15
+ $ dotscope ingest
16
+
17
+ Analyzing dependency graph...
18
+ Mining git history...
19
+ Discovering conventions...
20
+
21
+ Discoveries:
22
+ - version.py and environment.prod.ts always change together
23
+ - workflow-edit-dialog.component.ts and models.py are tightly coupled
24
+
25
+ Validation (49 commits backtested):
26
+ - Overall recall: 78%
27
+ - Token reduction: 67% (1.3M → 437K avg)
28
+
29
+ Output: 3 .scope files written.
30
+ ```
31
+
32
+ One MCP tool call. The agent gets the relevant code, its dependency
33
+ neighborhood, implicit contracts from git history, convention rules,
34
+ swarm lock status, and action hints. One call, not five.
35
+
36
+ dotscope learns from every commit. Files agents consistently need get
37
+ ranked higher. Conventions that hold get enforced harder. Rules that
38
+ get overridden get quieter. Recall starts at 78% and climbs past 91%.
39
+
40
+ ```
41
+ pip install dotscope && dotscope init
42
+ ```
43
+
44
+ Zero dependencies. Python 3.9+ stdlib only. MIT.
45
+
46
+ [How It Works](docs/how-it-works.md) · [Scope Files](docs/scope-file.md) · [Agent Instructions](AGENT_INSTRUCTIONS.md) · [MIT](LICENSE)
@@ -1,3 +1,3 @@
1
1
  """dotscope — Directory-scoped context boundaries for AI coding agents."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "1.2.2"
@@ -354,12 +354,18 @@ def _cmd_init(args):
354
354
  except Exception as e:
355
355
  print(f"dotscope: MCP config failed: {e}", file=sys.stderr)
356
356
 
357
- # 4. Write AGENT_INSTRUCTIONS.md
357
+ # 4. Write AGENT_INSTRUCTIONS.md + CLAUDE.md
358
358
  try:
359
359
  _write_agent_instructions(root, quiet)
360
360
  except Exception as e:
361
361
  if not quiet:
362
362
  print(f"dotscope: agent instructions failed: {e}", file=sys.stderr)
363
+ try:
364
+ from .storage.claude_hooks import write_claude_md
365
+ write_claude_md(root)
366
+ except Exception as e:
367
+ if not quiet:
368
+ print(f"dotscope: CLAUDE.md failed: {e}", file=sys.stderr)
363
369
 
364
370
  # 5. Backtest as counterfactual demo
365
371
  if not quiet:
@@ -2,20 +2,44 @@
2
2
 
3
3
  # Directories to always skip when walking a codebase
4
4
  SKIP_DIRS = frozenset({
5
+ # Version control
5
6
  ".git",
7
+ # Package managers
6
8
  "node_modules",
9
+ "vendor",
10
+ # Python
7
11
  "__pycache__",
8
12
  "venv",
9
13
  ".venv",
10
14
  "env",
11
15
  ".env",
12
- "dist",
13
- "build",
14
16
  ".tox",
15
17
  ".mypy_cache",
16
18
  ".ruff_cache",
17
19
  ".eggs",
18
20
  ".pytest_cache",
21
+ # Build output
22
+ "dist",
23
+ "build",
24
+ "out",
25
+ "target",
26
+ "bin",
27
+ "obj",
28
+ # JS/TS frameworks
29
+ ".next",
30
+ ".nuxt",
31
+ ".output",
32
+ ".parcel-cache",
33
+ # Caches
34
+ ".cache",
35
+ ".gradle",
36
+ ".terraform",
37
+ # Test/coverage output
38
+ "coverage",
39
+ "test-results",
40
+ # dotscope / Claude
41
+ ".dotscope",
42
+ ".claude",
19
43
  })
20
44
 
21
45
  # Source file extensions
@@ -57,7 +57,7 @@ def _format_plain(resolved: ResolvedScope, root: Optional[str], show_tokens: boo
57
57
 
58
58
 
59
59
  def _format_json(resolved: ResolvedScope, root: Optional[str]) -> str:
60
- """JSON format: full object."""
60
+ """JSON format: full object with all compiled retrieval fields."""
61
61
  data = {
62
62
  "files": [make_relative(f, root) for f in resolved.files],
63
63
  "context": resolved.context,
@@ -69,6 +69,18 @@ def _format_json(resolved: ResolvedScope, root: Optional[str]) -> str:
69
69
  if resolved.excluded_files:
70
70
  data["excluded_count"] = len(resolved.excluded_files)
71
71
 
72
+ # Compiled retrieval fields (populated by codebase_search)
73
+ if resolved.flattened_abstractions:
74
+ data["flattened_abstractions"] = resolved.flattened_abstractions
75
+ if resolved.constraints:
76
+ data["constraints"] = resolved.constraints
77
+ if resolved.routing:
78
+ data["routing"] = resolved.routing
79
+ if resolved.action_hints:
80
+ data["action_hints"] = resolved.action_hints
81
+ if resolved.retrieval_metadata:
82
+ data["retrieval_metadata"] = resolved.retrieval_metadata
83
+
72
84
  return json.dumps(data, indent=2)
73
85
 
74
86
 
@@ -118,8 +118,8 @@ def _load_config(root: str) -> GenerateConfig:
118
118
  return GenerateConfig()
119
119
 
120
120
  try:
121
- from ..parser import _parse_yaml_simple
122
- data = _parse_yaml_simple(config_path.read_text(encoding="utf-8"))
121
+ from ..parser import _parse_yaml
122
+ data = _parse_yaml(config_path.read_text(encoding="utf-8"))
123
123
  gen = data.get("generate", {})
124
124
  return GenerateConfig(
125
125
  output_dir=gen.get("output_dir", "docs/dotscope"),
@@ -0,0 +1,59 @@
1
+ """.dotscopeignore support — gitignore-style exclusion patterns.
2
+
3
+ Loaded once at scan start, passed through the pipeline. No per-file IO.
4
+ """
5
+
6
+ import fnmatch
7
+ import os
8
+ from pathlib import Path
9
+ from typing import List
10
+
11
+
12
+ def load_ignore_patterns(repo_root: str) -> List[str]:
13
+ """Load .dotscopeignore patterns. Returns empty list if no file."""
14
+ ignore_path = os.path.join(repo_root, ".dotscopeignore")
15
+ if not os.path.exists(ignore_path):
16
+ return []
17
+
18
+ patterns = []
19
+ try:
20
+ with open(ignore_path, "r", encoding="utf-8") as f:
21
+ for line in f:
22
+ line = line.strip()
23
+ if not line or line.startswith("#"):
24
+ continue
25
+ patterns.append(line)
26
+ except (IOError, OSError):
27
+ return []
28
+ return patterns
29
+
30
+
31
+ def should_skip(
32
+ path: str,
33
+ skip_dirs: frozenset,
34
+ ignore_patterns: List[str],
35
+ ) -> bool:
36
+ """Check if a path should be skipped.
37
+
38
+ Order: hardcoded skip_dirs first (O(1) lookup),
39
+ then .dotscopeignore patterns (glob matching).
40
+ """
41
+ parts = Path(path).parts
42
+ for part in parts:
43
+ if part in skip_dirs:
44
+ return True
45
+
46
+ for pattern in ignore_patterns:
47
+ if fnmatch.fnmatch(path, pattern):
48
+ return True
49
+ # Directory patterns: "renderer/target/" matches any file under it
50
+ if pattern.endswith("/"):
51
+ dir_prefix = pattern.rstrip("/")
52
+ if path.startswith(dir_prefix + "/") or path.startswith(dir_prefix + os.sep):
53
+ return True
54
+ # Also match against any path component
55
+ for part in parts:
56
+ if fnmatch.fnmatch(part, dir_prefix):
57
+ return True
58
+
59
+ return False
@@ -29,6 +29,26 @@ from .paths import (
29
29
  from .tokens import estimate_scope_tokens
30
30
 
31
31
 
32
+ def _safe_print(text, **kwargs):
33
+ """Print with ASCII fallback for Windows cp1252 terminals."""
34
+ try:
35
+ print(text, **kwargs)
36
+ except UnicodeEncodeError:
37
+ print(text.encode("ascii", errors="replace").decode("ascii"), **kwargs)
38
+
39
+
40
+ def _log_ingest_error(root: str, message: str) -> None:
41
+ """Append error to .dotscope/error.log for debugging."""
42
+ try:
43
+ log_dir = os.path.join(root, ".dotscope")
44
+ os.makedirs(log_dir, exist_ok=True)
45
+ import time
46
+ with open(os.path.join(log_dir, "error.log"), "a", encoding="utf-8") as f:
47
+ f.write(f"[{time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime())}] {message}\n")
48
+ except Exception:
49
+ pass # Logging failure should never block ingest
50
+
51
+
32
52
  def ingest(
33
53
  root: str,
34
54
  mine_history: bool = True,
@@ -168,8 +188,8 @@ def ingest(
168
188
  artifacts_path = os.path.join(root, ".dotscope_artifacts.yaml")
169
189
  if os.path.isfile(artifacts_path):
170
190
  try:
171
- from .parser import _parse_yaml_simple
172
- artifacts_data = _parse_yaml_simple(
191
+ from .parser import _parse_yaml
192
+ artifacts_data = _parse_yaml(
173
193
  open(artifacts_path, "r", encoding="utf-8").read()
174
194
  )
175
195
  for artifact in artifacts_data.get("artifacts", []):
@@ -191,13 +211,41 @@ def ingest(
191
211
  except Exception:
192
212
  pass
193
213
 
214
+ # Cap chunk count to prevent OOM on large repos
215
+ max_chunks = getattr(args, "max_chunks", 50_000) if args else 50_000
216
+ if len(all_chunks) > max_chunks:
217
+ # Prefer source files over tests/configs
218
+ def _chunk_priority(c):
219
+ p = c.file_path.lower()
220
+ if "/test" in p or p.startswith("test"):
221
+ return 2
222
+ if any(p.endswith(e) for e in (".json", ".yaml", ".yml", ".toml")):
223
+ return 1
224
+ return 0
225
+ all_chunks.sort(key=lambda c: (_chunk_priority(c), c.file_path))
226
+ _safe_print(
227
+ f"dotscope: {len(all_chunks)} chunks exceeds limit,"
228
+ f" keeping top {max_chunks}",
229
+ file=sys.stderr,
230
+ )
231
+ all_chunks = all_chunks[:max_chunks]
232
+
194
233
  if all_chunks:
195
234
  index = build_vector_index(root, all_chunks)
196
235
  progress.finish(f"{index.chunk_count} chunks, {index.model_name}")
197
236
  else:
198
237
  progress.finish("0 chunks")
199
238
  except Exception as e:
200
- progress.finish(f"skipped ({e})")
239
+ import traceback
240
+ _safe_print(
241
+ f"dotscope: search index failed: {e}\n"
242
+ f" Scopes still work. Search will be unavailable.\n"
243
+ f" Try: dotscope ingest . --max-chunks 25000",
244
+ file=sys.stderr,
245
+ )
246
+ # Log full traceback for debugging
247
+ _log_ingest_error(root, traceback.format_exc())
248
+ progress.finish("failed")
201
249
 
202
250
  # Step 4: Synthesize scope files
203
251
  progress.start("generating scopes")
@@ -1256,7 +1256,20 @@ def main():
1256
1256
  task_type=task_type,
1257
1257
  no_observe=no_observe or False,
1258
1258
  )
1259
- return format_resolved(resolved, fmt="json", root=root)
1259
+ result = json.loads(format_resolved(resolved, fmt="json", root=root))
1260
+
1261
+ # Add next_steps based on what was found
1262
+ next_steps = []
1263
+ if resolved.constraints:
1264
+ next_steps.append("Run dotscope_check before committing.")
1265
+ if any(c.get("severity") == "GUARD" for c in resolved.constraints):
1266
+ next_steps.append("GUARD-level constraints found. These will block your commit.")
1267
+ if result.get("retrieval_metadata", {}).get("index_freshness") == "stale":
1268
+ next_steps.append("Index is stale. Run dotscope ingest to refresh.")
1269
+ if next_steps:
1270
+ result["next_steps"] = next_steps
1271
+
1272
+ return json.dumps(result, indent=2)
1260
1273
 
1261
1274
  # -------------------------------------------------------------------
1262
1275
  # Swarm Lock MCP tools
@@ -1453,5 +1466,112 @@ def _route_by_imports(planned_imports: list, root: str) -> Optional[dict]:
1453
1466
  }
1454
1467
 
1455
1468
 
1469
+ # -------------------------------------------------------------------
1470
+ # Swarm helpers
1471
+ # -------------------------------------------------------------------
1472
+
1473
+ def _find_root():
1474
+ from .discovery import find_repo_root
1475
+ return find_repo_root() or "."
1476
+
1477
+ def _get_graph(root):
1478
+ from .passes.graph_builder import build_graph
1479
+ return build_graph(root)
1480
+
1481
+ def _load_index(root):
1482
+ from .discovery import load_index
1483
+ return load_index(root)
1484
+
1485
+ def _load_invariants(root):
1486
+ inv_path = os.path.join(root, ".dotscope", "invariants.json")
1487
+ if os.path.isfile(inv_path):
1488
+ try:
1489
+ with open(inv_path, "r", encoding="utf-8") as f:
1490
+ return json.load(f)
1491
+ except Exception:
1492
+ pass
1493
+ return {}
1494
+
1495
+ # -------------------------------------------------------------------
1496
+ # Swarm Intelligence MCP tools
1497
+ # -------------------------------------------------------------------
1498
+
1499
+ @mcp.tool()
1500
+ def partition_search_space(
1501
+ intent: str,
1502
+ n_partitions: int = 3,
1503
+ ) -> dict:
1504
+ """Divide an exploratory task into non-overlapping starting points.
1505
+
1506
+ Uses semantic search to find relevant files, then graph analysis
1507
+ to cleave them into decoupled partitions. Scouts assigned to
1508
+ different partitions are guaranteed to start in structurally
1509
+ independent domains.
1510
+
1511
+ Args:
1512
+ intent: Natural language description of what to investigate
1513
+ n_partitions: Number of parallel scouts to support (2-10)
1514
+
1515
+ May return fewer partitions than requested if search results
1516
+ are highly localized. Check len(partitions), not n_partitions.
1517
+ """
1518
+ from .swarm.partition import partition_search_space as _partition
1519
+ root = _root or _find_root()
1520
+ graph = _get_graph(root)
1521
+ index = _load_index(root)
1522
+ invariants = _load_invariants(root)
1523
+ return _partition(intent, n_partitions, root, graph, index, invariants)
1524
+
1525
+ @mcp.tool()
1526
+ def resolve_trace(
1527
+ entry_file: str,
1528
+ max_depth: int = 3,
1529
+ focus: str = "",
1530
+ ) -> dict:
1531
+ """Resolve context along a specific execution path.
1532
+
1533
+ Follows imports from entry_file up to max_depth. Returns unified
1534
+ context covering all scopes crossed, deduplicated, with only the
1535
+ constraints relevant to files in the trace.
1536
+
1537
+ Args:
1538
+ entry_file: Starting point for the trace
1539
+ max_depth: How many import levels to follow (default 3, max 10)
1540
+ focus: Optional keyword to filter context relevance
1541
+ (e.g., "memory" to prioritize memory-related context)
1542
+ """
1543
+ from .swarm.trace import resolve_trace as _trace
1544
+ root = _root or _find_root()
1545
+ graph = _get_graph(root)
1546
+ index = _load_index(root)
1547
+ invariants = _load_invariants(root)
1548
+ return _trace(
1549
+ entry_file, max_depth, focus or None,
1550
+ root, graph, index, invariants,
1551
+ )
1552
+
1553
+ @mcp.tool()
1554
+ def merge_scout_findings(
1555
+ scout_reports: list,
1556
+ ) -> dict:
1557
+ """Cross-reference scout findings against codebase physics.
1558
+
1559
+ Takes raw scout reports (flagged files + notes) and returns
1560
+ structurally validated connections, convergence points,
1561
+ and a unified blast radius.
1562
+
1563
+ Each scout report should contain:
1564
+ scout_id: int
1565
+ flagged_files: List[str]
1566
+ notes: str (natural language findings)
1567
+ confidence: float (0-1, scout's self-assessed confidence)
1568
+ """
1569
+ from .swarm.merge import merge_scout_findings as _merge
1570
+ root = _root or _find_root()
1571
+ graph = _get_graph(root)
1572
+ invariants = _load_invariants(root)
1573
+ return _merge(scout_reports, root, graph, invariants)
1574
+
1575
+
1456
1576
  if __name__ == "__main__":
1457
1577
  main()
@@ -94,6 +94,10 @@ class ResolvedScope:
94
94
  # Compiled Retrieval extensions (populated by codebase_search only)
95
95
  flattened_abstractions: Dict[str, dict] = field(default_factory=dict)
96
96
  retrieval_metadata: Optional[dict] = None
97
+ # Structured constraints (contracts, anti-patterns, conventions, intents)
98
+ constraints: List[dict] = field(default_factory=list)
99
+ # Routing guidance (convention blueprints, voice rules)
100
+ routing: List[dict] = field(default_factory=list)
97
101
  # Action hints: imperative directives derived from constraints and locks
98
102
  action_hints: List[str] = field(default_factory=list)
99
103
 
@@ -14,6 +14,7 @@ from ..ast_analyzer import (
14
14
  resolve_python_import,
15
15
  )
16
16
  from ..constants import LANG_MAP, SKIP_DIRS
17
+ from ..ignore import load_ignore_patterns, should_skip
17
18
  from ..models.core import (
18
19
  DependencyGraph,
19
20
  FileNode,
@@ -201,15 +202,25 @@ def transitive_dependents(graph: DependencyGraph, file: str) -> Set[str]:
201
202
  def _collect_source_files(root: str) -> List[Tuple[str, str]]:
202
203
  """Walk the tree and collect (relative_path, language)."""
203
204
  lang_map = {k: v.lower() for k, v in LANG_MAP.items()}
205
+ ignore_patterns = load_ignore_patterns(root)
204
206
  results = []
205
207
 
206
208
  for dirpath, dirnames, filenames in os.walk(root):
207
- dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]
209
+ dirnames[:] = [
210
+ d for d in dirnames
211
+ if d not in SKIP_DIRS
212
+ and not should_skip(
213
+ os.path.relpath(os.path.join(dirpath, d), root),
214
+ SKIP_DIRS,
215
+ ignore_patterns,
216
+ )
217
+ ]
208
218
  for fn in filenames:
209
219
  ext = os.path.splitext(fn)[1].lower()
210
220
  if ext in lang_map:
211
221
  rel = normalize_relative_path(os.path.relpath(os.path.join(dirpath, fn), root))
212
- results.append((rel, lang_map[ext]))
222
+ if not should_skip(rel, frozenset(), ignore_patterns):
223
+ results.append((rel, lang_map[ext]))
213
224
 
214
225
  return sorted(results)
215
226
 
@@ -12,6 +12,7 @@ from typing import List, Optional, Set, Tuple
12
12
 
13
13
  from .constants import LANG_MAP, SKIP_DIRS
14
14
  from .context import parse_context
15
+ from .ignore import load_ignore_patterns, should_skip
15
16
  from .models import ScopeConfig
16
17
  from .tokens import estimate_file_tokens
17
18
 
@@ -100,11 +101,27 @@ def _scan_files(path: str) -> Tuple[List[str], Counter, int]:
100
101
  lang_counts: Counter = Counter()
101
102
  total_tokens = 0
102
103
 
104
+ # Load .dotscopeignore patterns from the repo root (or nearest parent)
105
+ ignore_patterns = load_ignore_patterns(path)
106
+
103
107
  for dirpath, dirnames, filenames in os.walk(path):
104
- dirnames[:] = [d for d in dirnames if d not in SKIP_DIRS]
108
+ dirnames[:] = [
109
+ d for d in dirnames
110
+ if d not in SKIP_DIRS
111
+ and not should_skip(
112
+ os.path.relpath(os.path.join(dirpath, d), path),
113
+ SKIP_DIRS,
114
+ ignore_patterns,
115
+ )
116
+ ]
105
117
 
106
118
  for filename in filenames:
107
119
  full = os.path.join(dirpath, filename)
120
+ rel = os.path.relpath(full, path)
121
+
122
+ if should_skip(rel, frozenset(), ignore_patterns):
123
+ continue
124
+
108
125
  files.append(full)
109
126
 
110
127
  ext = os.path.splitext(filename)[1].lower()
@@ -283,12 +283,30 @@ def _dense_search(query: str, embeddings, limit: int = 50) -> List[Tuple[int, fl
283
283
  return []
284
284
 
285
285
 
286
- def _embed_texts(texts: List[str]):
287
- """Embed texts using sentence-transformers. Returns numpy array or None."""
286
+ def _embed_texts(texts: List[str], batch_size: int = 512):
287
+ """Embed texts in batches using sentence-transformers. Returns numpy array or None."""
288
288
  try:
289
289
  from sentence_transformers import SentenceTransformer
290
+ import numpy as np
291
+
290
292
  model = SentenceTransformer("all-MiniLM-L6-v2")
291
- return model.encode(texts, show_progress_bar=False, convert_to_numpy=True)
293
+
294
+ if len(texts) <= batch_size:
295
+ return model.encode(texts, show_progress_bar=False, convert_to_numpy=True)
296
+
297
+ # Batch to avoid OOM on large repos
298
+ all_embeddings = []
299
+ for i in range(0, len(texts), batch_size):
300
+ batch = texts[i:i + batch_size]
301
+ try:
302
+ embeddings = model.encode(batch, show_progress_bar=False, convert_to_numpy=True)
303
+ all_embeddings.append(embeddings)
304
+ except Exception:
305
+ continue # Skip failed batch, keep going
306
+
307
+ if not all_embeddings:
308
+ return None
309
+ return np.vstack(all_embeddings)
292
310
  except ImportError:
293
311
  return None
294
312