406 Commits

Author SHA1 Message Date
Safi 9caaa17f7f bump version to 0.7.13 v0.7.13 2026-05-09 23:45:43 +01:00
Safi 8c4c67f3ad fix Ollama num_ctx: derive from actual chunk size instead of hardcoding 131072 (#798) 2026-05-09 23:42:44 +01:00
Safi 5ead190891 wire callflow HTML into watch/hook rebuild: regenerates automatically if file exists 2026-05-09 23:29:43 +01:00
Porun db66b8727b feat: add callflow HTML export with Mermaid architecture diagrams 2026-05-09 23:26:01 +01:00
Safi 8c00287e84 fix Ollama context saturation: set num_ctx=131072, keep_alive=30m, serial by default (#798) 2026-05-09 22:51:36 +01:00
Safi e926079c0a bump version to 0.7.12, update README with new languages and extract flags
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:41:44 +01:00
Safi 23f598f3a0 fix MultiGraph crash, hollow LLM response retry, and skill --help (#796, #795, #792)
#796: add edge_data()/edge_datas() helpers in build.py that tolerate
MultiGraph/MultiDiGraph; replace all G.edges[u,v] 2-tuple call sites in
__main__.py, serve.py, wiki.py, export.py, analyze.py, benchmark.py;
fix same pattern in 10 skill file inline heredocs

#795: all 12 skill files now short-circuit on /graphify --help or -h
and print the Usage block without running any pipeline steps

#792 (hollow response): add _response_is_hollow() predicate in llm.py;
when Ollama (or any backend) returns empty/null/whitespace content or a
parsed result with no nodes/edges, rewrite finish_reason="length" so
_extract_with_adaptive_retry bisects the chunk instead of silently
dropping it; applied to _call_openai_compat, _call_claude, _call_bedrock

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 21:17:25 +01:00
Safi dc50979a68 fix hook OOM, lift worker cap, fix antigravity .agents path and frontmatter
#791: per-repo fcntl flock in _rebuild_code prevents concurrent hook rebuilds
from exhausting memory; changed_paths wired through so only modified files are
re-extracted; stale nodes evicted on deletion; SIGALRM watchdog with
GRAPHIFY_REBUILD_TIMEOUT; Darwin-aware RLIMIT_DATA memory cap

#792: remove hard 8-worker cap (GRAPHIFY_MAX_WORKERS env var); add
--max-workers, --token-budget, --max-concurrency, --api-timeout CLI flags
to graphify extract; fix ollama API key gate for loopback URLs; explicit
timeout on OpenAI client (GRAPHIFY_API_TIMEOUT, default 600s); per-chunk
progress prints during extraction

#453 + #785: rename .agent -> .agents throughout antigravity install/uninstall;
add trigger:always_on YAML frontmatter to _ANTIGRAVITY_RULES so Antigravity
recognises the rules file

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 16:57:05 +01:00
Safi 8e6483511d add Pascal regex fallback - extraction works without tree-sitter-pascal
tree-sitter-pascal is not on PyPI so extract_pascal() fell back to an
empty error result for all users. _extract_pascal_regex() now handles
unit/program/library headers, uses clauses, class/interface declarations
with inheritance, forward method decls, qualified impl headers, balanced
begin/end body extraction, and intra-file calls edges. All 15 previously
skipped pascal_required tests now run unconditionally and pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 15:52:17 +01:00
simeonbodurov 32bf8b4a37 feat(extract): add Pascal/Delphi and Lazarus IDE support (#781)
* feat(extract): add Pascal/Delphi language support

Adds full AST extraction for Pascal and Delphi source files using
tree-sitter-pascal (https://github.com/Isopod/tree-sitter-pascal).

Supported file extensions: .pas, .pp, .dpr, .dpk, .inc

Extracted nodes:
- File node (the .pas file itself)
- unit / program / library declarations
- class, interface, and helper type declarations
- procedure and function implementations

Extracted edges:
- file --contains--> module
- module --imports--> dependency (via uses clause, resolved to path-based IDs)
- class --inherits--> base class / interface
- class/module --contains/method--> procedure or function
- procedure --calls--> procedure (in-file call resolution)

Key design: uses clause targets are resolved to path-based node IDs by
scanning all Pascal files under the project root (_pascal_project_root +
_pascal_resolve_unit helpers). This avoids dangling import edges that
result from resolving bare unit names like "SysUtils" to IDs that never
match any file node.

Bare procedure calls (e.g. `Reset;` without parentheses) are detected
by inspecting statement nodes whose sole named child is an identifier,
in addition to the standard exprCall nodes used for calls with arguments.

Requires: pip install tree-sitter-pascal
(https://github.com/Isopod/tree-sitter-pascal)
If not installed, extract_pascal returns {"nodes":[], "edges":[], "error": ...}
so the rest of the pipeline is unaffected.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat(extract): add Lazarus .lfm and .lpk file support

Adds two new extractors for Lazarus IDE-specific file formats:

extract_lazarus_form() — .lfm (Lazarus Form files)
  .lfm files are text-based UI component trees. The extractor parses
  `object Name: TClassName ... end` blocks to build a containment graph
  of form components, and captures `OnXxx = HandlerName` event bindings
  as `references` edges (context: "event") linking each component to
  its handler procedure.

extract_lazarus_package() — .lpk (Lazarus Package files)
  .lpk files are XML package definitions. The extractor reads the
  package name, required package dependencies (→ imports edges), and
  listed unit files (→ contains edges). Unit names are resolved to
  path-based node IDs via _pascal_resolve_unit so they connect to the
  same nodes produced by extract_pascal on .pas files.

Both extensions added to CODE_EXTENSIONS in detect.py and to _DISPATCH.
13 new tests in test_pascal.py cover both extractors.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(pascal): fix dangling inherits-edge targets and capture all base classes

The declType/typeref handler built inherits edge targets with
_make_id(_read(child)) — just the bare class name. But class nodes
use _make_id(stem, type_name), so targets never matched, making the
entire class hierarchy invisible in the graph.

Add _pascal_class_stem_cache and _pascal_resolve_class(): strips the
conventional T/I prefix, locates the defining file by stem lookup
(same cache mechanism as _pascal_resolve_unit), and returns the
correct _make_id(file_stem, class_name) ID. RTL/unresolvable bases
(e.g. TObject) fall back to _make_id(bare_name) with an explicit
stub node, following the same pattern as the Python extractor.

Also remove the `break` that stopped after the first typeref, so
all parents are captured (e.g. class(TBase, IInterface)).

Extend test_pascal_no_dangling_edges to also assert that within-file
edge targets (contains, method, inherits, calls) resolve to real nodes.

* feat(extract): add Delphi .dfm form file support

Adds extract_delphi_form() for Delphi Form files (.dfm), which use the
same `object Name: TClassName ... end` text syntax as Lazarus .lfm files.

Binary .dfm files (FF 0A magic header) are skipped gracefully with an
informative error message so the pipeline is unaffected.  Text .dfm files
are parsed identically to .lfm: component containment (`contains` edges)
and event handler references (`references`, context "event").

Adds .dfm to _DISPATCH and CODE_EXTENSIONS.
10 new tests in test_pascal.py, including a regression test for the
binary-format detection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* Add .lpr extension and fix removesuffix in Pascal extractor

Address review feedback from @safishamsi:
- Add .lpr (Lazarus program file, identical syntax to .dpr) to _DISPATCH
  in extract.py and CODE_EXTENSIONS in detect.py so Lazarus project entry
  points are indexed. Completes the promised Lazarus IDE support.
- Replace rstrip("()") with removesuffix("()") in the call-resolution
  dict comprehension for precise suffix removal (rstrip strips individual
  characters, not the literal string "()").
- Add .lpr assertions to test_pascal_dispatch_registered and
  test_pascal_detect_extensions_registered.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Simeon Bodurov <simeon.bodurov@speedy.bg>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 14:44:58 +01:00
Safi adf96da283 bump version to 0.7.11
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.7.11
2026-05-09 13:10:42 +01:00
nauman73 e5f263ba98 fix(windows): unblock pipeline on Windows consoles + missing __main__ guards (#788)
Three independent Windows compatibility fixes shipped together because they
all surface during the same first /graphify run on Windows.

graphify/benchmark.py
  print_benchmark() unconditionally printed U+2500 (box-drawing) and U+2192
  (rightwards arrow), which UnicodeEncodeError'd on stdouts that can't encode
  them — most notably the legacy Windows console at cp1252. New _safe()
  helper falls back to ASCII when the active stdout encoding can't carry the
  glyph; _hr() uses it. Two regression tests cover both paths and prove
  print_benchmark survives a cp1252-strict stream.

graphify/extract.py
  ProcessPoolExecutor on Windows uses spawn, so worker subprocesses
  re-import the calling __main__. When the caller is `python -c "..."` or a
  script without an `if __name__ == "__main__":` guard, the workers
  recursively spawn themselves and the pool dies. The user-visible failure
  was a 290-line traceback ending in BrokenProcessPool, hiding the actual
  cause. _extract_parallel now catches BrokenProcessPool, prints a one-line
  warning that names the __main__-guard idiom, and returns False so the
  public extract() routes to the existing _extract_sequential fallback. Two
  tests cover the parallel-returns-False contract and the sequential
  fallback wiring.

graphify/skill-windows.md
  Every `python -c "..."` block (30 in total) is replaced with a
  Write+run+delete pattern using PowerShell's literal here-string @'...'@.
  The old form was a quote-escaping minefield: any double-quote inside the
  Python source had to be backslash-escaped for the shell, and PowerShell's
  parser ate them inconsistently — failing on f-strings like
  `f'AST: {len(result["nodes"])} nodes'`. The new form passes Python source
  to disk literally, so what the model writes is what Python sees. The AST
  step's script template now includes an explicit `if __name__ == "__main__":`
  guard so multi-core extraction works even before the runtime fallback above
  kicks in. All 31 resulting heredoc blocks parse cleanly under
  `ast.parse`.

Co-authored-by: Nauman Hameed <Nauman.Hameed@enghouse.com>
2026-05-09 12:59:38 +01:00
tmaeder f88567b114 Recover from context-window-exceeded API errors in adaptive retry (#789)
Adaptive retry only recovered from `finish_reason="length"` (output
truncation). It did not handle the other shape of overflow: the API
rejecting the prompt outright with a 400 because the input plus
`max_completion_tokens` doesn't fit in the model's context window.

This shows up immediately on local OpenAI-compatible servers (LM
Studio, llama.cpp, vLLM) where the default context is small (4K-32K)
and a 60K-token chunk packed for cloud Kimi/Claude blows past it.
Without retry the whole chunk fails with no output, even though the
two halves would each fit cleanly.

Catch a heuristic set of context-overflow exception messages,
classify them as the same kind of recoverable failure as
`finish_reason="length"`, and split-recurse on the same path. Single-
file overflow returns an empty fragment so the rest of the corpus
keeps running. Unrelated errors (rate limit, auth, etc.) still
propagate.

Tested with qwen3.5-9b on LM Studio (32K ctx) against a 215-file
corpus where chunks 4-12 of 12 previously failed; with this change
the overflowing chunks self-heal by splitting in half.
2026-05-09 12:59:35 +01:00
Safi 0c29b2cb88 fix reversed call edges after --update and missing SKILL.md on install (#760, #725)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 22:00:57 +01:00
Safi c8dcd03b08 document graphify uninstall command in README
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 20:40:07 +01:00
Safi 480eaea2a8 add graphify uninstall command - removes all platforms in one shot
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-08 20:38:08 +01:00
zuyeyang 5d0392524a fix(extract): add ALTER TABLE FK extraction + schema-qualified name support for SQL (#779)
The SQL parser (`extract_sql`) previously only extracted foreign key
relationships defined inline within CREATE TABLE column definitions.
FK constraints added via ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY
... REFERENCES were silently ignored.

Additionally, `_obj_name()` only read the first identifier child of
object_reference nodes, so schema-qualified names like `Sales.Customer`
were truncated to just `Sales`.

Changes:
- Add `alter_table` handler to `walk()` that extracts FK edges from
  ALTER TABLE ... ADD CONSTRAINT ... FOREIGN KEY ... REFERENCES
- Fix `_obj_name()` to read the full object_reference text, preserving
  schema-qualified names (e.g. `Sales.Customer`)
- Fix inline FK resolution in create_table and _walk_from_refs to use
  full object_reference text instead of first identifier only
2026-05-08 20:31:25 +01:00
Safi ef1050b0e4 bump version to 0.7.10
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.7.10
2026-05-07 20:17:02 +01:00
Chris S ca1b774dd9 Harden Google Workspace gws exports (#772) 2026-05-07 20:07:57 +01:00
Arjun Pramanik e16ea149aa refactor(__main__): strengthen agent instructions sections with forceful graph-first directives (#775)
Rewrote _CLAUDE_MD_SECTION, _AGENTS_MD_SECTION, and _GEMINI_MD_SECTION to use forceful ALWAYS/NEVER directives instead of soft suggestions.
Agents must now consult the knowledge graph before file operations.

Context:
- Updated AGENTS.md template injected via _agents_install()
- Updated CLAUDE.md template injected via claude install
- Updated GEMINI.md template injected via gemini_install()
2026-05-07 20:07:53 +01:00
Arjun Pramanik a15cb36dfc fix(skills): rewrite YAML descriptions from pipeline-only to trigger-oriented (#774)
10 skill-*.md files had descriptions that only described what graphify does (input->pipeline->output), not when agents should use it. This meant skills never loaded proactively on codebase questions.

Changed to hybrid descriptions that retain the pipeline summary but add trigger conditions: 'Use when user asks any question about a codebase, project content, architecture, or file relationships'.
2026-05-07 20:07:49 +01:00
SerkanGezici 8489b26d06 fix(extract): use language_tsx for .tsx files to enable JSX-aware parsing (#766)
tree-sitter-typescript ships two grammars:
- language_typescript: pure TypeScript, no JSX support
- language_tsx:        JSX-aware variant for .tsx files

Currently both .ts and .tsx are parsed with language_typescript, which
treats JSX syntax as parse errors. Every function declaration, arrow
function, and call_expression nested inside a JSX tree is silently
dropped from the extracted graph.

Repro on a representative React+TypeScript codebase (a 13-file Tauri app):
parsing each .tsx with language_typescript produces ~276 ERROR nodes per
file. Only declarations that happen to live before the first JSX block
survive.

Fix: add _TSX_CONFIG that mirrors _TS_CONFIG but selects language_tsx,
and route .tsx files to it in extract_js().

Effect on the same repo (graphify update --force):
  Nodes:        303 → 618  (+104%)
  Edges:        482 → 779  (+62%)
  Communities:   28 → 45   (+61%)
  Parse errors  276 → 0    per .tsx file

Tests added:
- tsx fixture with helpers + JSX-returning component
- helpers and component are captured
- JSX expression calls ({fmtDate(now)}) resolve to call edges
- wiring check: .tsx uses language_tsx, .ts uses language_typescript

Note: this fixes the parsing layer. Calls inside deeply nested arrow
function callbacks (e.g. items.map(x => <T>{f(x)}</T>)) are still
missed by the call extraction logic — separate enhancement.

Co-authored-by: Serkan Gezici <serkan@quadroaipilot.com>
2026-05-07 20:07:36 +01:00
Safi 3e1c257dde add X link to README badges 2026-05-07 18:26:08 +01:00
Safi 853f4baad4 add PowerShell usage note to README 2026-05-07 16:37:35 +01:00
Safi 0656ec62a4 security hardening: F-002/F-005/F-007/F-008/F-009/F-010/F-016/F-031/F-035/F-038/PR747-NEW-2 2026-05-07 16:32:26 +01:00
Safi cf46be439a document AWS Bedrock backend in README privacy section and command reference 2026-05-07 14:51:41 +01:00
Safi aa2bd138b7 fix edges/links key mismatch in query, path, explain, and MCP loader (#768) 2026-05-07 14:48:51 +01:00
Safi 7c6c5242dc shrink star history chart width to 370px in README 2026-05-07 13:58:40 +01:00
Safi c8da4a7082 add Kimi Code CLI platform support (graphify install --platform kimi) 2026-05-07 13:16:15 +01:00
Safi 13947c3a05 add MCP resources: report, stats, god-nodes, surprises, audit, questions 2026-05-07 13:13:54 +01:00
Safi 96c1d04889 bump version to 0.7.9, update README and CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.7.9
2026-05-07 12:09:46 +01:00
Safi 3529d46fd2 add PR numbers to 0.7.9 CHANGELOG entries
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 11:19:12 +01:00
Safi fe76612d90 Merge PR #708: TypeScript interface/enum/type-alias/const/new_expression extraction 2026-05-07 11:07:24 +01:00
Safi 30860b61fb changelog: 0.7.9 -- add .qmd Quarto support entry 2026-05-07 11:05:24 +01:00
Safi 62bcf754d3 Merge PR #761: add .qmd (Quarto) file extension support 2026-05-07 11:03:57 +01:00
Safi b1ea93586b add .qmd to to_obsidian_canvas safe_name regex 2026-05-07 11:03:42 +01:00
Safi 9bc79ef6e3 trim noisy scalar const types from js_extra_walk, collapse docstring 2026-05-07 11:02:15 +01:00
Safi 2d44788931 add .qmd to to_obsidian_canvas safe_name regex 2026-05-07 11:02:11 +01:00
Safi 027fd7a1c1 remove spurious base_url from bedrock BACKENDS entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:53:53 +01:00
Safi 61e27fb1a5 add AWS Bedrock backend via boto3 Converse API 2026-05-07 10:51:45 +01:00
Safi 669bc32e0d Merge PR #752: Google Workspace shortcut export (.gdoc/.gsheet/.gslides)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:42:23 +01:00
Safi 6f15e5b102 pseudonymize Google account email with SHA256 hash in sidecar frontmatter
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:39:26 +01:00
Safi 9bbd14a7dd Merge PR #753: CommonJS require() imports as EXTRACTED edges
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-07 10:28:44 +01:00
Safi 09e69745bc Merge PR #759: Positional install platform names 2026-05-07 10:25:56 +01:00
Safi c986e28a70 Merge PR #758: Fix GRAPHIFY_OUT for query/path/explain 2026-05-07 10:25:50 +01:00
Safi 78a16c3733 Merge PR #672: Silence file_type None warning 2026-05-07 10:25:40 +01:00
Safi 935312c227 Merge PR #671: tree-sitter version mismatch hint 2026-05-07 10:25:35 +01:00
shym 1026695da7 feat: add .qmd file extension support
Adds support for Quarto markdown (.qmd) files by:
- Adding '.qmd' to document file extensions in detection
- Updating export logic to handle .qmd in filename sanitization
- Adding .qmd extractor dispatch using the existing markdown extractor
- Updating watch comments to include .qmd files
2026-05-07 11:13:14 +09:00
Chris Stephens 68804f7f70 Handle positional install platforms 2026-05-06 17:10:45 -04:00
Chris Stephens 81bc2f9298 Fix GRAPHIFY_OUT defaults for graph query commands 2026-05-06 17:04:57 -04:00