dotscope 1.2.1__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.
- {dotscope-1.2.1 → dotscope-1.2.2}/.github/workflows/python-publish.yml +1 -1
- dotscope-1.2.2/CLAUDE.md +10 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/PKG-INFO +1 -1
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/__init__.py +1 -1
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/cli.py +7 -1
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/formatter.py +13 -1
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/mcp_server.py +121 -1
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/models/core.py +4 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/search/synthesizer.py +17 -7
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/claude_hooks.py +47 -0
- dotscope-1.2.2/dotscope/swarm/__init__.py +13 -0
- dotscope-1.2.2/dotscope/swarm/merge.py +161 -0
- dotscope-1.2.2/dotscope/swarm/partition.py +236 -0
- dotscope-1.2.2/dotscope/swarm/trace.py +251 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/pyproject.toml +1 -1
- dotscope-1.2.2/tests/test_swarm.py +300 -0
- dotscope-1.2.1/.claude/settings.local.json +0 -35
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/.claude/hooks/pre-commit-check.sh +0 -41
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/.claude/settings.json +0 -15
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/.claude/settings.local.json +0 -52
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/.git +0 -1
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/README.md +0 -90
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/constants.py +0 -45
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/formatter.py +0 -157
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/generate/engine.py +0 -189
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/ingest.py +0 -972
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/mcp_server.py +0 -1457
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/models/core.py +0 -328
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/passes/graph_builder.py +0 -437
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/scanner.py +0 -246
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/search/retriever.py +0 -368
- dotscope-1.2.1/.claude/worktrees/hopeful-chatelet/dotscope/search/synthesizer.py +0 -292
- dotscope-1.2.1/.gitignore +0 -10
- dotscope-1.2.1/.mcp.json +0 -9
- dotscope-1.2.1/.scopes +0 -28
- dotscope-1.2.1/AGENT_INSTRUCTIONS.md +0 -129
- dotscope-1.2.1/LICENSE +0 -21
- dotscope-1.2.1/docs/architecture.md +0 -72
- dotscope-1.2.1/docs/cli-reference.md +0 -67
- dotscope-1.2.1/docs/how-it-works.md +0 -146
- dotscope-1.2.1/docs/mcp-setup.md +0 -255
- dotscope-1.2.1/docs/scope-file.md +0 -285
- dotscope-1.2.1/dotscope/.scope +0 -82
- dotscope-1.2.1/dotscope/__init__.py +0 -3
- dotscope-1.2.1/dotscope/absorber.py +0 -390
- dotscope-1.2.1/dotscope/assertions.py +0 -127
- dotscope-1.2.1/dotscope/ast_analyzer.py +0 -2
- dotscope-1.2.1/dotscope/backtest.py +0 -2
- dotscope-1.2.1/dotscope/bench.py +0 -141
- dotscope-1.2.1/dotscope/budget.py +0 -3
- dotscope-1.2.1/dotscope/cache.py +0 -2
- dotscope-1.2.1/dotscope/check/__init__.py +0 -1
- dotscope-1.2.1/dotscope/check/acknowledge.py +0 -2
- dotscope-1.2.1/dotscope/check/checker.py +0 -3
- dotscope-1.2.1/dotscope/check/checks/__init__.py +0 -1
- dotscope-1.2.1/dotscope/check/checks/antipattern.py +0 -2
- dotscope-1.2.1/dotscope/check/checks/boundary.py +0 -2
- dotscope-1.2.1/dotscope/check/checks/contracts.py +0 -3
- dotscope-1.2.1/dotscope/check/checks/direction.py +0 -2
- dotscope-1.2.1/dotscope/check/checks/intent.py +0 -2
- dotscope-1.2.1/dotscope/check/checks/stability.py +0 -2
- dotscope-1.2.1/dotscope/check/constraints.py +0 -2
- dotscope-1.2.1/dotscope/check/models.py +0 -15
- dotscope-1.2.1/dotscope/cli.py +0 -1561
- dotscope-1.2.1/dotscope/composer.py +0 -229
- dotscope-1.2.1/dotscope/context.py +0 -60
- dotscope-1.2.1/dotscope/counterfactual.py +0 -180
- dotscope-1.2.1/dotscope/debug.py +0 -220
- dotscope-1.2.1/dotscope/discovery.py +0 -138
- dotscope-1.2.1/dotscope/eval/.scope +0 -27
- dotscope-1.2.1/dotscope/eval/__init__.py +0 -18
- dotscope-1.2.1/dotscope/eval/bootstrap.py +0 -231
- dotscope-1.2.1/dotscope/eval/compare.py +0 -147
- dotscope-1.2.1/dotscope/eval/corpus.py +0 -214
- dotscope-1.2.1/dotscope/eval/harness.py +0 -310
- dotscope-1.2.1/dotscope/eval/replay.py +0 -356
- dotscope-1.2.1/dotscope/generate/.scope +0 -24
- dotscope-1.2.1/dotscope/generate/__init__.py +0 -1
- dotscope-1.2.1/dotscope/generate/atlas.py +0 -341
- dotscope-1.2.1/dotscope/generate/contracts.py +0 -296
- dotscope-1.2.1/dotscope/generate/models.py +0 -27
- dotscope-1.2.1/dotscope/generate/network.py +0 -284
- dotscope-1.2.1/dotscope/graph.py +0 -3
- dotscope-1.2.1/dotscope/health.py +0 -272
- dotscope-1.2.1/dotscope/help.py +0 -218
- dotscope-1.2.1/dotscope/history.py +0 -6
- dotscope-1.2.1/dotscope/hooks.py +0 -2
- dotscope-1.2.1/dotscope/intent.py +0 -614
- dotscope-1.2.1/dotscope/lessons.py +0 -223
- dotscope-1.2.1/dotscope/matcher.py +0 -104
- dotscope-1.2.1/dotscope/merge/.scope +0 -34
- dotscope-1.2.1/dotscope/merge/__init__.py +0 -1
- dotscope-1.2.1/dotscope/merge/classifier.py +0 -83
- dotscope-1.2.1/dotscope/merge/composer.py +0 -210
- dotscope-1.2.1/dotscope/merge/differ.py +0 -178
- dotscope-1.2.1/dotscope/merge/driver.py +0 -147
- dotscope-1.2.1/dotscope/merge/imports.py +0 -114
- dotscope-1.2.1/dotscope/merge/models.py +0 -62
- dotscope-1.2.1/dotscope/merge/swarm.py +0 -336
- dotscope-1.2.1/dotscope/models/.scope +0 -45
- dotscope-1.2.1/dotscope/models/__init__.py +0 -8
- dotscope-1.2.1/dotscope/models/eval.py +0 -96
- dotscope-1.2.1/dotscope/models/history.py +0 -73
- dotscope-1.2.1/dotscope/models/intent.py +0 -214
- dotscope-1.2.1/dotscope/models/passes.py +0 -58
- dotscope-1.2.1/dotscope/models/state.py +0 -251
- dotscope-1.2.1/dotscope/models.py +0 -9
- dotscope-1.2.1/dotscope/near_miss.py +0 -3
- dotscope-1.2.1/dotscope/onboarding.py +0 -2
- dotscope-1.2.1/dotscope/parser.py +0 -395
- dotscope-1.2.1/dotscope/passes/.scope +0 -105
- dotscope-1.2.1/dotscope/passes/__init__.py +0 -1
- dotscope-1.2.1/dotscope/passes/ast_analyzer.py +0 -757
- dotscope-1.2.1/dotscope/passes/backtest.py +0 -198
- dotscope-1.2.1/dotscope/passes/budget_allocator.py +0 -343
- dotscope-1.2.1/dotscope/passes/convention_compliance.py +0 -40
- dotscope-1.2.1/dotscope/passes/convention_discovery.py +0 -345
- dotscope-1.2.1/dotscope/passes/convention_parser.py +0 -235
- dotscope-1.2.1/dotscope/passes/hint_generator.py +0 -128
- dotscope-1.2.1/dotscope/passes/history_miner.py +0 -336
- dotscope-1.2.1/dotscope/passes/incremental.py +0 -221
- dotscope-1.2.1/dotscope/passes/lang/__init__.py +0 -38
- dotscope-1.2.1/dotscope/passes/lang/_base.py +0 -20
- dotscope-1.2.1/dotscope/passes/lang/_treesitter.py +0 -93
- dotscope-1.2.1/dotscope/passes/lang/go.py +0 -334
- dotscope-1.2.1/dotscope/passes/lang/javascript.py +0 -431
- dotscope-1.2.1/dotscope/passes/lazy.py +0 -177
- dotscope-1.2.1/dotscope/passes/preflight.py +0 -117
- dotscope-1.2.1/dotscope/passes/semantic_diff.py +0 -160
- dotscope-1.2.1/dotscope/passes/sentinel/__init__.py +0 -1
- dotscope-1.2.1/dotscope/passes/sentinel/acknowledge.py +0 -222
- dotscope-1.2.1/dotscope/passes/sentinel/checker.py +0 -428
- dotscope-1.2.1/dotscope/passes/sentinel/checks/__init__.py +0 -1
- dotscope-1.2.1/dotscope/passes/sentinel/checks/antipattern.py +0 -84
- dotscope-1.2.1/dotscope/passes/sentinel/checks/boundary.py +0 -46
- dotscope-1.2.1/dotscope/passes/sentinel/checks/contracts.py +0 -148
- dotscope-1.2.1/dotscope/passes/sentinel/checks/convention.py +0 -54
- dotscope-1.2.1/dotscope/passes/sentinel/checks/direction.py +0 -71
- dotscope-1.2.1/dotscope/passes/sentinel/checks/intent.py +0 -207
- dotscope-1.2.1/dotscope/passes/sentinel/checks/network.py +0 -91
- dotscope-1.2.1/dotscope/passes/sentinel/checks/spatial.py +0 -115
- dotscope-1.2.1/dotscope/passes/sentinel/checks/stability.py +0 -66
- dotscope-1.2.1/dotscope/passes/sentinel/checks/voice.py +0 -108
- dotscope-1.2.1/dotscope/passes/sentinel/constraints.py +0 -472
- dotscope-1.2.1/dotscope/passes/sentinel/line_filter.py +0 -88
- dotscope-1.2.1/dotscope/passes/sentinel/models.py +0 -15
- dotscope-1.2.1/dotscope/passes/spatial_autofix.py +0 -206
- dotscope-1.2.1/dotscope/passes/virtual.py +0 -247
- dotscope-1.2.1/dotscope/passes/voice.py +0 -161
- dotscope-1.2.1/dotscope/passes/voice_defaults.py +0 -68
- dotscope-1.2.1/dotscope/passes/voice_discovery.py +0 -245
- dotscope-1.2.1/dotscope/paths.py +0 -83
- dotscope-1.2.1/dotscope/progress.py +0 -44
- dotscope-1.2.1/dotscope/refresh.py +0 -543
- dotscope-1.2.1/dotscope/regression.py +0 -147
- dotscope-1.2.1/dotscope/resolver.py +0 -198
- dotscope-1.2.1/dotscope/runtime_overlay.py +0 -403
- dotscope-1.2.1/dotscope/search/.scope +0 -29
- dotscope-1.2.1/dotscope/search/__init__.py +0 -1
- dotscope-1.2.1/dotscope/search/chunker.py +0 -343
- dotscope-1.2.1/dotscope/search/expander.py +0 -129
- dotscope-1.2.1/dotscope/search/flattener.py +0 -187
- dotscope-1.2.1/dotscope/search/models.py +0 -70
- dotscope-1.2.1/dotscope/search/observation.py +0 -279
- dotscope-1.2.1/dotscope/search/reranker.py +0 -85
- dotscope-1.2.1/dotscope/sessions.py +0 -2
- dotscope-1.2.1/dotscope/storage/.scope +0 -64
- dotscope-1.2.1/dotscope/storage/__init__.py +0 -1
- dotscope-1.2.1/dotscope/storage/cache.py +0 -177
- dotscope-1.2.1/dotscope/storage/claude_hooks.py +0 -119
- dotscope-1.2.1/dotscope/storage/git_hooks.py +0 -500
- dotscope-1.2.1/dotscope/storage/incremental_state.py +0 -124
- dotscope-1.2.1/dotscope/storage/mcp_config.py +0 -98
- dotscope-1.2.1/dotscope/storage/near_miss.py +0 -183
- dotscope-1.2.1/dotscope/storage/onboarding.py +0 -150
- dotscope-1.2.1/dotscope/storage/session_manager.py +0 -195
- dotscope-1.2.1/dotscope/storage/swarm_state.py +0 -144
- dotscope-1.2.1/dotscope/storage/timing.py +0 -84
- dotscope-1.2.1/dotscope/textio.py +0 -122
- dotscope-1.2.1/dotscope/timing.py +0 -2
- dotscope-1.2.1/dotscope/tokens.py +0 -53
- dotscope-1.2.1/dotscope/utility.py +0 -123
- dotscope-1.2.1/dotscope/virtual.py +0 -3
- dotscope-1.2.1/dotscope/visibility.py +0 -687
- dotscope-1.2.1/logo.png +0 -0
- dotscope-1.2.1/pyproject.toml +0 -45
- dotscope-1.2.1/tests/.scope +0 -29
- dotscope-1.2.1/tests/__init__.py +0 -0
- dotscope-1.2.1/tests/conftest.py +0 -152
- dotscope-1.2.1/tests/test_absorber.py +0 -91
- dotscope-1.2.1/tests/test_ast_analyzer.py +0 -168
- dotscope-1.2.1/tests/test_backtest.py +0 -114
- dotscope-1.2.1/tests/test_budget.py +0 -124
- dotscope-1.2.1/tests/test_canonical_snippet.py +0 -70
- dotscope-1.2.1/tests/test_cli.py +0 -122
- dotscope-1.2.1/tests/test_composer.py +0 -125
- dotscope-1.2.1/tests/test_context.py +0 -52
- dotscope-1.2.1/tests/test_enforcement.py +0 -423
- dotscope-1.2.1/tests/test_eval_harness.py +0 -376
- dotscope-1.2.1/tests/test_experience.py +0 -237
- dotscope-1.2.1/tests/test_graph.py +0 -78
- dotscope-1.2.1/tests/test_health.py +0 -142
- dotscope-1.2.1/tests/test_history.py +0 -71
- dotscope-1.2.1/tests/test_ingest.py +0 -319
- dotscope-1.2.1/tests/test_lessons.py +0 -91
- dotscope-1.2.1/tests/test_line_filter.py +0 -67
- dotscope-1.2.1/tests/test_loop.py +0 -384
- dotscope-1.2.1/tests/test_matcher.py +0 -47
- dotscope-1.2.1/tests/test_near_miss.py +0 -161
- dotscope-1.2.1/tests/test_parser.py +0 -180
- dotscope-1.2.1/tests/test_refresh.py +0 -251
- dotscope-1.2.1/tests/test_resolver.py +0 -100
- dotscope-1.2.1/tests/test_rigor.py +0 -223
- dotscope-1.2.1/tests/test_routing.py +0 -207
- dotscope-1.2.1/tests/test_scanner.py +0 -54
- dotscope-1.2.1/tests/test_sessions.py +0 -122
- dotscope-1.2.1/tests/test_textio.py +0 -85
- dotscope-1.2.1/tests/test_treesitter.py +0 -359
- dotscope-1.2.1/tests/test_utility.py +0 -48
- dotscope-1.2.1/tests/test_virtual.py +0 -95
- dotscope-1.2.1/tests/test_visibility.py +0 -417
- dotscope-1.2.1/tests/test_voice_check.py +0 -123
- dotscope-1.2.1/tests/test_voice_discovery.py +0 -143
- dotscope-1.2.1/uv.lock +0 -2375
- {dotscope-1.2.1 → dotscope-1.2.2}/.claude/hooks/pre-commit-check.sh +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/.claude/settings.json +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/.gitignore +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/.scopes +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/AGENT_INSTRUCTIONS.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/LICENSE +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/README.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/architecture.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/cli-reference.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/how-it-works.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/mcp-setup.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/docs/scope-file.md +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/absorber.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/assertions.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/ast_analyzer.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/backtest.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/bench.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/budget.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/cache.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/acknowledge.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checker.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/antipattern.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/boundary.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/contracts.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/direction.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/intent.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/checks/stability.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/constraints.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/check/models.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/composer.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/constants.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/context.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/counterfactual.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/debug.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/discovery.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/bootstrap.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/compare.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/corpus.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/harness.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/eval/replay.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/atlas.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/contracts.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/generate/engine.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/models.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/generate/network.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/graph.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/health.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/help.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/history.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/hooks.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/ignore.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/ingest.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/intent.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/lessons.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/matcher.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/classifier.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/composer.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/differ.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/driver.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/imports.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/models.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/merge/swarm.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/eval.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/history.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/intent.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/passes.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models/state.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/models.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/near_miss.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/onboarding.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/parser.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/ast_analyzer.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/backtest.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/budget_allocator.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/convention_compliance.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/convention_discovery.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/convention_parser.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/passes/graph_builder.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/hint_generator.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/history_miner.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/incremental.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/_base.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/_treesitter.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/go.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lang/javascript.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/lazy.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/preflight.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/semantic_diff.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/acknowledge.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checker.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/antipattern.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/boundary.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/contracts.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/convention.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/direction.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/intent.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/network.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/spatial.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/stability.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/checks/voice.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/constraints.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/line_filter.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/sentinel/models.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/spatial_autofix.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/virtual.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/voice.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/voice_defaults.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/passes/voice_discovery.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/paths.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/progress.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/refresh.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/regression.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/resolver.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/runtime_overlay.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/scanner.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/chunker.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/expander.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/flattener.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/models.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/observation.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/search/reranker.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/dotscope/search/retriever.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/sessions.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/cache.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/git_hooks.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/incremental_state.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/mcp_config.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/near_miss.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/onboarding.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/session_manager.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/swarm_state.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/storage/timing.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/textio.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/timing.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/tokens.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/utility.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/virtual.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/dotscope/visibility.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/logo.png +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/.scope +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/__init__.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/conftest.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_absorber.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_ast_analyzer.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_backtest.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_budget.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_canonical_snippet.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_cli.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_composer.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_context.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_enforcement.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_eval_harness.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_experience.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_graph.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_health.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_history.py +0 -0
- {dotscope-1.2.1 → dotscope-1.2.2}/tests/test_ignore.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_ingest.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_lessons.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_line_filter.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_loop.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_matcher.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_near_miss.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_parser.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_refresh.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_resolver.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_rigor.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_routing.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_scanner.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_sessions.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_textio.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_treesitter.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_utility.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_virtual.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_visibility.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_voice_check.py +0 -0
- {dotscope-1.2.1/.claude/worktrees/hopeful-chatelet → dotscope-1.2.2}/tests/test_voice_discovery.py +0 -0
- {dotscope-1.2.1/.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:
|
|
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
|
#
|
dotscope-1.2.2/CLAUDE.md
ADDED
|
@@ -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.
|
|
@@ -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:
|
|
@@ -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
|
|
|
@@ -1256,7 +1256,20 @@ def main():
|
|
|
1256
1256
|
task_type=task_type,
|
|
1257
1257
|
no_observe=no_observe or False,
|
|
1258
1258
|
)
|
|
1259
|
-
|
|
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
|
|
|
@@ -131,23 +131,31 @@ def synthesize_search(
|
|
|
131
131
|
"scope_crossing": ab.scope_crossing,
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
# Build constraints
|
|
135
|
-
|
|
134
|
+
# Build constraints (keep structured for JSON response)
|
|
135
|
+
structured_constraints = []
|
|
136
136
|
try:
|
|
137
137
|
from ..passes.sentinel.constraints import build_constraints
|
|
138
|
-
|
|
139
|
-
if
|
|
138
|
+
raw_constraints = build_constraints(root, unique_files, query)
|
|
139
|
+
if raw_constraints:
|
|
140
|
+
structured_constraints = raw_constraints
|
|
140
141
|
constraint_lines = []
|
|
141
|
-
for c in
|
|
142
|
+
for c in raw_constraints:
|
|
142
143
|
msg = c.get("message", "")
|
|
143
144
|
if msg:
|
|
144
145
|
constraint_lines.append(f"- {msg}")
|
|
145
146
|
constraints_text = "\n".join(constraint_lines)
|
|
147
|
+
if constraints_text:
|
|
148
|
+
context_parts.append(f"\n## Constraints\n{constraints_text}")
|
|
146
149
|
except Exception:
|
|
147
150
|
pass
|
|
148
151
|
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
# Build routing guidance
|
|
153
|
+
structured_routing = []
|
|
154
|
+
try:
|
|
155
|
+
from ..passes.sentinel.constraints import build_routing_guidance
|
|
156
|
+
structured_routing = build_routing_guidance(root, unique_files, query) or []
|
|
157
|
+
except Exception:
|
|
158
|
+
pass
|
|
151
159
|
|
|
152
160
|
# Budget allocation: inside-out truncation
|
|
153
161
|
from ..tokens import estimate_tokens
|
|
@@ -166,6 +174,8 @@ def synthesize_search(
|
|
|
166
174
|
context="\n\n".join(context_parts) if context_parts else "",
|
|
167
175
|
token_estimate=used,
|
|
168
176
|
truncated=len(budget_files) < len(unique_files),
|
|
177
|
+
constraints=structured_constraints,
|
|
178
|
+
routing=structured_routing,
|
|
169
179
|
flattened_abstractions=flat_abstractions,
|
|
170
180
|
retrieval_metadata={
|
|
171
181
|
"query": query,
|
|
@@ -117,3 +117,50 @@ def install_claude_hook(repo_root: str) -> str:
|
|
|
117
117
|
f.write("\n")
|
|
118
118
|
|
|
119
119
|
return f"Claude Code hook installed: {script_path}"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
_CLAUDE_MD_CONTENT = """\
|
|
123
|
+
# CLAUDE.md
|
|
124
|
+
|
|
125
|
+
This repo uses dotscope. Before touching code:
|
|
126
|
+
|
|
127
|
+
1. `codebase_search("your task description")` — not manual file reads
|
|
128
|
+
2. `dotscope_check` before every commit
|
|
129
|
+
3. If check returns HOLDs, fix them before committing
|
|
130
|
+
|
|
131
|
+
dotscope provides: dependency graph, implicit contracts, conventions,
|
|
132
|
+
and file locks. Use its tools instead of guessing.
|
|
133
|
+
"""
|
|
134
|
+
|
|
135
|
+
_CLAUDE_MD_SECTION = """
|
|
136
|
+
## dotscope
|
|
137
|
+
|
|
138
|
+
This repo uses dotscope. Before touching code:
|
|
139
|
+
|
|
140
|
+
1. `codebase_search("your task description")` — not manual file reads
|
|
141
|
+
2. `dotscope_check` before every commit
|
|
142
|
+
3. If check returns HOLDs, fix them before committing
|
|
143
|
+
"""
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def write_claude_md(repo_root: str) -> str:
|
|
147
|
+
"""Write CLAUDE.md for automatic agent briefing.
|
|
148
|
+
|
|
149
|
+
If CLAUDE.md doesn't exist, creates it with dotscope instructions.
|
|
150
|
+
If it exists but has no dotscope section, appends one.
|
|
151
|
+
If it already has a dotscope section, does nothing.
|
|
152
|
+
"""
|
|
153
|
+
claude_md_path = os.path.join(repo_root, "CLAUDE.md")
|
|
154
|
+
|
|
155
|
+
if not os.path.exists(claude_md_path):
|
|
156
|
+
with open(claude_md_path, "w", encoding="utf-8") as f:
|
|
157
|
+
f.write(_CLAUDE_MD_CONTENT)
|
|
158
|
+
return f"Created {claude_md_path}"
|
|
159
|
+
|
|
160
|
+
existing = open(claude_md_path, "r", encoding="utf-8").read()
|
|
161
|
+
if "dotscope" in existing.lower() and "codebase_search" in existing:
|
|
162
|
+
return "CLAUDE.md already has dotscope instructions"
|
|
163
|
+
|
|
164
|
+
with open(claude_md_path, "a", encoding="utf-8") as f:
|
|
165
|
+
f.write(_CLAUDE_MD_SECTION)
|
|
166
|
+
return f"Appended dotscope section to {claude_md_path}"
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Swarm-ready primitives for parallel agent coordination.
|
|
2
|
+
|
|
3
|
+
Three read-only tools that make dotscope the sensory layer for agent swarms:
|
|
4
|
+
partition_search_space — divide work into non-overlapping starting points
|
|
5
|
+
resolve_trace — follow an execution path with focused context
|
|
6
|
+
merge_scout_findings — cross-reference parallel findings against codebase structure
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from .partition import partition_search_space
|
|
10
|
+
from .trace import resolve_trace
|
|
11
|
+
from .merge import merge_scout_findings
|
|
12
|
+
|
|
13
|
+
__all__ = ["partition_search_space", "resolve_trace", "merge_scout_findings"]
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"""Cross-reference scout findings against codebase structure."""
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from typing import Dict, List, Set
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def merge_scout_findings(
|
|
8
|
+
scout_reports: List[dict],
|
|
9
|
+
repo_root: str,
|
|
10
|
+
graph,
|
|
11
|
+
invariants: dict,
|
|
12
|
+
) -> dict:
|
|
13
|
+
"""Merge parallel scout findings using codebase structure.
|
|
14
|
+
|
|
15
|
+
Deterministic structural analysis: convergence detection, hidden
|
|
16
|
+
connection discovery via NPMI, blast radius expansion, and
|
|
17
|
+
scout agreement tiers. No LLM calls.
|
|
18
|
+
"""
|
|
19
|
+
# Collect all flagged files with attribution
|
|
20
|
+
file_scouts: Dict[str, List[int]] = defaultdict(list)
|
|
21
|
+
all_files: Set[str] = set()
|
|
22
|
+
|
|
23
|
+
for report in scout_reports:
|
|
24
|
+
scout_id = report.get("scout_id", 0)
|
|
25
|
+
for filepath in report.get("flagged_files", []):
|
|
26
|
+
file_scouts[filepath].append(scout_id)
|
|
27
|
+
all_files.add(filepath)
|
|
28
|
+
|
|
29
|
+
n_scouts = len(scout_reports)
|
|
30
|
+
|
|
31
|
+
# 1. Convergence points: files flagged by 2+ scouts
|
|
32
|
+
convergence_points = []
|
|
33
|
+
for filepath, scouts in file_scouts.items():
|
|
34
|
+
if len(scouts) >= 2:
|
|
35
|
+
convergence_points.append({
|
|
36
|
+
"file": filepath,
|
|
37
|
+
"flagged_by": sorted(scouts),
|
|
38
|
+
"significance": (
|
|
39
|
+
f"{len(scouts)} independent traces converged on this file"
|
|
40
|
+
),
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
convergence_points.sort(key=lambda c: -len(c["flagged_by"]))
|
|
44
|
+
|
|
45
|
+
# 2. Hidden connections: files from different scouts that have
|
|
46
|
+
# structural relationships (contracts, dependencies)
|
|
47
|
+
hidden_connections = []
|
|
48
|
+
scout_file_groups: Dict[int, Set[str]] = defaultdict(set)
|
|
49
|
+
for report in scout_reports:
|
|
50
|
+
scout_id = report.get("scout_id", 0)
|
|
51
|
+
for filepath in report.get("flagged_files", []):
|
|
52
|
+
scout_file_groups[scout_id].add(filepath)
|
|
53
|
+
|
|
54
|
+
# Check NPMI contracts between scout groups
|
|
55
|
+
contracts = invariants.get("contracts", [])
|
|
56
|
+
seen_connections = set()
|
|
57
|
+
for contract in contracts:
|
|
58
|
+
trigger = contract.get("trigger_file", "")
|
|
59
|
+
coupled = contract.get("coupled_file", "")
|
|
60
|
+
confidence = contract.get("confidence", 0)
|
|
61
|
+
|
|
62
|
+
if confidence < 0.5:
|
|
63
|
+
continue
|
|
64
|
+
|
|
65
|
+
trigger_scouts = set(file_scouts.get(trigger, []))
|
|
66
|
+
coupled_scouts = set(file_scouts.get(coupled, []))
|
|
67
|
+
|
|
68
|
+
if (trigger in all_files and coupled in all_files
|
|
69
|
+
and trigger_scouts != coupled_scouts
|
|
70
|
+
and not trigger_scouts & coupled_scouts):
|
|
71
|
+
key = tuple(sorted([trigger, coupled]))
|
|
72
|
+
if key not in seen_connections:
|
|
73
|
+
seen_connections.add(key)
|
|
74
|
+
hidden_connections.append({
|
|
75
|
+
"file_a": trigger,
|
|
76
|
+
"file_b": coupled,
|
|
77
|
+
"relation": "implicit_contract",
|
|
78
|
+
"confidence": confidence,
|
|
79
|
+
"note": (
|
|
80
|
+
f"Co-change rate {confidence:.0%}"
|
|
81
|
+
f" -- flagged by different scouts"
|
|
82
|
+
),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
# Check graph edges between scout groups
|
|
86
|
+
graph_files = graph.files if hasattr(graph, 'files') else {}
|
|
87
|
+
for file_a in all_files:
|
|
88
|
+
node = graph_files.get(file_a)
|
|
89
|
+
if not node:
|
|
90
|
+
continue
|
|
91
|
+
imports = getattr(node, 'imports', []) or []
|
|
92
|
+
for dep in imports:
|
|
93
|
+
if dep in all_files:
|
|
94
|
+
scouts_a = set(file_scouts.get(file_a, []))
|
|
95
|
+
scouts_b = set(file_scouts.get(dep, []))
|
|
96
|
+
if scouts_a and scouts_b and not scouts_a & scouts_b:
|
|
97
|
+
key = tuple(sorted([file_a, dep]))
|
|
98
|
+
if key not in seen_connections:
|
|
99
|
+
seen_connections.add(key)
|
|
100
|
+
hidden_connections.append({
|
|
101
|
+
"file_a": file_a,
|
|
102
|
+
"file_b": dep,
|
|
103
|
+
"relation": "direct_dependency",
|
|
104
|
+
"confidence": 1.0,
|
|
105
|
+
"note": f"{file_a} imports {dep}",
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
# 3. Blast radius: expand via NPMI to find strongly coupled files
|
|
109
|
+
proposed_blast_radius = set(all_files)
|
|
110
|
+
npmi_index = invariants.get("npmi_index", {})
|
|
111
|
+
for filepath in list(all_files):
|
|
112
|
+
coupled_files = npmi_index.get(filepath, {})
|
|
113
|
+
for partner, score in coupled_files.items():
|
|
114
|
+
if score >= 0.8 and partner not in all_files:
|
|
115
|
+
proposed_blast_radius.add(partner)
|
|
116
|
+
|
|
117
|
+
# 4. Confidence tiers
|
|
118
|
+
blast_by_confidence: Dict[str, List[str]] = {
|
|
119
|
+
"high": [], "medium": [], "low": [],
|
|
120
|
+
}
|
|
121
|
+
for filepath in proposed_blast_radius:
|
|
122
|
+
scouts = file_scouts.get(filepath, [])
|
|
123
|
+
if len(scouts) >= 2:
|
|
124
|
+
blast_by_confidence["high"].append(filepath)
|
|
125
|
+
elif len(scouts) == 1:
|
|
126
|
+
scout_confidence = next(
|
|
127
|
+
(r.get("confidence", 0.5)
|
|
128
|
+
for r in scout_reports
|
|
129
|
+
if r.get("scout_id") in scouts),
|
|
130
|
+
0.5,
|
|
131
|
+
)
|
|
132
|
+
if scout_confidence >= 0.7:
|
|
133
|
+
blast_by_confidence["medium"].append(filepath)
|
|
134
|
+
else:
|
|
135
|
+
blast_by_confidence["low"].append(filepath)
|
|
136
|
+
else:
|
|
137
|
+
# NPMI-expanded files (not flagged by any scout)
|
|
138
|
+
blast_by_confidence["low"].append(filepath)
|
|
139
|
+
|
|
140
|
+
for tier in blast_by_confidence.values():
|
|
141
|
+
tier.sort()
|
|
142
|
+
|
|
143
|
+
# 5. Scout agreement
|
|
144
|
+
unanimous = sorted(f for f, s in file_scouts.items() if len(s) == n_scouts and n_scouts > 1)
|
|
145
|
+
majority = sorted(
|
|
146
|
+
f for f, s in file_scouts.items()
|
|
147
|
+
if n_scouts > 1 and len(s) > n_scouts / 2 and len(s) < n_scouts
|
|
148
|
+
)
|
|
149
|
+
single = sorted(f for f, s in file_scouts.items() if len(s) == 1)
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
"convergence_points": convergence_points,
|
|
153
|
+
"hidden_connections": hidden_connections,
|
|
154
|
+
"proposed_blast_radius": sorted(proposed_blast_radius),
|
|
155
|
+
"blast_radius_by_confidence": blast_by_confidence,
|
|
156
|
+
"scout_agreement": {
|
|
157
|
+
"unanimous": unanimous,
|
|
158
|
+
"majority": majority,
|
|
159
|
+
"single": single,
|
|
160
|
+
},
|
|
161
|
+
}
|