283 Commits

Author SHA1 Message Date
Safi e48428296c bump version to 0.6.7 v0.6.7 2026-05-02 17:13:08 +01:00
Safi d819827ea2 fix #655 #656 #657 #658: cache dir crash, sanitize_label None, rationale file_type, token counting
#655 and #656 already fixed in cache.py and security.py.
#657: add rationale to file_type schema in all 12 skill variants; warn against inventing concept.
#658: add explicit chunk-merge step with token summation before save_semantic_cache.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:10:20 +01:00
Safi bd92ab67d6 docs: remove VB.NET from README language count and file type table 2026-05-02 17:06:00 +01:00
Safi 1e848458f9 remove VB.NET support: tree-sitter-vbnet only has Windows wheels, no Linux/macOS
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:02:24 +01:00
Safi 2ca3a5994b merge PR #579: dynamic import() extraction for JS/TS
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:52:19 +01:00
Safi bfe18f0c83 fix: add context=import to JS/TS named-import edges (caught by PR #573 test)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:50:33 +01:00
Safi 28047b502f merge PR #573: cross-language edge context filters in MCP query tool
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:49:22 +01:00
Safi 9881d7ca30 merge PR #557: graphify tree — D3 v7 collapsible-tree HTML view of graph.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:48:09 +01:00
Safi 24808ef8e6 merge PR #625: token-aware chunking with split-and-retry on truncation
Co-Authored-By: Jason Matthew <jasonm4130@gmail.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:46:37 +01:00
Safi 66e61c76b1 docs: add Docker MCP Toolkit + SQLite MCP runbook (#620) 2026-05-02 16:42:08 +01:00
Safi 7237cd3290 feat: add VB.NET (.vb) language support via tree-sitter (#648) 2026-05-02 16:41:55 +01:00
Safi 996e82b3d9 test: add regression test for ambiguous cross-file call resolution (#632) 2026-05-02 16:39:53 +01:00
Safi 9ab4f39020 Merge pull request #662 from RubenAAA/fix/ts-named-import-symbol-edges
fix(extract): emit symbol-level edges for TS/JS named imports
2026-05-02 16:37:17 +01:00
Safi 58271fb5af docs: add Pi to pyproject.toml description and keywords 2026-05-02 15:33:17 +01:00
Safi 893219d66f docs: add Pi coding agent to README platform table and install docs 2026-05-02 15:33:17 +01:00
Safi 763a9359f5 Add Pi coding agent support and tighten wheel packaging
- Add skill-pi.md, graphify pi install/uninstall, --platform pi support (#661)
- Fix pyproject.toml: packages = ["graphify"] + include-package-data = false
  (wheel drops from 1.7MB to 285KB)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 15:33:12 +01:00
RubenAAA 5a342e385c fix(extract): emit symbol-level edges for TS/JS named imports
_import_js only created a file→file imports_from edge, leaving named
imported symbols (classes, error types, constants) as degree-1 orphans
with no connection to their consumers.

Track resolved_path when the import target resolves to a local file
(relative path or tsconfig alias). After emitting the file-level edge,
walk import_clause → named_imports → import_specifier to emit a
file → symbol EXTRACTED edge for each named specifier, using the same
_make_id(target_stem, name) key that _extract_generic uses when defining
the symbol.

On a 1696-file TypeScript monorepo this raised edge count from 8530 to
11267 (+2737 edges) and reduced isolated communities from 878 to 604.
2026-05-02 15:45:02 +02:00
Safi 47ca9228c3 security: add usedforsecurity=False to MD5/SHA1 hashes used for file diffing and filename generation 2026-05-02 14:32:16 +01:00
Safi 36e894aa62 v0.6.6: Windows skill bash rewrite, wiki fixes, rationale-node fix, hidden allowlist, --no-viz cluster-only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 14:25:26 +01:00
Safi d40e1c0cef Bump version to 0.6.5
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.6.5
2026-05-02 14:00:32 +01:00
Safi e02c7cc60c Fix Codex PreToolUse hook on Windows by delegating to graphify hook-check
The python3 -c "..." approach still failed on Windows Conda (no python3
shim) and PowerShell (JSON curly brace/quote parsing). Replace the inline
command with 'graphify hook-check' — a new shell-agnostic subcommand that
prints the hookSpecificOutput JSON if graph.json exists and exits 0 silently
if not. Works on PowerShell, cmd.exe, macOS, and Linux with no quoting or
interpreter-name issues.

Users must re-run 'graphify codex install' to regenerate the hook.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 13:57:19 +01:00
Safi ca48092413 Add --force flag and GRAPHIFY_FORCE env var to graphify update
Bypasses the node-count safety check in to_json for refactors that
legitimately shrink the graph (renames, package deletions). Also
honored by post-commit and post-checkout hooks via GRAPHIFY_FORCE=1.

Implements the approach from #639 (targeted at v5) adapted for v6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 13:52:09 +01:00
Hanzala Sohrab 8e01d686f7 feat: replace show/hide buttons with checkbox-based multi-select controls (#647) 2026-05-02 13:49:45 +01:00
Michal Harakal 71423a1efb Kotlin call-walker: accept both simple_identifier and identifier (#659)
`extract_kotlin` previously emitted zero `calls` edges (and zero
`raw_calls` entries) on the current PyPI grammar. The Kotlin branch
of `walk_calls` only matched node type `simple_identifier`, but
PyPI's `tree_sitter_kotlin` produces `identifier` for the equivalent
plain-identifier node. The `simple_identifier` ↔ `identifier` rename
is a generation gap between tree-sitter-kotlin grammar versions —
older forks (and the JVM `io.github.bonede:tree-sitter-kotlin`
binding) still use `simple_identifier`.

Accept both names so the extractor works across grammar generations.
Also widens `_KOTLIN_CONFIG.name_fallback_child_types` for the same
reason (defensive — currently the `name` field path covers
class/function name resolution, but if that field is dropped in a
future grammar update the fallback would face the same rename).

Tested against `tests/fixtures/sample.kt`: edges go from 6
(file-contains + class-method only) to 10 (adds 4 in-file `calls`
edges resolved by the walker:
  - .get() → .buildRequest() @ L8
  - .post() → .buildRequest() @ L12
  - createClient() → Config @ L21
  - createClient() → HttpClient @ L22).

A new regression test `test_kotlin_emits_in_file_calls` asserts the
four edges so this exact bug can't recur.

Found via graphify-kmp (Kotlin Multiplatform port of graphify) —
its `PythonParityTest` flagged 4 KMP-only edges that Python missed.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 13:49:42 +01:00
Safi c3ddace690 Update README git hooks description to reflect detached background rebuild
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 09:37:46 +01:00
Safi a61b25ce5f Bump version to 0.6.4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.6.4
2026-05-02 09:36:20 +01:00
Safi 8c9ee1818b Fix Codex PreToolUse hook failing on Windows
Replace bash-only [ -f ] file check with a cross-platform Python one-liner
so the hook works on Windows where cmd.exe has no [ builtin.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 09:35:28 +01:00
Safi a4149dffcd Bump version to 0.6.3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.6.3
2026-05-02 08:57:57 +01:00
Safi 028f585356 Fix ambiguous cross-file call resolution inflating god_nodes and guard cluster-only to_html
extract.py: build name -> all candidates map instead of last-write-wins dict.
Skip cross-file INFERRED calls where the callee name resolves to 2+ nodes
(common names like log/execute/find with no import evidence to pick the right
target) — prevents spurious edges from polluting god_nodes degree ranking.

__main__.py: wrap cluster-only to_html in try/except ValueError so large
graphs (>5000 nodes) don't crash the cluster command.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 08:56:20 +01:00
Safi c8969edd3c Fix semantic node preservation on incremental rebuild and detach git hooks
watch.py: filter preserved nodes by ID membership in new AST output instead
of file_type — INFERRED/AMBIGUOUS nodes on code files also carry file_type=code
and were being wrongly dropped, triggering the to_json safety check refusal.

hooks.py: detach post-commit and post-checkout rebuilds with nohup + disown
so git commit returns immediately instead of blocking for the full rebuild
duration. Rebuild log written to ~/.cache/graphify-rebuild.log.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 08:53:17 +01:00
Rangarajan Ramaswamy af15e33f57 feat: add extraction support for VB.NET files 2026-05-02 03:22:58 +03:00
Safi be83a8cc55 bump to v0.6.2 v0.6.2 2026-05-01 22:18:18 +01:00
Safi 3fdae8f334 fix #623 #621 #605 #638 #589 #586 #593: kimi thinking, manifest, inline comments, query boost, cache race, markdownify, content hash
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 22:15:24 +01:00
Safi e73b6060b1 fix #590 #628 #629 #630 #619 #617: directed graph, negation patterns, Windows paths, cross-lang noise, shebang, R
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 21:56:17 +01:00
Rangarajan Ramaswamy 5dbbcf7dad feat: add VB.NET (.vb) language support via tree-sitter
This commit adds full VB.NET language support to graphify, raising the
supported language count from 25 to 26. The implementation follows the
established LanguageConfig pattern used by all other tree-sitter-backed
extractors.

New dependency:
- Adds optional extra [vbnet] backed by tree-sitter-vbnet (published
  to PyPI at https://pypi.org/project/tree-sitter-vbnet/0.1.0/).
  Install with: pip install graphifyy[vbnet]

graphify/detect.py:
- Added .vb to CODE_EXTENSIONS so VB.NET files are discovered during
  corpus ingestion and file-system watching.

graphify/extract.py:
- _import_vbnet(): import handler for imports_statement nodes; emits
  imports edges using the namespace_name child text.
- _vbnet_extra_walk(): extra-walk hook that intercepts namespace_block
  nodes, emits a namespace node, and recurses.
- _VBNET_CONFIG: full LanguageConfig covering class_block / module_block /
  structure_block / interface_block as class types; method_declaration /
  constructor_declaration / property_declaration as function types;
  invocation call nodes with target/member_access fields.
- VB.NET-specific branches in _extract_generic:
  * Class body: VB.NET has no wrapper body node; inherits and implements
    are named fields directly on the class_block. Emits separate inherits
    and implements edges for each base type, stripping generic arguments.
  * Constructor name: constructor_declaration carries no name field in
    the grammar; always resolves to New.
  * Function body: uses the declaration node itself as body sentinel so
    the call-graph pass can find invocations inside methods.
- extract_vbnet(path): public wrapper that delegates to _extract_generic.
- _DISPATCH['.vb']: routes .vb files to extract_vbnet.

pyproject.toml:
- Added vbnet = ['tree-sitter-vbnet'] optional dependency group.
- Added 'tree-sitter-vbnet' to the all extra.

tests/fixtures/sample.vb:
- New fixture file exercising: Imports statements, Namespace block,
  Interface, Class with Inherits + Implements, Module, Structure,
  Sub/Function/Property methods, and method calls.

tests/test_languages.py:
- Added 13 tests covering: no-error, class/interface/module/structure
  detection, method detection, imports relation, inherits edge,
  implements edge, and no-dangling-edges invariant.

README.md:
- Updated language count 25 to 26.
- Added VB.NET to language list and file-extension table.
2026-05-01 21:20:36 +03:00
Safi 2dc759a951 bump to v0.6.1 v0.6.1 2026-05-01 18:50:12 +01:00
Safi 14fd14a284 combine what+when in skill description 2026-05-01 18:47:40 +01:00
Safi 7f336acfd9 fix .graphifyignore: correct gitignore semantics + hermetic non-VCS scan + skill auto-invoke
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 18:45:12 +01:00
Safi 8a6306f769 make .graphifyignore hermetic: stop at VCS root, not project boundaries (closes #643)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 15:28:33 +01:00
Safi 6b68de140c stop .graphifyignore walk at any VCS root or home dir, not just .git (fixes #643) 2026-05-01 14:54:04 +01:00
Safi 17fb524a91 bump to v0.6.0 v0.6.0 2026-05-01 10:18:37 +01:00
Safi ad1e11a035 update README: add SQL support to file type table and feature description 2026-05-01 10:16:20 +01:00
Safi 7d604e8141 v6: SQL AST extractor + xlsx structural extraction utility (fixes #349)
- extract_sql(): deterministic tree-sitter extraction of tables, views,
  functions, foreign key references, and FROM/JOIN reads_from edges
- .sql added to CODE_EXTENSIONS and dispatch table
- tree-sitter-sql added as optional dep under [sql] extra
- xlsx_extract_structure(): extracts sheet/table/column nodes from .xlsx
  (utility — pipeline wiring in follow-up)
- 6 new SQL tests, 447 total passing

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 10:15:06 +01:00
Safi 0999822364 update README: add yaml/yml to file type table and feature description 2026-04-30 22:36:24 +01:00
Safi 47a994ad5b bump to v0.5.7 v0.5.7 2026-04-30 22:34:08 +01:00
Safi 5aaa268650 add yaml/yml to DOC_EXTENSIONS so k8s/kustomize corpora are indexed (fixes #633)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 22:32:22 +01:00
Jason Matthew 2d13a17c3b feat(llm): split and retry chunks that hit max_completion_tokens truncation
Token-budget chunking cuts the truncation rate but doesn't eliminate
it. Output token cost scales with extractable concept density rather
than input tokens — a chunk that lands on a directory of dense design
docs can pack under the input budget while needing more than
`max_completion_tokens=8192` to express every named concept, so the
response is truncated mid-string and `_parse_llm_json` returns an
empty fragment.

Pre-tuning chunk size to be conservative enough that this never
happens leaves throughput on the table for the common case. Adding a
hard `max_files_per_chunk` cap on top of `token_budget` reintroduces
the "tune a static constant" problem the previous commit set out to
fix.

The fix uses the API's own truncation signal:

1. `_call_openai_compat` and `_call_claude` now expose `finish_reason`
   on the result dict (Anthropic's `stop_reason == "max_tokens"` is
   normalised to `"length"`).
2. `_extract_with_adaptive_retry` checks it: when truncated, splits
   the chunk in half and recurses on each half. Recursion is bounded
   by `max_retry_depth` (default 3 → at most 8x fanout per top-level
   chunk).
3. Single-file chunks that truncate can't recover and surface a
   warning rather than infinite-loop.
4. `extract_corpus_parallel` routes every chunk through the retry
   wrapper. The `on_chunk_done` callback fires once per top-level
   chunk with the merged result — recursive splits are invisible to
   callers.
2026-04-30 22:08:28 +10:00
Jason Matthew cc5c54574d feat(llm): pack chunks by token budget, parallelise, accept tiktoken
Three independent improvements to extract_corpus_parallel:

1. Token-aware chunking. Replaces `chunk_size=20` static packing with
   a greedy packer keyed on `token_budget` (default 60_000), grouped
   by parent directory so related artefacts share a chunk. Pass
   `token_budget=None` to fall back to fixed-count packing.

2. Optional tiktoken (added to the [kimi] extra). When available,
   `_estimate_file_tokens` uses cl100k_base for accurate counts;
   without it, the existing chars/4 heuristic kicks in. Kimi-K2 ships
   a tiktoken-based tokenizer so estimates against Moonshot are very
   close to truth.

3. True parallelism. The function name said "parallel" but the body
   was a sequential for-loop. Now uses ThreadPoolExecutor capped at
   `max_concurrency` (default 4 — conservative against provider rate
   limits). `on_chunk_done(idx, total, result)` still fires once per
   chunk with the original submission idx so progress UIs work
   unchanged. `max_concurrency=1` skips the pool to preserve
   sequential semantics.

Plus failure tolerance: a chunk raising is now caught, logged to
stderr, and the run continues. Other chunks' results merge as normal.

On a 162-file repo (~125k words), the same work that took ~36 min
sequential under the old code finishes in ~7 min.
2026-04-30 22:08:28 +10:00
Safi 3755fdc885 swap downloads badge back to pepy.tech 2026-04-30 09:48:37 +01:00
Safi 4e871ad36c swap downloads badge to shields.io for cache refresh 2026-04-30 09:47:55 +01:00