descry-codegraph 0.1.0__tar.gz → 0.2.0__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.
- descry_codegraph-0.2.0/.github/assets/01-landing.png +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/.github/workflows/ci.yml +6 -1
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/.github/workflows/release.yml +6 -1
- descry_codegraph-0.2.0/CHANGELOG.md +369 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/CLAUDE.md +3 -3
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/PKG-INFO +60 -26
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/README.md +59 -25
- descry_codegraph-0.2.0/claude-skill/README.md +112 -0
- descry_codegraph-0.2.0/claude-skill/descry/SKILL.md +251 -0
- descry_codegraph-0.2.0/claude-skill/descry/references/cli-reference.md +154 -0
- descry_codegraph-0.2.0/claude-skill/descry/references/mcp-tools.md +75 -0
- descry_codegraph-0.2.0/claude-skill/descry/references/recipes.md +154 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/pyproject.toml +1 -1
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/__init__.py +1 -1
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/_graph.py +1 -1
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/ast_grep.py +34 -28
- descry_codegraph-0.2.0/src/descry/clang_parser.py +443 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/cli.py +2 -2
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/cross_lang.py +5 -138
- descry_codegraph-0.2.0/src/descry/dart_parser.py +451 -0
- descry_codegraph-0.2.0/src/descry/dotnet_parser.py +418 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/embeddings.py +8 -47
- descry_codegraph-0.2.0/src/descry/generate.py +8417 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/git_history.py +9 -9
- descry_codegraph-0.2.0/src/descry/go_parser.py +382 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/handlers.py +200 -45
- descry_codegraph-0.2.0/src/descry/java_parser.py +336 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/mcp_server.py +7 -2
- descry_codegraph-0.2.0/src/descry/php_parser.py +367 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/query.py +24 -38
- descry_codegraph-0.2.0/src/descry/ruby_parser.py +328 -0
- descry_codegraph-0.2.0/src/descry/scip/adapter.py +209 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/__init__.py +23 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/_java_compat.init.gradle +21 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/clang.py +190 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/dart.py +143 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/dotnet.py +279 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/go.py +152 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/java.py +343 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/php.py +272 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/python.py +137 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/ruby.py +140 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/rust.py +216 -0
- descry_codegraph-0.2.0/src/descry/scip/adapters/typescript.py +295 -0
- descry_codegraph-0.2.0/src/descry/scip/cache.py +753 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/scip/parser.py +58 -153
- descry_codegraph-0.2.0/src/descry/scip/support.py +70 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/web/server.py +82 -48
- descry_codegraph-0.2.0/tests/test_clang_parser.py +160 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_config.py +42 -0
- descry_codegraph-0.2.0/tests/test_dart_parser.py +216 -0
- descry_codegraph-0.2.0/tests/test_dotnet_parser.py +241 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_generate.py +1 -1
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_git_history.py +61 -0
- descry_codegraph-0.2.0/tests/test_go_parser.py +261 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_handlers.py +1 -2
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_hardening.py +1 -1
- descry_codegraph-0.2.0/tests/test_java_parser.py +242 -0
- descry_codegraph-0.2.0/tests/test_php_parser.py +227 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_query.py +3 -3
- descry_codegraph-0.2.0/tests/test_ruby_parser.py +228 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_scip.py +121 -23
- descry_codegraph-0.2.0/tests/test_scip_clang.py +106 -0
- descry_codegraph-0.2.0/tests/test_scip_dart.py +96 -0
- descry_codegraph-0.2.0/tests/test_scip_dotnet.py +83 -0
- descry_codegraph-0.2.0/tests/test_scip_go.py +128 -0
- descry_codegraph-0.2.0/tests/test_scip_java.py +306 -0
- descry_codegraph-0.2.0/tests/test_scip_php.py +72 -0
- descry_codegraph-0.2.0/tests/test_scip_ruby.py +81 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_web_server.py +1 -1
- descry_codegraph-0.1.0/CHANGELOG.md +0 -30
- descry_codegraph-0.1.0/src/descry/generate.py +0 -3579
- descry_codegraph-0.1.0/src/descry/scip/cache.py +0 -1047
- descry_codegraph-0.1.0/src/descry/scip/support.py +0 -174
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/.gitignore +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/LICENSE +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/SECURITY.md +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/justfile +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/pi-extension/README.md +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/pi-extension/descry-cli.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/pi-extension/descry-tools.ts +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/_env.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/scip/__init__.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/scip/pb2.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/tree_sitter_parser.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/web/__init__.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/web/web/index.html +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/src/descry/web/web/style.css +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/__init__.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/conftest.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/fixtures/small_graph.json +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_cli.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_mcp.py +0 -0
- {descry_codegraph-0.1.0 → descry_codegraph-0.2.0}/tests/test_tree_sitter_parser.py +0 -0
|
Binary file
|
|
@@ -73,4 +73,9 @@ jobs:
|
|
|
73
73
|
- name: Audit resolved environment
|
|
74
74
|
run: |
|
|
75
75
|
. .venv/bin/activate
|
|
76
|
-
|
|
76
|
+
# CVE-2026-3219 (GHSA-58qw-9mgm-455v): concatenated tar/ZIP
|
|
77
|
+
# interpretation conflict in pip itself. Affects pip <= 26.0.1
|
|
78
|
+
# with no patched version upstream. pip is a build-time
|
|
79
|
+
# installer in the venv, not a runtime dep we ship.
|
|
80
|
+
# Re-evaluate when pip ships a fix.
|
|
81
|
+
pip-audit --skip-editable --ignore-vuln CVE-2026-3219
|
|
@@ -70,7 +70,12 @@ jobs:
|
|
|
70
70
|
- name: Audit resolved environment
|
|
71
71
|
run: |
|
|
72
72
|
. .venv/bin/activate
|
|
73
|
-
|
|
73
|
+
# CVE-2026-3219 (GHSA-58qw-9mgm-455v): concatenated tar/ZIP
|
|
74
|
+
# interpretation conflict in pip itself. Affects pip <= 26.0.1
|
|
75
|
+
# with no patched version upstream. pip is a build-time
|
|
76
|
+
# installer in the venv, not a runtime dep we ship.
|
|
77
|
+
# Re-evaluate when pip ships a fix.
|
|
78
|
+
pip-audit --skip-editable --ignore-vuln CVE-2026-3219
|
|
74
79
|
|
|
75
80
|
publish-testpypi:
|
|
76
81
|
name: Publish to TestPyPI
|
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to Descry will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to pre-1.0 semver (minor-version bumps may include breaking changes; see README versioning stance).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.2.0] — 2026-04-20
|
|
10
|
+
|
|
11
|
+
A large feature + resolution-quality release. Seven new SCIP language
|
|
12
|
+
adapters land (Java/Kotlin/Scala, Go, Ruby, PHP, C#/VB, C/C++, Dart)
|
|
13
|
+
alongside a language-general STDLIB_FILTER sweep that brought CALLS
|
|
14
|
+
resolution above 90% on 20 of 26 measured corpora. The release also
|
|
15
|
+
folds in a full session of convergence-audit hardening: user-input
|
|
16
|
+
parsing no longer 500s on garbage query strings, subprocess output
|
|
17
|
+
tolerates non-UTF-8 bytes, and the documented security invariants match
|
|
18
|
+
what the code actually does.
|
|
19
|
+
|
|
20
|
+
Graph schema stays at v1 — existing `.descry_cache/codebase_graph.json`
|
|
21
|
+
files remain readable. CLI subcommands and MCP tool names are unchanged
|
|
22
|
+
(19 of each, 1:1 parity).
|
|
23
|
+
|
|
24
|
+
### Added
|
|
25
|
+
|
|
26
|
+
- **Dart / Flutter support** via `scip-dart` (Milestone D). DartAdapter
|
|
27
|
+
discovers projects by `pubspec.yaml` at the root or under
|
|
28
|
+
`packages/*` (melos / workspace layout); runs `scip-dart ./` from the
|
|
29
|
+
package root and uses `output_mode="rename"` to move the emitted
|
|
30
|
+
`index.scip` into the cache. DartParser handles imports
|
|
31
|
+
(`package:` / `dart:` / relative), classes (including `abstract`,
|
|
32
|
+
`base`, `sealed`, `final`, `interface class`, `mixin class`), mixins,
|
|
33
|
+
extensions, enums, typedefs, top-level constants, class inheritance
|
|
34
|
+
(`extends` → INHERITS edge), and call sites with null-safe receiver
|
|
35
|
+
chains (`?.method()`). Dart has heavy top-level code (top-level
|
|
36
|
+
functions, top-level variable initializers), so the parser emits
|
|
37
|
+
calls at file scope too — unlike Java/C# parsers which gate calls on
|
|
38
|
+
non-file context. pub smoke test hit **71%** resolution
|
|
39
|
+
(10,279 / 14,490 CALLS edges) — below the 91.2% Rust bar, accepted
|
|
40
|
+
as the Dart ceiling for test-heavy codebases where pub's internal
|
|
41
|
+
test-helper DSL (`servePackages`, `d.file`, `runPub`, etc.) contributes
|
|
42
|
+
the bulk of unresolved calls.
|
|
43
|
+
- **Java / Kotlin / Scala support** via `scip-java` (Milestone J of Wave 2).
|
|
44
|
+
JavaParser extracts classes, interfaces, enums, records, methods,
|
|
45
|
+
constructors, fields, imports, and call sites. JavaAdapter ships a
|
|
46
|
+
Gradle init-script that strips `-Werror` so scip-java works out of the
|
|
47
|
+
box on Apache projects (Kafka, etc.) whose builds treat warnings as
|
|
48
|
+
fatal. Kafka smoke test hit **92.7%** CALLS resolution.
|
|
49
|
+
- **Go support** via `scip-go` (Milestone G). GoParser covers packages,
|
|
50
|
+
grouped imports, type declarations, free functions, methods with
|
|
51
|
+
receivers, const/var blocks, and call sites. Kubernetes smoke test
|
|
52
|
+
hit **98.3%** resolution.
|
|
53
|
+
- **Ruby support** via `scip-ruby` (Milestone R). RubyParser uses
|
|
54
|
+
indent-based context tracking (Ruby uses `end` not `}`); extracts
|
|
55
|
+
classes with INHERITS edges, modules, methods (including `self.foo`,
|
|
56
|
+
`foo?`, `foo!`), `attr_reader/writer/accessor`, `require` /
|
|
57
|
+
`require_relative`, and top-level constants. Rails smoke test hit
|
|
58
|
+
**87.8%** — below the 91.2% Rust bar, accepted as the Ruby-without-
|
|
59
|
+
Sorbet ceiling (scip-ruby falls back to `# typed: false` heuristics
|
|
60
|
+
when Sorbet annotations are absent).
|
|
61
|
+
- **PHP support** via `scip-php` (Milestone P, third-party indexer by
|
|
62
|
+
davidrjenni). PhpParser handles namespaces, classes / interfaces /
|
|
63
|
+
traits / enums, `public/protected/private function`, properties,
|
|
64
|
+
constants, and method / static / instance calls; Allman-brace lookahead
|
|
65
|
+
(scan up to 10 lines for the opening `{`) was needed for Laravel's
|
|
66
|
+
style. Laravel smoke test hit **88.6%**.
|
|
67
|
+
- **C# / VB.NET support** via `scip-dotnet` (Milestone N). DotnetAdapter
|
|
68
|
+
sets `DOTNET_ROLL_FORWARD=LatestMajor` so scip-dotnet's net9 target
|
|
69
|
+
runs on systems with only net10 installed. Serilog smoke test hit
|
|
70
|
+
**83.7%**.
|
|
71
|
+
- **C / C++ support** via `scip-clang` (Milestone C). ClangAdapter emits
|
|
72
|
+
scheme `cxx` (verified from real indexes; not `scip-clang` as a name
|
|
73
|
+
might suggest). Discovery gives top priority to root-level
|
|
74
|
+
`compile_commands.json` so Bear-backed Makefile builds and top-level
|
|
75
|
+
CMake projects work as a single unit. ClangParser avoids regex
|
|
76
|
+
catastrophic backtracking (which hit >20s on Redis `src/dict.c` in
|
|
77
|
+
an early draft) via a hand-rolled `_extract_function_name` that scans
|
|
78
|
+
right-to-left through the argument list. Redis smoke test hit
|
|
79
|
+
**79.2%**; headers lag .c files (63.3% vs 81.2%) due to scip-clang
|
|
80
|
+
compdb-coverage limits on transitively-included headers.
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
|
|
84
|
+
- **CALLS resolution rose above the 90% bar on 20 of 26 measured
|
|
85
|
+
corpora** (up from ~10 pre-sweep) via a focused language-general
|
|
86
|
+
filter pass — zero codebase-specific entries. The sweep expanded
|
|
87
|
+
`STDLIB_FILTER` / `STDLIB_PREFIXES` across every supported language:
|
|
88
|
+
- **TypeScript / JavaScript**: `_JSTS_CONTROL_KEYWORDS` filter in
|
|
89
|
+
the `TSParser` regex fallback (rejects `if(`, `while(`, `for(`,
|
|
90
|
+
`switch(` captures — removes ~37k spurious unresolved on the
|
|
91
|
+
TypeScript compiler alone), tslib emit helpers (`__awaiter`,
|
|
92
|
+
`__generator`, `__rest`, `__spreadArray`, `__classPrivateFieldGet`,
|
|
93
|
+
`__addDisposableResource`, …), DOM APIs (`textContent`,
|
|
94
|
+
`getAttribute`, `classList`, `appendChild`, …), Array/Object
|
|
95
|
+
statics (`isArray`, `fromEntries`, `defineProperty`, …),
|
|
96
|
+
Playwright (`page.*`), Vitest/Jest todo / only / each / snapshot
|
|
97
|
+
modifiers, React core hooks + TanStack Query + Node `assert`
|
|
98
|
+
strict variants + Lingui / nanoid / uuid.* / date-fns / RN-Expo
|
|
99
|
+
surface. ast-grep now rejects `$FUNC` captures that include parens
|
|
100
|
+
or non-identifier characters (stops curried-call shape like
|
|
101
|
+
`test.runIf(isBuild)(…)` from polluting CALLS targets).
|
|
102
|
+
- **C#**: `var` added to `_DOTNET_CONTROL_KEYWORDS` (fixes ~1k/file
|
|
103
|
+
spurious `var (` captures on modern C# codebases) along with the
|
|
104
|
+
full modern declaration vocabulary (`record`, `partial`, `sealed`,
|
|
105
|
+
`override`, `static`, `params`, `required`, `scoped`, `file`,
|
|
106
|
+
`global`) and every primitive alias (`object`, `string`, `bool`,
|
|
107
|
+
`int`, `long`, `byte`, `char`, `float`, `double`, `decimal`,
|
|
108
|
+
`nint`, `nuint`). Moq (`It.IsAny`, `Mock.Of`, `Setup`, `Verify`,
|
|
109
|
+
`ReturnsAsync`), FakeItEasy (`A.CallTo`, `A.Fake`, `A.Dummy`),
|
|
110
|
+
ASP.NET Core DI (`Add*`, `Use*`, `Map*`, `GetRequiredService`),
|
|
111
|
+
.NET Reflection + Span/Memory, `System.String` statics, Selenium
|
|
112
|
+
WebDriver.
|
|
113
|
+
- **Java**: AssertJ (full `assertThat*` surface, `hasCauseInstanceOf`,
|
|
114
|
+
`isThrownBy`, `satisfies`), BDDMockito (`given`, `willReturn`,
|
|
115
|
+
`willThrow`), Project Reactor (`StepVerifier`, `expectNext`,
|
|
116
|
+
`flatMap`, `switchIfEmpty`, `subscribeOn`), Mockito static
|
|
117
|
+
(`mockStatic`, `mockConstruction`, `invocation.getArgument`),
|
|
118
|
+
Hamcrest matcher vocabulary, Apache Lucene types, ANTLR-generated
|
|
119
|
+
runtime, `java.time` / `java.util.Properties` / `java.nio.Buffer`
|
|
120
|
+
/ `java.io.File`, `java.sql.*` + `java.util.Locale.*`,
|
|
121
|
+
`jakarta.servlet` + `javax.xml.sax`, reflection extras.
|
|
122
|
+
- **Go**: `encoding/binary` (`BigEndian/LittleEndian.Uint*/PutUint*`),
|
|
123
|
+
`sync` lock methods (`Lock`, `Unlock`, `RLock`, `RUnlock`,
|
|
124
|
+
`Add`/`Done`/`Wait`), `bytes.Buffer` + `strings.Builder` common
|
|
125
|
+
methods, `golang.org/x/sync/errgroup`, `go.uber.org/goleak`,
|
|
126
|
+
AWS SDK v2 helpers (`aws.Int32`, `aws.String`, …), ULID,
|
|
127
|
+
`klog.`/`ginkgo.`/`Gomega.`/`testify.` prefixes.
|
|
128
|
+
- **Rust**: clap CLI (`value_name`, `help_heading`, `get_one`,
|
|
129
|
+
`get_flag`, `long_about`, subcommand builders), snapbox test
|
|
130
|
+
(`stdout_eq`, `stderr_eq`, `subset_matches`), integer arithmetic
|
|
131
|
+
(`wrapping_*`, `saturating_*`, `checked_*`, `overflowing_*`,
|
|
132
|
+
`rotate_*`, `count_ones`/`_zeros`), atomic compare-exchange /
|
|
133
|
+
fetch variants, pointer `as_ptr`/`as_mut_ptr`/`copy_nonoverlapping`/
|
|
134
|
+
`read_volatile`, slice `is_ascii_*`/`split_whitespace`/
|
|
135
|
+
`char_indices`, fd `from_raw_fd`/`as_raw_fd`/`borrow_raw`.
|
|
136
|
+
- **C / C++**: TCL C API (`Tcl_*` prefix — sqlite bindings),
|
|
137
|
+
LLVM C API (`LLVM*` — postgres JIT), CPython C API (`Py_*`,
|
|
138
|
+
`PyObject_*`, `PyDict_*`, …), Win32 C API (`CreateFile`,
|
|
139
|
+
`GetLastError`, `LoadLibrary`, registry, `HeapAlloc`, …), POSIX
|
|
140
|
+
pthread full surface (`pthread_mutex_*`, `pthread_cond_*`,
|
|
141
|
+
`pthread_rwlock_*`, `pthread_spin_*`, `pthread_barrier_*`),
|
|
142
|
+
stdarg (`va_start`, `va_end`, `va_arg`, `va_copy`), C11
|
|
143
|
+
stdatomic, BSD-specific strings (`strlcpy`, `strlcat`, `arc4random_*`,
|
|
144
|
+
`reallocarray`), BSD socket byte-order (`ntohs`, `htonl`, …) +
|
|
145
|
+
full socket API, OpenSSL (`BN_`, `HMAC_`, `EC_KEY_`, `ENGINE_`),
|
|
146
|
+
jemalloc (public `mallocx`/`xallocx`/`rallocx`/`sallocx`/
|
|
147
|
+
`dallocx`/`nallocx` + internals `edata_`, `emap_`, `sz_`, `pa_`,
|
|
148
|
+
`hpa_`, `prof_`, `tsd_`, `tsdn_`, `atomic_*_zu`).
|
|
149
|
+
- **PHP**: PHPUnit `assertIs*` full surface + PHPUnit:: qualified
|
|
150
|
+
variants, Mockery extras (`makePartial`, `withArgs`), Carbon +
|
|
151
|
+
PHP `DateTime` full method set, `version_compare`, binary /
|
|
152
|
+
encoding / output stdlib (`pack`, `unpack`, `bin2hex`,
|
|
153
|
+
`curl_setopt_array`, `ob_start`/`ob_end_flush`, `strspn`, `strtr`,
|
|
154
|
+
`addslashes`), PSR-7 HTTP helpers (`getStatusCode`, `withHeader`,
|
|
155
|
+
`withBody`, `getUri`).
|
|
156
|
+
- **Ruby**: Full `String` / `Enumerable` / `Hash` / `IO` method
|
|
157
|
+
surface (`gsub`, `scan`, `end_with?`, `is_a?`, `key?`, `sysread`,
|
|
158
|
+
`each_with_object`, `tally`, …), `SecureRandom`/`Addrinfo`/
|
|
159
|
+
`Socket`/`TCP*`/`UDP*`/`UNIX*`/`IPAddr`/`Resolv`/`Zlib`/`CGI`/
|
|
160
|
+
`ERB`/`Liquid::` prefixes, JRuby Java-side API (`RubyString.`,
|
|
161
|
+
`RubyArray.`, `RubyHash.`, `ByteList.`, `ThreadContext.`, …) +
|
|
162
|
+
bare `newString`, `newFixnum`, `callMethod`, `getRuntime`.
|
|
163
|
+
- **Dart**: `package:test_descriptor` (`d.file`, `d.dir`,
|
|
164
|
+
`d.nothing`), `package:test_process` (`shouldExit`), `dart:typed_data`
|
|
165
|
+
fromList constructors, `dart:convert` (`JsonEncoder`, `Utf8Decoder`,
|
|
166
|
+
`LineSplitter`), `package:shelf` Response helpers, `package:args`
|
|
167
|
+
CLI builders (`addFlag`, `addOption`, `addSubcommand`,
|
|
168
|
+
`wasParsed`), `package:yaml` loaders, Dart SDK error types
|
|
169
|
+
(`StateError`, `UnsupportedError`, `FormatException`, …),
|
|
170
|
+
pub_semver (`Version`, `VersionConstraint`).
|
|
171
|
+
- **`is_non_project_call` now splits on `->` in addition to `.` and
|
|
172
|
+
`::`** so PHP `$obj->method()` and C `struct_ptr->method()` resolve
|
|
173
|
+
their bare method name against `STDLIB_FILTER` — previously
|
|
174
|
+
`headers->set`, `response->getStatusCode` never matched. Laravel /
|
|
175
|
+
Symfony resolution climbed 88% → 91%.
|
|
176
|
+
|
|
177
|
+
### Fixed
|
|
178
|
+
|
|
179
|
+
- **SCIP incremental re-indexing** no longer silently degrades to zero
|
|
180
|
+
for adapters outside rust / typescript / python. `_hash_project` now
|
|
181
|
+
falls back to `_hash_generic_adapter` (walks the adapter's declared
|
|
182
|
+
extensions + hashes paths + bytes) for java / go / ruby / php /
|
|
183
|
+
dotnet / clang / dart, instead of raising `ValueError: Unknown project
|
|
184
|
+
type`. Before this fix, every second+ index produced a `.scip`-less
|
|
185
|
+
graph that looked successful in logs but had no SCIP-resolved CALLS
|
|
186
|
+
edges.
|
|
187
|
+
- **SCIP Strategy 1 name match.** `ScipIndex.resolve`'s exact
|
|
188
|
+
(file, line) lookup used to fall back to the first candidate in the
|
|
189
|
+
definitions map when no name matched. Downstream, the cross-crate
|
|
190
|
+
name check in `generate.py` would reject those mismatched targets,
|
|
191
|
+
but by then Strategy 2 (fuzzy resolve by name) had already been
|
|
192
|
+
skipped. Tighten Strategy 1 to require a name match; non-matching
|
|
193
|
+
line lookups now fall through to fuzzy. Measured: pub Dart 52% →
|
|
194
|
+
71%, Redis C 79.2% → 80.4%.
|
|
195
|
+
- **`changes` no longer crashes on non-UTF-8 git diff output.**
|
|
196
|
+
`GitHistoryAnalyzer._run_git` previously used `subprocess.run(text=True)`
|
|
197
|
+
which raises `UnicodeDecodeError` the moment `git diff` emits a byte
|
|
198
|
+
that isn't valid UTF-8 (observed on c-postgres — byte 0x92 — and
|
|
199
|
+
rust-coreutils — byte 0xfd, both carrying Latin-1 content in older
|
|
200
|
+
source files). All subprocess callers that capture stdout/stderr
|
|
201
|
+
(`git_history.py`, `scip/cache.py`, `scip/adapter.py`, `ast_grep.py`)
|
|
202
|
+
now decode with `encoding="utf-8", errors="replace"` so a stray
|
|
203
|
+
non-UTF-8 byte becomes `U+FFFD` instead of aborting the tool.
|
|
204
|
+
Regression: `tests/test_git_history.py::TestGitHistoryNonUtf8Output`
|
|
205
|
+
seeds a throwaway repo with 0x92 / 0xfd bytes and asserts
|
|
206
|
+
`_run_git` + `get_changes` stay clean.
|
|
207
|
+
- **User-input numeric parsing is crash-safe.** The web API's
|
|
208
|
+
`?limit=foo` / `?depth=bar` inputs and the `DESCRY_SCIP_WORKERS` /
|
|
209
|
+
`DESCRY_PRIME_THREADS` / `DESCRY_SCIP_TIMEOUT` env-var overrides
|
|
210
|
+
previously called `int(raw)` directly; a non-integer value raised
|
|
211
|
+
`ValueError` and surfaced as a 500 (web) or a hard crash during
|
|
212
|
+
SCIP cache init (env var). Web handlers now go through the new
|
|
213
|
+
`_int_param(request, name, default)` helper that returns the
|
|
214
|
+
default on parse failure; env-var paths catch `ValueError`, log a
|
|
215
|
+
warning, and fall through to the auto-tuned default.
|
|
216
|
+
- **Exception chains preserved on re-raise.** Three sites in
|
|
217
|
+
`git_history.py` and one in `embeddings.py` re-raised exceptions
|
|
218
|
+
without `from err` / `from None`, which hid the underlying cause in
|
|
219
|
+
tracebacks. Now `FileNotFoundError` → `GitError("git not found")` /
|
|
220
|
+
`TimeoutExpired` → `GitError("timed out")` / `FileExistsError` →
|
|
221
|
+
`TimeoutError("embeddings lock")` all use `from None` (cause
|
|
222
|
+
already captured in the message), and `_verify_git`'s internal
|
|
223
|
+
re-raise uses `from err` to preserve the inner git failure.
|
|
224
|
+
- **`descry.__version__` matches `pyproject.toml`.** Since the 0.1.1
|
|
225
|
+
tag, the package version string was `"0.1.0"` in `__init__.py` but
|
|
226
|
+
`"0.1.1"` in `pyproject.toml`, so `descry health` reported the
|
|
227
|
+
wrong version. Bumped `__init__.py` and added this to the release
|
|
228
|
+
gate so a future mismatch is caught before tagging.
|
|
229
|
+
- **Documented security invariants now match the code.** `CLAUDE.md`
|
|
230
|
+
said `descry-web` "allows CORS `*`"; in reality the code omits
|
|
231
|
+
`CORSMiddleware` entirely so browsers enforce same-origin by
|
|
232
|
+
default (with `TrustedHostMiddleware` defeating DNS-rebinding).
|
|
233
|
+
The subprocess-sanitization list also named only `scip-typescript`
|
|
234
|
+
as the representative SCIP indexer — now enumerates all ten.
|
|
235
|
+
- **Implicit-`Optional` annotations in `query.py` made explicit.**
|
|
236
|
+
11 signatures across `flow` / `trace_flow_structured` /
|
|
237
|
+
`get_context_prompt` / `find_trait_impls` used `x: int = None`
|
|
238
|
+
(which PEP 484 prohibits); now `int | None = None`.
|
|
239
|
+
- **Pure-JavaScript repos no longer drop every CALLS edge.** ast-grep
|
|
240
|
+
has separate `typescript` and `javascript` grammars; the
|
|
241
|
+
`extract_calls_typescript` / `extract_imports_typescript` helpers
|
|
242
|
+
hardcoded `-l typescript` for the subprocess, which returns no
|
|
243
|
+
matches when fed `.js` / `.jsx` / `.mjs` / `.cjs`. Caught by the
|
|
244
|
+
pre-publish corpus sweep against express (100% .js): scip-typescript
|
|
245
|
+
emitted 9,702 references but the graph had **0 CALLS edges**. New
|
|
246
|
+
`_ast_grep_lang_for(file_path)` routes to `javascript` for JS-family
|
|
247
|
+
extensions; express now resolves 58% of CALLS (graph went 1,353 →
|
|
248
|
+
6,117 edges). 0.1.x users on pure-JS repos were silently affected.
|
|
249
|
+
|
|
250
|
+
### Changed
|
|
251
|
+
|
|
252
|
+
- **Configuration docs now cover every parsed field.** README's
|
|
253
|
+
`[cross_lang]` TOML section (with `openapi_path`,
|
|
254
|
+
`backend_handler_patterns`, `frontend_api_patterns`, `api_prefixes`)
|
|
255
|
+
and `[timeouts] index_minutes` were parsed at runtime but undocumented;
|
|
256
|
+
added. Four `DESCRY_*` env vars (`SCIP_WORKERS`, `SCIP_TIMEOUT`,
|
|
257
|
+
`PRIME_THREADS`, `AST_GREP_MAX_FILES`) were honoured by the code but
|
|
258
|
+
missing from the environment-variables table; added.
|
|
259
|
+
|
|
260
|
+
### Known limitations (surfaced by the pre-publish corpus sweep)
|
|
261
|
+
|
|
262
|
+
These aren't regressions in 0.2.0 — they're scenarios the new corpus
|
|
263
|
+
coverage made visible. Documenting so users know what to expect.
|
|
264
|
+
|
|
265
|
+
- **Kotlin codebases need scip-java to be useful.** Descry has no
|
|
266
|
+
`.kt` / `.scala` parser baseline; Kotlin and Scala source files are
|
|
267
|
+
walked by the file walker but produce no nodes when scip-java
|
|
268
|
+
doesn't run. scip-java in turn fails on Kotlin-DSL Gradle projects
|
|
269
|
+
that use precompiled-script-plugins (observed on both `ktorio/ktor`
|
|
270
|
+
and `Kotlin/kotlinx.coroutines` — same upstream task-ordering
|
|
271
|
+
error). Practical effect: pure-Kotlin repos with that build
|
|
272
|
+
pattern will produce a near-empty graph. Mixed Java+Kotlin repos
|
|
273
|
+
index the Java side only. The `JavaAdapter` now pre-flights for
|
|
274
|
+
this scenario and skips scip-java with a clear log message
|
|
275
|
+
("scip-java incompatibility: kotlin-dsl precompiled-script-plugins
|
|
276
|
+
in <path>") instead of a confusing 1100-byte stderr dump from the
|
|
277
|
+
failed Gradle invocation. Detection covers `buildSrc/` and any
|
|
278
|
+
`includeBuild()` participants in `settings.gradle{,.kts}`.
|
|
279
|
+
- **C++ resolution ceiling without scip-clang.** scip-clang requires
|
|
280
|
+
a working `compile_commands.json` with all transitive deps
|
|
281
|
+
available (Boost, gflags, glog, fmt, etc. for `facebook/folly`).
|
|
282
|
+
When deps are missing scip-clang is skipped and the regex
|
|
283
|
+
`ClangParser` baseline reaches ~46–54% on modern template-heavy
|
|
284
|
+
C++ (folly 46%, abseil-cpp 54%). With a working compdb scip-clang
|
|
285
|
+
contributes ~40% of resolved CALLS; the rest is regex fallback.
|
|
286
|
+
Plain C codebases (redis, sqlite, postgres, curl) sit at 72–80%
|
|
287
|
+
on regex baseline alone.
|
|
288
|
+
- **scip-java does not support Ant.** Maven, Gradle, sbt, and Mill
|
|
289
|
+
are supported; Ant projects (e.g. `apache/cassandra`) fall back
|
|
290
|
+
to the regex `JavaParser`, which still reaches ~86% on its own.
|
|
291
|
+
- **scip-dart needs `dart pub get` first.** scip-dart aborts with
|
|
292
|
+
"Unable to locate packageConfig" when the project hasn't been
|
|
293
|
+
bootstrapped. Run `dart pub get` (or `flutter pub get` for Flutter
|
|
294
|
+
packages) before `descry index` to get type-aware Dart resolution.
|
|
295
|
+
- **scip-dotnet honours `global.json` SDK pins.** When a project
|
|
296
|
+
pins an SDK not installed on the host (e.g. `PowerShell/PowerShell`
|
|
297
|
+
pins .NET 11 preview), scip-dotnet's adapter detects the
|
|
298
|
+
incompatibility and falls back to the regex `DotnetParser`. The
|
|
299
|
+
regex baseline alone reached 90% on PowerShell, so the fallback
|
|
300
|
+
is usually fine.
|
|
301
|
+
- **Pinned Rust toolchains need `rust-analyzer` installed.** A
|
|
302
|
+
`rust-toolchain.toml` pin (e.g. `helix` pins `1.90.0`) means
|
|
303
|
+
rust-analyzer must be installed for that specific toolchain
|
|
304
|
+
via `rustup component add rust-analyzer --toolchain <version>`.
|
|
305
|
+
Otherwise scip-rust emits per-crate warnings and the regex
|
|
306
|
+
`RustParser` baseline carries the project (~80%).
|
|
307
|
+
|
|
308
|
+
## [0.1.1] — 2026-04-17
|
|
309
|
+
|
|
310
|
+
Patch release focused on making cross-language tracing actually configurable,
|
|
311
|
+
plus a round of dead-code cleanup. No breaking changes.
|
|
312
|
+
|
|
313
|
+
### Fixed
|
|
314
|
+
|
|
315
|
+
- **Cross-language tracing is now configurable from `.descry.toml`.** The
|
|
316
|
+
`DescryConfig.openapi_path` field existed in 0.1.0 but had no TOML loader
|
|
317
|
+
and the web `/api/cross-lang` handler hardcoded `public/api/latest.json`,
|
|
318
|
+
so custom spec locations silently did nothing. Added a `[cross_lang]`
|
|
319
|
+
section with `openapi_path`, `backend_handler_patterns`,
|
|
320
|
+
`frontend_api_patterns`, and `api_prefixes` keys. Web and CLI/MCP now
|
|
321
|
+
both honour the config and pass all four through to `CrossLangTracer`.
|
|
322
|
+
- `[cross_lang] openapi_path` is containment-checked against the project
|
|
323
|
+
root; a crafted `.descry.toml` cannot point the indexer at files outside
|
|
324
|
+
the configured project.
|
|
325
|
+
|
|
326
|
+
### Removed
|
|
327
|
+
|
|
328
|
+
Dead code with no call sites anywhere in the tree was pruned:
|
|
329
|
+
|
|
330
|
+
- `DescryConfig.project_markers` (auto-detect used a module constant).
|
|
331
|
+
- `DescryConfig.use_tree_sitter_ts` (scaffolding field with no consumer).
|
|
332
|
+
- `descry.query.MAX_INLINE_THRESHOLD` constant.
|
|
333
|
+
- `CrossLangTracer.endpoint_to_node_id()` and module-level
|
|
334
|
+
`_create_cross_lang_edges()` helper.
|
|
335
|
+
- `SemanticSearcher._find_similar()` (distinct from
|
|
336
|
+
`GraphQuerier._find_similar_nodes`, which remains).
|
|
337
|
+
- `descry.ast_grep.extract_imports_typescript_batch()`.
|
|
338
|
+
- `ScipIndex.get_definition_location()` and `get_symbol_info()`.
|
|
339
|
+
- `TypeScriptSymbolTable.file_dir` attribute.
|
|
340
|
+
- `DescryService._clear_dedup_cache()` (superseded by `reset_caches()` in
|
|
341
|
+
the 0.1.0 hardening sweep).
|
|
342
|
+
|
|
343
|
+
A `vulture --min-confidence 80` sweep on `src/descry/` now reports zero
|
|
344
|
+
findings outside generated protobuf code.
|
|
345
|
+
|
|
346
|
+
## [0.1.0] — 2026-04-16
|
|
347
|
+
|
|
348
|
+
Initial public PyPI release. Descry is a polyglot codebase knowledge graph toolkit with three interfaces: CLI (`descry`), MCP server (`descry-mcp`), and local web UI (`descry-web`).
|
|
349
|
+
|
|
350
|
+
### Features
|
|
351
|
+
|
|
352
|
+
- **Indexer**: Parses Rust, Python, TypeScript, JavaScript, and Svelte into a cached knowledge graph of symbols (functions, classes, constants) and edges (calls, imports, defines).
|
|
353
|
+
- **SCIP integration**: Optional type-aware call resolution via `rust-analyzer` and `scip-typescript`; regex fallback otherwise.
|
|
354
|
+
- **Semantic search**: Optional embeddings via sentence-transformers (Jina code embeddings by default; model pinned by revision).
|
|
355
|
+
- **19 MCP tools**: search, callers, callees, context, flow, path, impls, structure, flatten, cross-lang (preview), churn, evolution, changes, semantic, quick, index, status, ensure, health.
|
|
356
|
+
- **Web UI**: Starlette + Alpine.js; 20+ UI panels for browsing the graph visually.
|
|
357
|
+
- **Configuration**: `.descry.toml` + env-var overrides for cache dir, timeouts, embedding model, SCIP toolchain, excluded dirs.
|
|
358
|
+
|
|
359
|
+
### Security
|
|
360
|
+
|
|
361
|
+
- Git argument injection hardening on all user-controlled inputs (commit ranges, symbol names, file paths, pathspecs).
|
|
362
|
+
- Safe embedding-cache storage (JSON sidecar + safe-mode numpy load) with atomic writes and content-addressed cache keys.
|
|
363
|
+
- Default embedding model revision pinned for supply-chain integrity; `trust_remote_code` defaults to `False` for user-supplied models.
|
|
364
|
+
- TOML-sourced subprocess args (scip toolchain, extra args, embedding model path) are validated.
|
|
365
|
+
- Subprocess env sanitized against known credential patterns.
|
|
366
|
+
- Web UI path traversal containment on `/api/source` + regular-file / size / text-file checks.
|
|
367
|
+
- MCP `descry_index(path=...)` restricted to project root.
|
|
368
|
+
- Graph JSON carries `schema_version`; mismatched graphs are rejected with an actionable error.
|
|
369
|
+
|
|
@@ -23,7 +23,7 @@ just test tests/test_handlers.py::test_index # one test
|
|
|
23
23
|
just test -k "cross_lang and not slow" # by expression
|
|
24
24
|
```
|
|
25
25
|
|
|
26
|
-
Python 3.11+ required (enforced by `pyproject.toml`). Pre-commit gate: `just lint && just fmt && just test` all pass (
|
|
26
|
+
Python 3.11+ required (enforced by `pyproject.toml`). Pre-commit gate: `just lint && just fmt && just test` all pass (497 tests currently — a drop is a regression signal).
|
|
27
27
|
|
|
28
28
|
Invoke the tool while developing:
|
|
29
29
|
|
|
@@ -58,9 +58,9 @@ Packaging: `pyproject.toml` defines four console scripts — `descry`, `descry-m
|
|
|
58
58
|
|
|
59
59
|
These are load-bearing — see `SECURITY.md` and the `## Security` section of `CHANGELOG.md`. Do not weaken without a review:
|
|
60
60
|
|
|
61
|
-
- **Subprocess env sanitization.** Every subprocess call
|
|
61
|
+
- **Subprocess env sanitization.** Every subprocess call — git, every SCIP indexer (`rust-analyzer`, `scip-typescript`, `scip-python`, `scip-java`, `scip-go`, `scip-ruby`, `scip-php`, `scip-dotnet`, `scip-clang`, `scip-dart`), ast-grep, and the `descry-generate` child process — must pass `env=safe_env()` from `src/descry/_env.py`, which filters credential-shaped env vars by regex.
|
|
62
62
|
- **TOML-sourced subprocess args are validated.** `_validate_toolchain`, `_validate_scip_extra_arg`, `_validate_embedding_model` in `handlers.py` reject short flags, shell metacharacters, and out-of-root local paths. New TOML → subprocess plumbing must validate.
|
|
63
|
-
- **Web UI is local-only by design.** `descry-web` binds `127.0.0.1`, has no auth, and
|
|
63
|
+
- **Web UI is local-only by design.** `descry-web` binds `127.0.0.1`, has no auth, and deliberately omits `CORSMiddleware` so browsers enforce same-origin — a tab on `evil.com` cannot read `/api/source` or trigger `/api/index`. `TrustedHostMiddleware` rejects non-loopback `Host` headers to defeat DNS-rebinding that would otherwise bypass the 127.0.0.1 bind. `/api/source` enforces project-root containment, rejects non-regular files / non-text content / >10 MiB, and uses `O_NOFOLLOW` on the final open. `/api/index` (and `/api/index/stream`) take no path parameter (always indexes the configured root). Don't add a `--host 0.0.0.0` flag, don't add `CORSMiddleware`, and don't expose network listeners.
|
|
64
64
|
- **MCP `index(path=...)`** is restricted to the configured project root.
|
|
65
65
|
- **Embedding cache** uses numpy safe-mode load + JSON sidecar + atomic writes + content-addressed keys. Default embedding model revision is pinned for supply-chain integrity; `trust_remote_code` defaults to `False` for user-supplied models.
|
|
66
66
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: descry-codegraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis
|
|
5
5
|
Project-URL: Homepage, https://github.com/06chaynes/descry
|
|
6
6
|
Project-URL: Repository, https://github.com/06chaynes/descry
|
|
@@ -67,7 +67,7 @@ Description-Content-Type: text/markdown
|
|
|
67
67
|
|
|
68
68
|
Polyglot codebase knowledge graph with call-graph analysis, semantic search, and SCIP integration. Built for AI coding agents (MCP), with CLI and Web UI interfaces.
|
|
69
69
|
|
|
70
|
-
Descry indexes your codebase into a knowledge graph of symbols (functions, classes, constants) and their relationships (calls, imports, defines).
|
|
70
|
+
Descry indexes your codebase into a knowledge graph of symbols (functions, classes, constants) and their relationships (calls, imports, defines). SCIP-backed type-aware resolution is available for Rust, TypeScript, JavaScript, Svelte, Python, Java (+ Kotlin / Scala), Go, Ruby, PHP, C# (+ VB.NET), C / C++, and Dart. The `.js` / `.jsx` / `.svelte` paths run through `scip-typescript`; pure Kotlin / Scala source needs `scip-java` (which doesn't always work on Kotlin-DSL Gradle projects — see [CHANGELOG](CHANGELOG.md#020--2026-04-20) known limitations).
|
|
71
71
|
|
|
72
72
|
> ### ⚠️ Disclaimer — please read
|
|
73
73
|
>
|
|
@@ -124,6 +124,7 @@ descry quick handle_request
|
|
|
124
124
|
| **MCP Server** | `descry-mcp` | AI coding agents (Claude Code, etc.) |
|
|
125
125
|
| **Web UI** | `descry-web` | Visual exploration at `http://127.0.0.1:8787` |
|
|
126
126
|
| **Pi Extension** | See `pi-extension/` | Pi coding agent integration |
|
|
127
|
+
| **Claude Code Skill** | See `claude-skill/` | Teaches Claude when/how to reach for descry |
|
|
127
128
|
|
|
128
129
|
## MCP Setup
|
|
129
130
|
|
|
@@ -161,7 +162,7 @@ Descry uses the standard MCP stdio transport. Any MCP-compatible host can spawn
|
|
|
161
162
|
|
|
162
163
|
## Tools
|
|
163
164
|
|
|
164
|
-
Descry provides
|
|
165
|
+
Descry provides 19 tools, available through all interfaces:
|
|
165
166
|
|
|
166
167
|
| Tool | Description |
|
|
167
168
|
|------|-------------|
|
|
@@ -187,35 +188,49 @@ Descry provides 18 tools, available through all interfaces:
|
|
|
187
188
|
|
|
188
189
|
## Configuration
|
|
189
190
|
|
|
190
|
-
Descry works zero-config by auto-detecting your project root
|
|
191
|
+
Descry works zero-config by auto-detecting your project root. The walker looks for any of: `.git`, `.descry.toml`, `Cargo.toml`, `package.json`, `pyproject.toml`, `setup.py`, `go.mod`, `Gemfile`, `composer.json`, `build.gradle{,.kts}`, `settings.gradle{,.kts}`, `pom.xml`, `build.sbt`, `global.json`, `pubspec.yaml`, `CMakeLists.txt`, or `compile_commands.json`.
|
|
192
|
+
|
|
193
|
+
For customization, add a `.descry.toml` to your project root.
|
|
194
|
+
|
|
195
|
+
> **Heads-up on list-typed fields.** Several settings below are **lists that REPLACE descry's defaults** when set, not merge. These include `[project] excluded_dirs`, `[code_files] extensions`, `[test_detection] path_patterns` / `file_suffixes`, and `[git] churn_exclusions`. Leave them out unless you have a specific reason — descry's defaults already cover a wide language matrix. If you do set them, copy the full default list (see `_DEFAULT_*` constants in `src/descry/handlers.py`) and modify from there. `[syntax.lang_map]` is the one list-shaped field that *merges* with defaults.
|
|
191
196
|
|
|
192
197
|
```toml
|
|
193
198
|
[project]
|
|
194
|
-
|
|
195
|
-
|
|
199
|
+
# OPTIONAL — REPLACES the 25-element default. Leave unset to keep defaults
|
|
200
|
+
# (.git, .gradle, .next, .svelte-kit, .venv, node_modules, target, build, …).
|
|
201
|
+
# excluded_dirs = ["target", "node_modules", "dist", "build", "vendor"]
|
|
202
|
+
max_stale_hours = 24
|
|
196
203
|
|
|
197
204
|
[features]
|
|
198
|
-
enable_scip = true
|
|
205
|
+
enable_scip = true # Type-aware resolution (auto-detects which indexers are on PATH)
|
|
199
206
|
enable_embeddings = true # Semantic search (requires sentence-transformers)
|
|
200
207
|
|
|
201
208
|
[embeddings]
|
|
202
209
|
model = "jinaai/jina-code-embeddings-0.5b"
|
|
203
210
|
|
|
204
211
|
[test_detection]
|
|
205
|
-
|
|
206
|
-
|
|
212
|
+
# OPTIONAL — REPLACES defaults. Defaults cover Rust/Python/TS/Go/Ruby/Java/Kotlin/
|
|
213
|
+
# Scala/PHP/C#/Dart/C/C++ test conventions.
|
|
214
|
+
# path_patterns = ["/tests/", "/test/", "/__tests__/"]
|
|
215
|
+
# file_suffixes = ["_test.rs", ".test.ts", ".spec.ts", "_test.py"]
|
|
207
216
|
|
|
208
217
|
[code_files]
|
|
209
|
-
|
|
218
|
+
# OPTIONAL — REPLACES the 30-element default (.rs/.py/.ts/.tsx/.js/.jsx/.svelte/
|
|
219
|
+
# .go/.java/.kt/.scala/.rb/.rake/.gemspec/.php/.cs/.vb/.c/.cc/.cpp/.cxx/.cu/.h/
|
|
220
|
+
# .hh/.hpp/.hxx/.dart/.css/.scss/.html). Leave unset to keep defaults.
|
|
221
|
+
# extensions = [".rs", ".py", ".ts", ".tsx", ".go", ".java"]
|
|
210
222
|
|
|
211
223
|
[git]
|
|
212
|
-
|
|
224
|
+
# OPTIONAL — REPLACES defaults (.descry_cache/, .beads/, Cargo.lock,
|
|
225
|
+
# package-lock.json, yarn.lock, pnpm-lock.yaml).
|
|
226
|
+
# churn_exclusions = [".descry_cache/", "Cargo.lock", "package-lock.json"]
|
|
213
227
|
timeout = 30
|
|
214
228
|
|
|
215
229
|
[timeouts]
|
|
216
230
|
scip_minutes = 0 # 0 = unlimited
|
|
217
231
|
embedding_seconds = 60
|
|
218
232
|
query_ms = 4000
|
|
233
|
+
index_minutes = 30 # Timeout for `descry index` subprocess
|
|
219
234
|
|
|
220
235
|
[query]
|
|
221
236
|
max_depth = 3
|
|
@@ -231,8 +246,16 @@ skip_crates = [] # Crate names to skip during SCIP indexing
|
|
|
231
246
|
toolchain = "1.92.0" # Pin rust-analyzer version via rustup
|
|
232
247
|
|
|
233
248
|
[syntax.lang_map]
|
|
249
|
+
# MERGES with defaults (additive). Maps file extensions to syntax-highlight names.
|
|
234
250
|
".svelte" = "svelte"
|
|
235
251
|
".proto" = "protobuf"
|
|
252
|
+
|
|
253
|
+
[cross_lang]
|
|
254
|
+
# Frontend -> backend handler tracing via OpenAPI spec.
|
|
255
|
+
openapi_path = "public/api/openapi.json" # must resolve inside project_root
|
|
256
|
+
backend_handler_patterns = ["backend/src/routes"] # path substrings; empty = no filter
|
|
257
|
+
frontend_api_patterns = ["webapp/src/lib/api"] # same
|
|
258
|
+
api_prefixes = ["/api/v1", "/api/v2", "/api"] # stripped when matching spec paths
|
|
236
259
|
```
|
|
237
260
|
|
|
238
261
|
### Environment Variables
|
|
@@ -243,6 +266,10 @@ toolchain = "1.92.0" # Pin rust-analyzer version via rustup
|
|
|
243
266
|
| `DESCRY_CACHE_DIR` | `.descry_cache/` | Override cache directory location |
|
|
244
267
|
| `DESCRY_NO_SCIP` | `false` | Disable SCIP indexing |
|
|
245
268
|
| `DESCRY_NO_EMBEDDINGS` | `false` | Disable semantic search |
|
|
269
|
+
| `DESCRY_SCIP_WORKERS` | auto | Max parallel SCIP indexer workers (overrides the memory-based default) |
|
|
270
|
+
| `DESCRY_SCIP_TIMEOUT` | auto | Per-project SCIP indexer timeout in minutes (`0` / `none` disables) |
|
|
271
|
+
| `DESCRY_PRIME_THREADS` | auto | Threads used when pre-warming `rust-analyzer` cache |
|
|
272
|
+
| `DESCRY_AST_GREP_MAX_FILES` | `5000` | Skip ast-grep per-file invocation on repos larger than this many target-language files |
|
|
246
273
|
|
|
247
274
|
Configuration precedence: defaults < `.descry.toml` < environment variables.
|
|
248
275
|
|
|
@@ -250,15 +277,20 @@ Configuration precedence: defaults < `.descry.toml` < environment variables.
|
|
|
250
277
|
|
|
251
278
|
| Language | Parsing | SCIP (Type-Aware) | Requirements |
|
|
252
279
|
|----------|---------|-------------------|--------------|
|
|
253
|
-
| Rust | Regex +
|
|
254
|
-
| TypeScript | Regex (+
|
|
255
|
-
|
|
|
256
|
-
|
|
|
257
|
-
|
|
|
258
|
-
|
|
|
259
|
-
|
|
|
260
|
-
|
|
261
|
-
|
|
280
|
+
| Rust | Regex (+ ast-grep when `sg` on PATH) | Yes | `rust-analyzer` via rustup |
|
|
281
|
+
| TypeScript | Regex (+ ast-grep when `sg` on PATH) | Yes | `scip-typescript` via npm |
|
|
282
|
+
| JavaScript | Regex (+ ast-grep when `sg` on PATH) | Yes (via `scip-typescript`) | `scip-typescript` via npm |
|
|
283
|
+
| Svelte | Regex | Yes (via `scip-typescript`) | `scip-typescript` via npm |
|
|
284
|
+
| Python | Regex + Python `ast` module | Yes | `scip-python` via npm |
|
|
285
|
+
| Java / Kotlin / Scala | Regex (Java only — `.kt` / `.scala` produce no nodes when scip-java doesn't run) | Yes | `scip-java` (`coursier install scip-java`); see [CHANGELOG](CHANGELOG.md#020--2026-04-20) for the Kotlin-DSL Gradle limitation |
|
|
286
|
+
| Go | Regex | Yes | `scip-go` (`go install github.com/sourcegraph/scip-go/cmd/scip-go@latest`) |
|
|
287
|
+
| Ruby | Regex | Yes | `scip-ruby` gem or direct binary |
|
|
288
|
+
| PHP | Regex | Yes | `scip-php` via `composer require --dev davidrjenni/scip-php` (third-party indexer) |
|
|
289
|
+
| C# / VB.NET | Regex (C# only) | Yes | `scip-dotnet` via `dotnet tool install --global scip-dotnet` |
|
|
290
|
+
| C / C++ | Regex | Yes | `scip-clang` binary + `compile_commands.json` (CMake `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON`, Meson+Ninja, or `bear -- make`) |
|
|
291
|
+
| Dart / Flutter | Regex | Yes | `scip-dart` via `dart pub global activate scip_dart`; requires `dart pub get` at project root |
|
|
292
|
+
|
|
293
|
+
`ast-grep` is the `sg` Rust binary (install via Homebrew or `cargo install ast-grep`) — when present on `PATH`, descry uses it for higher-fidelity call extraction in Rust, TypeScript, and JavaScript files. It's auto-disabled on TS/JS corpora over `DESCRY_AST_GREP_MAX_FILES` (default 5,000) where per-file subprocess overhead would dominate. The `descry-codegraph[ast]` Python extra installs `tree-sitter*` packages that are scaffolding for a future AST-driven parser at `src/descry/tree_sitter_parser.py` — currently not wired into the active pipeline.
|
|
262
294
|
|
|
263
295
|
SCIP provides precise call-graph resolution (resolving which specific function is called through traits, generics, etc.). Without SCIP, Descry falls back to regex-based name matching which handles most cases but may produce false positives on overloaded names.
|
|
264
296
|
|
|
@@ -315,17 +347,19 @@ Requires [uv](https://github.com/astral-sh/uv) and [just](https://github.com/cas
|
|
|
315
347
|
|
|
316
348
|
3. **Query** — All tools query the cached graph. Keyword search uses TF-IDF scoring. Semantic search uses sentence-transformer embeddings. Call-graph traversal follows edges in the graph.
|
|
317
349
|
|
|
318
|
-
4. **Freshness** — `ensure`
|
|
350
|
+
4. **Freshness** — `ensure` regenerates the graph when its age exceeds the `--max-age-hours` flag (CLI) / `max_age_hours` argument (MCP), defaulting to 24 hours. The `[project] max_stale_hours` config drives the "STALE" badge in `descry status` output but does not by itself trigger regeneration. The MCP server pre-warms the graph on startup.
|
|
319
351
|
|
|
320
352
|
## Design Notes
|
|
321
353
|
|
|
322
|
-
### Web UI is local-only
|
|
354
|
+
### Web UI is local-only — same-origin + DNS-rebind defenses
|
|
323
355
|
|
|
324
|
-
`descry-web` is designed as a single-user local development tool. It binds to `127.0.0.1` by default,
|
|
356
|
+
`descry-web` is designed as a single-user local development tool. It binds to `127.0.0.1` by default, has no authentication, and **deliberately omits `CORSMiddleware`** so browsers enforce same-origin by default — a tab on `evil.com` cannot read `/api/source` or trigger `/api/index`. This is deliberate:
|
|
325
357
|
|
|
326
358
|
- The UI is served by the same process that reads your repository; any authentication layer would be a shared-secret between your browser and your own terminal.
|
|
327
|
-
-
|
|
328
|
-
- The
|
|
359
|
+
- `TrustedHostMiddleware` rejects requests whose `Host` header isn't loopback (`127.0.0.1`, `localhost`, `::1`), defeating DNS-rebinding attacks that would otherwise bypass the 127.0.0.1 bind.
|
|
360
|
+
- The `--host` flag is validated by `_loopback_host` and rejects non-loopback values with a clear error pointing at the reverse-proxy guidance.
|
|
361
|
+
- Path-traversal hardening on `/api/source` is independent of any CORS posture: it enforces project-root containment, rejects non-regular files, caps size at 10 MiB, refuses non-text content, and uses `O_NOFOLLOW` on the final open to defeat symlink swaps.
|
|
362
|
+
- The reindex endpoints (`/api/index`, `/api/index/stream`) accept no path parameter; they always index the configured project root.
|
|
329
363
|
|
|
330
364
|
**Do not expose `descry-web` to an untrusted network.** If you need remote access, put it behind your own authenticated reverse proxy.
|
|
331
365
|
|
|
@@ -333,7 +367,7 @@ Requires [uv](https://github.com/astral-sh/uv) and [just](https://github.com/cas
|
|
|
333
367
|
|
|
334
368
|
Descry is pre-1.0. Minor version bumps (`0.1.x` → `0.2.x`) may include breaking changes to the library API, graph schema, CLI, or MCP tool signatures. Patch releases (`0.1.0` → `0.1.1`) will not introduce breaking changes. Once we reach `1.0.0`, the project will follow [semver](https://semver.org/) strictly.
|
|
335
369
|
|
|
336
|
-
The public
|
|
370
|
+
The only stable public API in pre-1.0 releases is `descry.__version__`. Submodules (`descry.handlers`, `descry.query`, etc.) are not considered stable API yet — refactor freely.
|
|
337
371
|
|
|
338
372
|
## Further Reading
|
|
339
373
|
|