``` ┌───────────────────────────────┐ │ Source Code Directory │ │ (.py .js .ts .kt .rb .go │ │ .rs .java .c .cpp .h) │ └──────────┬────────────────────┘ │ scan_directory() ▼ ┌───────────────────────────────┐ │ Files grouped by extension │ │ .kt → [a.kt, b.kt, ...] │ │ .py → [x.py, y.py, ...] │ └──────────┬────────────────────┘ │ for each extension ▼ ┌───────────────────────────────────────────┐ │ preprocess_by_method(file_path, code) │ │ │ │ tree-sitter parser ◄── _load_grammar() │ │ + │ │ highlights.scm query ◄── _load_query() │ │ │ │ │ ▼ │ │ BEHAVIORAL_PREFIXES filter │ │ (definition./reference./keyword./ │ │ function/attribute/constructor/ │ │ label/type.definition/module) │ │ │ │ │ ▼ │ │ _find_method_bodies() │ │ grouped by body boundaries │ │ │ │ │ ▼ │ │ [(cap, text, line), ...] per method │ └──────────┬────────────────────────────────┘ │ list of sequences ▼ ┌───────────────────────────────────────────┐ │ frequency_filter(sequences, 0.2) │ │ removes symbols in <20% of files │ └──────────┬────────────────────────────────┘ │ filtered sequences ▼ ┌───────────────────────────────────────────┐ │ cluster_methods_adaptive() │ │ │ │ Try ngram=3 │ │ ├── _extract_call_tokens() → call seqs │ │ ├── build ngram→indices index │ │ ├── top 20 by freq → clusters │ │ └── if (other) > 60% → ngram=2 → ... │ │ │ │ Multi-assignment: no used set │ │ Methods can be in N clusters │ └──────────┬────────────────────────────────┘ │ clusters: [(label, [seqs]), ...] ▼ ┌────────────────────────────────────────────────────────┐ │ For each cluster: │ │ │ │ ┌─────────────────────┐ ┌────────────────────────┐ │ │ │ _extract_imports() │ │ _build_arg_patterns() │ │ │ │ scan 200 lines │ │ extract_arg_info() │ │ │ │ for import/from/ │ │ + _classify_arg_node │ │ │ │ require/#include/ │ │ + _find_arglist_node │ │ │ │ use/include │ │ + _iterate_arg_nodes │ │ │ └─────────┬──────────┘ │ + _summarize_arg_info│ │ │ │ └───────────┬────────────┘ │ │ ▼ ▼ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ infer_ensemble(symbol_seqs, min_coverage=0.8) │ │ │ │ ├── CRX (fast, unordered) │ │ │ │ ├── iDRegEx (ordered regex) │ │ │ │ └── kOREInference (noisy, probabilistic) │ │ │ │ └── pick best by MDL score │ │ │ │ └── core/outlier split via _find_core(0.8) │ │ │ └──────────────────────┬───────────────────────────┘ │ │ ▼ │ │ (label, result, count, meta) │ │ meta = {files, imports, arg_patterns, │ │ packages: _file_to_package(relpath)} │ └─────────────────────────┬──────────────────────────────┘ ▼ ┌─────────────────────────────────────────────────────┐ │ Output │ │ │ │ --format text (default) --format json │ │ ┌──────────────────┐ ┌──────────────────┐ │ │ │ .kt: │ │ [{ │ │ │ │ ├─ assertEquals │ │ "language": │ │ │ │ │ (327 meth.) │ │ ".kt", │ │ │ │ │ Grammar: │ │ "conventions": │ │ │ │ │ assertEquals+│ │ [{...}, ...] │ │ │ │ │ Imports: ... │ │ }] │ │ │ │ │ Args(assertEquals): │ │ │ │ │ │ n=2 [lit,var]│ │ → inject into │ │ │ │ ├─ (other) │ │ LLM prompt │ │ │ │ │ (1254 meth.) │ └──────────────────┘ │ │ └──────────────────┘ │ └─────────────────────────────────────────────────────┘ ```