dotscope 1.7.4__tar.gz → 1.7.7__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.7.4 → dotscope-1.7.7}/PKG-INFO +2 -2
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/__init__.py +1 -1
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/cli/__init__.py +4 -3
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/cli/ingest.py +1 -1
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/search.py +1 -1
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/__init__.py +28 -34
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/core.py +2 -2
- dotscope-1.7.7/dotscope/mcp/hooks.py +38 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/help.py +65 -7
- {dotscope-1.7.4 → dotscope-1.7.7}/pyproject.toml +2 -2
- dotscope-1.7.4/dotscope/mcp/hooks.py +0 -8
- {dotscope-1.7.4 → dotscope-1.7.7}/LICENSE +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/README.md +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/Cargo.lock +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/Cargo.toml +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/build.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/ast.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/bin/daemon.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/daemon.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/git.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/graph.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/ipc.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/lib.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/mmap.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/crates/dotscope-core/src/walk.rs +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/assets/ui/bundle.js +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/assets/ui/index.html +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/cli/core.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/cli/hooks.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/cli/observability.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/cli/serve.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/assertions.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/composer.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/constants.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/context.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/discovery.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/ignore.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/matcher.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/parser.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/resolver.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/runtime_overlay.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/scanner.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/tokens.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/engine/utility.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/eval/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/eval/bootstrap.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/eval/compare.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/eval/corpus.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/eval/harness.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/eval/replay.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/generate/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/generate/atlas.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/generate/contracts.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/generate/engine.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/generate/models.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/generate/network.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/ingest.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/logger.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/middleware.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/mvcc.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/observability.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/mcp/pipelines.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/classifier.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/composer.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/differ.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/driver.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/imports.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/models.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/merge/swarm.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/core.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/eval.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/history.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/intent.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/passes.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/models/state.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/ast_analyzer.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/backtest.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/budget_allocator.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/convention_compliance.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/convention_discovery.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/convention_parser.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/graph_builder.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/hint_generator.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/history_miner.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/incremental.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/_base.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/_treesitter.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/go.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/java.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/javascript.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/rust.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lang/solidity.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/lazy.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/preflight.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/semantic_diff.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/acknowledge.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checker.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/antipattern.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/boundary.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/contracts.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/convention.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/direction.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/intent.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/network.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/spatial.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/stability.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/checks/voice.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/constraints.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/line_filter.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/sentinel/models.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/spatial_autofix.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/virtual.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/voice.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/voice_defaults.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/voice_discovery.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/passes/z3_transpiler.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/paths/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/paths/repo.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/chunker.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/expander.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/flattener.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/models.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/observation.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/reranker.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/retriever.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/search/synthesizer.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/cache.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/claude_hooks.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/git_hooks.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/incremental_state.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/mcp_config.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/near_miss.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/onboarding.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/session_manager.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/swarm_state.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/storage/timing.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/bench.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/counterfactual.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/debug.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/explain.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/formatter.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/health.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/progress.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/textio.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/ux/visibility.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/__init__.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/absorber.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/ingest.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/intent.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/lessons.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/refresh.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/regression.py +0 -0
- {dotscope-1.7.4 → dotscope-1.7.7}/dotscope/workflows/sync.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dotscope
|
|
3
|
-
Version: 1.7.
|
|
3
|
+
Version: 1.7.7
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Topic :: Software Development :: Libraries
|
|
@@ -17,7 +17,7 @@ Requires-Dist: dotscope[mcp,tokens,search] ; extra == 'all'
|
|
|
17
17
|
Requires-Dist: pytest ; extra == 'dev'
|
|
18
18
|
Requires-Dist: ruff ; extra == 'dev'
|
|
19
19
|
Requires-Dist: sentence-transformers ; extra == 'embeddings'
|
|
20
|
-
Requires-Dist: mcp>=1.
|
|
20
|
+
Requires-Dist: mcp>=1.6.0,<3 ; extra == 'mcp'
|
|
21
21
|
Requires-Dist: sentence-transformers ; extra == 'search'
|
|
22
22
|
Requires-Dist: numpy ; extra == 'search'
|
|
23
23
|
Requires-Dist: tiktoken ; extra == 'tokens'
|
|
@@ -86,12 +86,13 @@ def main(argv=None):
|
|
|
86
86
|
sub.add_parser("health", help="Scope health: staleness, coverage, drift")
|
|
87
87
|
|
|
88
88
|
# --- sync ---
|
|
89
|
-
p_sync = sub.add_parser("sync", help="
|
|
90
|
-
p_sync.add_argument("scopes", nargs="*", help="Specific
|
|
89
|
+
p_sync = sub.add_parser("sync", help="Re-align .scope boundaries against the current import graph")
|
|
90
|
+
p_sync.add_argument("scopes", nargs="*", help="Specific scopes to sync (omit for entire repo)")
|
|
91
91
|
|
|
92
92
|
# --- ingest ---
|
|
93
93
|
p_ingest = sub.add_parser("ingest", help="Reverse-engineer .scope files from an existing codebase")
|
|
94
|
-
p_ingest.add_argument("
|
|
94
|
+
p_ingest.add_argument("directory", nargs="?", default=None, help="Repository root to ingest (default: current directory)")
|
|
95
|
+
p_ingest.add_argument("--dir", default=None, help="Repository root to ingest (alias for positional arg)")
|
|
95
96
|
p_ingest.add_argument("--no-history", action="store_true", help="Skip git history mining")
|
|
96
97
|
p_ingest.add_argument("--no-docs", action="store_true", help="Skip doc absorption")
|
|
97
98
|
p_ingest.add_argument("--dry-run", action="store_true", help="Plan only, don't write files")
|
|
@@ -21,7 +21,7 @@ def execute_semantic_search(root: str, query: str) -> str:
|
|
|
21
21
|
query
|
|
22
22
|
]
|
|
23
23
|
# Ignore case by default to maximize recall for the agent
|
|
24
|
-
cmd.insert(
|
|
24
|
+
cmd.insert(3, "-i")
|
|
25
25
|
|
|
26
26
|
result = subprocess.run(cmd, cwd=root, capture_output=True, text=True, timeout=15)
|
|
27
27
|
# 1 means no match, 0 means match. >1 is error
|
|
@@ -59,17 +59,17 @@ def main():
|
|
|
59
59
|
import contextlib
|
|
60
60
|
|
|
61
61
|
# Redirect stray stdout writes (from libraries, print() calls, etc.)
|
|
62
|
-
# to stderr so
|
|
62
|
+
# to stderr so only clean JSON-RPC flows over the stdio transport.
|
|
63
63
|
#
|
|
64
64
|
# How it works:
|
|
65
65
|
# 1. Save the real stdout fd (the MCP pipe to the client).
|
|
66
66
|
# 2. Point fd 1 and sys.stdout at stderr (captures stray output).
|
|
67
|
-
# 3. Build an
|
|
68
|
-
# 4.
|
|
69
|
-
#
|
|
70
|
-
#
|
|
71
|
-
#
|
|
72
|
-
#
|
|
67
|
+
# 3. Build an async file object from the saved fd.
|
|
68
|
+
# 4. Override FastMCP.run_stdio_async to pass the saved stdout
|
|
69
|
+
# into stdio_server(stdout=...) — its public API.
|
|
70
|
+
#
|
|
71
|
+
# This avoids monkeypatching internal module references, which break
|
|
72
|
+
# when FastMCP caches them via `from … import` at load time.
|
|
73
73
|
_isolated_stdout = None
|
|
74
74
|
try:
|
|
75
75
|
virgin_stdout_fd = os.dup(1)
|
|
@@ -97,35 +97,29 @@ def main():
|
|
|
97
97
|
known, _remaining = parser.parse_known_args()
|
|
98
98
|
_cli_root = known.root
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
#
|
|
100
|
+
mcp = FastMCP("dotscope")
|
|
101
|
+
|
|
102
|
+
# Override run_stdio_async to pass the isolated stdout directly into
|
|
103
|
+
# stdio_server's public `stdout=` parameter. This is stable across
|
|
104
|
+
# mcp versions — no module-level monkeypatching required.
|
|
103
105
|
if _isolated_stdout is not None:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
import anyio
|
|
108
|
-
from io import TextIOWrapper
|
|
109
|
-
|
|
110
|
-
_original_stdio_server = _mcp_stdio.stdio_server
|
|
111
|
-
|
|
112
|
-
@contextlib.asynccontextmanager
|
|
113
|
-
async def _patched_stdio_server(stdin=None, stdout=None):
|
|
114
|
-
if stdout is None:
|
|
115
|
-
stdout = anyio.wrap_file(
|
|
116
|
-
TextIOWrapper(_isolated_stdout, encoding="utf-8")
|
|
117
|
-
)
|
|
118
|
-
async with _original_stdio_server(stdin=stdin, stdout=stdout) as streams:
|
|
119
|
-
yield streams
|
|
120
|
-
|
|
121
|
-
# Patch both: the module attr (for anyone else importing it) and
|
|
122
|
-
# the local name inside fastmcp.server (the one that matters).
|
|
123
|
-
_mcp_stdio.stdio_server = _patched_stdio_server
|
|
124
|
-
_fastmcp_mod.stdio_server = _patched_stdio_server
|
|
125
|
-
except Exception as e:
|
|
126
|
-
print(f"dotscope warning: stdio patch failed: {e}", file=sys.stderr)
|
|
106
|
+
from mcp.server.stdio import stdio_server
|
|
107
|
+
import anyio
|
|
108
|
+
from io import TextIOWrapper
|
|
127
109
|
|
|
128
|
-
|
|
110
|
+
_mcp_stdout = anyio.wrap_file(
|
|
111
|
+
TextIOWrapper(_isolated_stdout, encoding="utf-8")
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
async def _run_stdio_with_isolated_stdout(self_ref=mcp):
|
|
115
|
+
async with stdio_server(stdout=_mcp_stdout) as (read_stream, write_stream):
|
|
116
|
+
await self_ref._mcp_server.run(
|
|
117
|
+
read_stream,
|
|
118
|
+
write_stream,
|
|
119
|
+
self_ref._mcp_server.create_initialization_options(),
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
mcp.run_stdio_async = _run_stdio_with_isolated_stdout
|
|
129
123
|
|
|
130
124
|
# Session-level tracker (lives across tool calls in a single MCP session)
|
|
131
125
|
from ..ux.visibility import SessionTracker
|
|
@@ -110,7 +110,7 @@ def register_core_tools(mcp, **kwargs):
|
|
|
110
110
|
|
|
111
111
|
index = load_resolution_index(root)
|
|
112
112
|
scopes = []
|
|
113
|
-
if index:
|
|
113
|
+
if index and index.scopes:
|
|
114
114
|
for name, entry in index.scopes.items():
|
|
115
115
|
scopes.append((name, entry.keywords, entry.description or ""))
|
|
116
116
|
else:
|
|
@@ -167,7 +167,7 @@ def register_core_tools(mcp, **kwargs):
|
|
|
167
167
|
scopes = []
|
|
168
168
|
index = load_resolution_index(root)
|
|
169
169
|
|
|
170
|
-
if index:
|
|
170
|
+
if index and index.scopes:
|
|
171
171
|
for name, entry in index.scopes.items():
|
|
172
172
|
scopes.append({
|
|
173
173
|
"name": name,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
def register_hooks_tools(mcp, **kwargs):
|
|
2
|
+
tracker = kwargs.get('tracker')
|
|
3
|
+
client_id = kwargs.get('client_id')
|
|
4
|
+
_root = kwargs.get('_root')
|
|
5
|
+
_repo_tokens = kwargs.get('_repo_tokens')
|
|
6
|
+
_cached_history = kwargs.get('_cached_history')
|
|
7
|
+
_cached_graph_hubs = kwargs.get('_cached_graph_hubs')
|
|
8
|
+
_cli_root = kwargs.get('_cli_root')
|
|
9
|
+
|
|
10
|
+
@mcp.tool()
|
|
11
|
+
def dotscope_sync(
|
|
12
|
+
scopes: list[str] | None = None,
|
|
13
|
+
root: str | None = None,
|
|
14
|
+
) -> str:
|
|
15
|
+
"""Synchronize .scope file boundaries against the current AST topology.
|
|
16
|
+
|
|
17
|
+
Re-scans the dependency graph and updates each .scope file's includes
|
|
18
|
+
and excludes to match the real imports. Preserves any lines marked
|
|
19
|
+
with ``# keep`` or ``# manual``. Non-destructive: context, description,
|
|
20
|
+
keywords, and related fields are never touched.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
scopes: Specific scope names to sync (omit for entire repo).
|
|
24
|
+
root: Repository root path (auto-detected if omitted).
|
|
25
|
+
"""
|
|
26
|
+
import json
|
|
27
|
+
from ..paths.repo import find_repo_root
|
|
28
|
+
from ..workflows.sync import sync_scopes
|
|
29
|
+
|
|
30
|
+
effective_root = root or _root or find_repo_root(_cli_root)
|
|
31
|
+
if effective_root is None:
|
|
32
|
+
return json.dumps({"error": "Could not find repository root"})
|
|
33
|
+
|
|
34
|
+
count = sync_scopes(effective_root, scopes)
|
|
35
|
+
return json.dumps({
|
|
36
|
+
"scopes_modified": count,
|
|
37
|
+
"message": f"Synchronized {count} scope(s)." if count else "All scopes already in sync.",
|
|
38
|
+
})
|
|
@@ -8,17 +8,25 @@ HELP_ROOT = """\
|
|
|
8
8
|
Usage: dotscope <command>
|
|
9
9
|
|
|
10
10
|
init One command: ingest, hooks, MCP config
|
|
11
|
-
resolve <scope> Serve context to an agent
|
|
11
|
+
resolve <scope> Serve files + context to an agent
|
|
12
|
+
context <scope> Architectural context only (no files)
|
|
13
|
+
match <task> Find matching scope for a task description
|
|
14
|
+
list List all scopes
|
|
12
15
|
check Verify routing (guards block, nudges guide)
|
|
13
|
-
conventions View and manage conventions
|
|
14
|
-
voice View and manage code style
|
|
15
16
|
health Scope staleness and drift
|
|
16
|
-
|
|
17
|
+
validate Check .scope files for broken paths
|
|
18
|
+
|
|
19
|
+
ingest . Reverse-engineer .scope files from codebase
|
|
20
|
+
sync Re-align .scope boundaries against import graph
|
|
21
|
+
refresh Reload runtime cache from disk
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
conventions View and manage conventions
|
|
24
|
+
voice View and manage code style
|
|
19
25
|
intent Declare architectural direction
|
|
20
|
-
diff --staged Semantic diff
|
|
21
|
-
|
|
26
|
+
diff --staged Semantic diff against conventions
|
|
27
|
+
impact <file> Predict blast radius of changes
|
|
28
|
+
|
|
29
|
+
hook install Install git hooks
|
|
22
30
|
bench Performance metrics
|
|
23
31
|
test-compiler Regression suite
|
|
24
32
|
debug --last Diagnose a bad session
|
|
@@ -188,10 +196,60 @@ Usage: dotscope refresh <action> [options]
|
|
|
188
196
|
Automatic refresh writes only to .dotscope/. Tracked .scope files stay stable
|
|
189
197
|
until you run dotscope ingest."""
|
|
190
198
|
|
|
199
|
+
HELP_SYNC = """\
|
|
200
|
+
Usage: dotscope sync [scopes...]
|
|
201
|
+
|
|
202
|
+
dotscope sync Re-align all .scope boundaries
|
|
203
|
+
dotscope sync auth payments Sync specific scopes only
|
|
204
|
+
|
|
205
|
+
Scans the AST dependency graph and updates each .scope file's includes
|
|
206
|
+
and excludes to match real imports. Lines marked # keep or # manual are
|
|
207
|
+
preserved. Context, description, and keywords are never touched."""
|
|
208
|
+
|
|
209
|
+
HELP_CONTEXT = """\
|
|
210
|
+
Usage: dotscope context <scope> [options]
|
|
211
|
+
|
|
212
|
+
dotscope context auth Full architectural context
|
|
213
|
+
dotscope context auth --section gotchas Specific section only
|
|
214
|
+
|
|
215
|
+
Options:
|
|
216
|
+
--section <name> Filter to a named section (invariants, gotchas, etc.)"""
|
|
217
|
+
|
|
218
|
+
HELP_MATCH = """\
|
|
219
|
+
Usage: dotscope match <task>
|
|
220
|
+
|
|
221
|
+
dotscope match "fix the auth token refresh bug"
|
|
222
|
+
dotscope match "add retry logic to API client"
|
|
223
|
+
|
|
224
|
+
Returns ranked scopes with confidence scores based on keyword overlap."""
|
|
225
|
+
|
|
226
|
+
HELP_VALIDATE = """\
|
|
227
|
+
Usage: dotscope validate
|
|
228
|
+
|
|
229
|
+
dotscope validate Check all .scope files
|
|
230
|
+
|
|
231
|
+
Checks:
|
|
232
|
+
- Include paths exist on disk
|
|
233
|
+
- Related scope files exist
|
|
234
|
+
- Description is not empty
|
|
235
|
+
- Context field is present"""
|
|
236
|
+
|
|
237
|
+
HELP_IMPACT = """\
|
|
238
|
+
Usage: dotscope impact <file>
|
|
239
|
+
|
|
240
|
+
dotscope impact auth/tokens.py Show blast radius
|
|
241
|
+
|
|
242
|
+
Returns direct dependents, two-hop dependents, and co-change companions."""
|
|
243
|
+
|
|
191
244
|
HELP_COMMANDS = {
|
|
192
245
|
"ingest": HELP_INGEST,
|
|
193
246
|
"resolve": HELP_RESOLVE,
|
|
247
|
+
"context": HELP_CONTEXT,
|
|
248
|
+
"match": HELP_MATCH,
|
|
194
249
|
"check": HELP_CHECK,
|
|
250
|
+
"sync": HELP_SYNC,
|
|
251
|
+
"validate": HELP_VALIDATE,
|
|
252
|
+
"impact": HELP_IMPACT,
|
|
195
253
|
"intent": HELP_INTENT,
|
|
196
254
|
"conventions": HELP_CONVENTIONS,
|
|
197
255
|
"diff": HELP_DIFF,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dotscope"
|
|
3
|
-
version = "1.7.
|
|
3
|
+
version = "1.7.7"
|
|
4
4
|
description = "Agents see files. You see architecture. dotscope gives agents the architecture."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -26,7 +26,7 @@ dependencies = [
|
|
|
26
26
|
]
|
|
27
27
|
|
|
28
28
|
[project.optional-dependencies]
|
|
29
|
-
mcp = ["mcp>=1.
|
|
29
|
+
mcp = ["mcp>=1.6.0,<3"]
|
|
30
30
|
tokens = ["tiktoken"]
|
|
31
31
|
embeddings = ["sentence-transformers"]
|
|
32
32
|
search = ["sentence-transformers", "numpy"]
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
def register_hooks_tools(mcp, **kwargs):
|
|
2
|
-
tracker = kwargs.get('tracker')
|
|
3
|
-
client_id = kwargs.get('client_id')
|
|
4
|
-
_root = kwargs.get('_root')
|
|
5
|
-
_repo_tokens = kwargs.get('_repo_tokens')
|
|
6
|
-
_cached_history = kwargs.get('_cached_history')
|
|
7
|
-
_cached_graph_hubs = kwargs.get('_cached_graph_hubs')
|
|
8
|
-
_cli_root = kwargs.get('_cli_root')
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|