Preserve the local regression-audit commits alongside their upstream squash and subsequent fixes. Resolve the overlapping changelog, regression tests, audit report, and name matcher to retain the reviewed upstream follow-ups.
Fixes#1840. Reuses and extends #1855 with lexical/import ownership and cache invalidation controls.
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fixes#1861. Reuses L4XB's receiver retention and owner resolution from #1866, with duplicate-owner and edit/sync guards.
Co-authored-by: L4XB <lukas.buck@e-mail.de>
Preserve the indexed-commit approach and regression cases from #1848, with dirty-path retention, commit-race guards, NUL Git paths, and failed-I/O recovery.
Fixes#1829.
Co-authored-by: Eric Minish <eric.minish@gmail.com>
* fix(ui): a screen's steps read as clusters, and a link too far to follow is said in words
The mobile app's /capture came back as a web: 100 boxes in a 1,227x5,588
ribbon, 113 lines drawn at rest crossing each other 652 times, each one
running over about five other boxes' names. Measured, not guessed — three
separate causes, very unequal.
The region grouping had nothing to divide there (98 of 100 boxes take their
region from one memoized component), so the picture fell back to a single
719px column. But the region dimension was not the lever. The lever was that
`packRegions` packed every step of one distance onto shared rows and wrapped
those rows at a fixed 720px, so a box and the thing it fires landed seven
lines apart: 70 of the 113 lines joined boxes ONE step apart. That is what
the crossings were made of.
So a region is now packed as CLUSTERS — a step, then the steps it sets in
motion on the line under it, stepped in — while the starting points that fire
nothing still share a line, because a screen's handlers are siblings and
giving each its own line turned a flat region into a column. A region's line
width is earned rather than fixed (sqrt(total * pitch), clamped 720..2600),
so a big screen comes out about as wide as it is tall.
Clustering makes most links local but not all: a step reached from two places
is drawn under whichever reached it first, so the other way in still crosses
the picture. Those are now said in WORDS at both ends — `-> resumeInference`
under the box that leads there, `<- CaptureView` under the box it arrives at,
capped at three with `+N more` — rather than drawn. This is not a hiding: the
link is stated, which says more than a line vanishing off the edge of the
screen does, and selecting the box draws every one of its real lines exactly
as before. It is the one at-rest cut that does not produce the "box that leads
somewhere and draws nothing" every earlier cut produced.
Also fixed while here, and predicted by the earlier region work: the in-region
row relaxation had no cycle guard, so a region holding one loop pushed 65 of
its boxes to rows 294-301 while the rest sat at 0-2. `forwardLinks` sets
cycle-closing links aside first, as the order reading's `withoutBackEdges`
already did.
/capture: 1,227x5,588 -> 2,279x4,356, at-rest crossings 652 -> 1,
lines-over-boxes 553 -> 26, with half the links still drawn as real lines and
every quiet box still one the screen itself fires directly. The order reading
is untouched (it keeps every line).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTUFNN5bH3aPw2gi2LqbYD
* fix(ui): a stub names its box without the mark the box wears for its kind
`← ⇠ onCaptureProgress +2` reads as two arrows arguing: the stub already
leads with a direction, and the box's own kind mark was competing with it.
Verified in the live canvas. The box keeps its mark, where nothing competes.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTUFNN5bH3aPw2gi2LqbYD
* fix(ui): the screen's line into each of its parts stops sweeping the picture
Audited all 51 screens of the mobile app on this branch. 96 lines — the
screen's own stand-in line into each region — were 17% of everything drawn
and caused 79% of every crossing left. A screen with ten regions tiles them
into bands, so the line into a region two bands down travelled the height of
the whole picture.
Two causes, both fixed. The entry the line lands on was the walk's first
member of the region; clustering moves a step that fires something BELOW the
ones that fire nothing, so that box could sit lines down inside the region
and the line had to reach past everything above it. It now lands on the box
nearest the region's top-left that the screen actually leads to. And the
stand-in line is no longer exempt from the stub rule — when the region is
still too far to follow, the link is said in words like any other. The rest
of the anchor's fan stays quiet as before: it is already stood in for.
Across the 51 screens: crossings 47 -> 10, no screen above 10 (worst was 19,
now 2); lines-over-boxes 236 -> 182; boxes with neither a line nor a word
150 -> 135.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTUFNN5bH3aPw2gi2LqbYD
* fix(ui): a screen's parts fill the canvas instead of squaring off into rows
Audited the app's 28 regioned screens: the median canvas was 55% region and
45% nothing, and /home was 44% — 4,860px tall to hold about 2,160px of
picture. The cause is that regions were tiled a row at a time with each row
as tall as its tallest member, so one short region beside a tall one left the
rest of that row blank, and a reader scrolls through the blank.
Each region now goes as high as it can and then as far left as it can, over a
skyline of what is already placed. Reading order is untouched: regions are
still walked in the screen's own source order, so an earlier one is never
pushed below a later one — a short one just tucks under another short one
rather than waiting for the tall one beside it. Layering now comes from the
finished geometry rather than a band counter, since once regions drop
independently what a reader sees as one row IS one row.
/home 4,860px -> 3,584px, aspect 0.59 -> 0.94. Tallest screen in the app
4,860 -> 4,356. Crossings 10 -> 13 across all 51 screens, still none above 10.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTUFNN5bH3aPw2gi2LqbYD
* fix(ui): the width a picture wraps at is tried, not estimated
A region's line width came from sqrt(total * pitch) — the width at which
total/width lines come out square. That estimate is wrong for how these
pictures are drawn: a cluster spends lines on its own structure (a hub gets a
line to itself, and what it fires starts another), so it undercounts a
region's lines badly and wrapped /capture's 98 boxes into a 4,356px column.
Laying a picture out is cheap and exact, so the widths are tried instead:
layoutAt runs the whole pack at each of eight widths and the best finished
canvas wins (~2ms for the model, all eight included). It has to be scored on
the CANVAS, not per region — squaring each region off individually leaves
fewer of them side by side, which took /home from 3,584px to 5,624px while
every region looked better on its own.
Also measured and rejected while here: dropping a region's CLUSTERS side by
side the way the regions drop onto the canvas. Total height 42,084 -> 39,756px
(-6%), but lines-over-boxes 120 -> 134 and crossings 5 -> 8, because two
clusters side by side put each one's lines through the other. Height is cheap
to scroll; a crossed line is what made this picture unreadable. The reasoning
is recorded in the code so it is not re-tried blindly. Regions differ — they
sit far enough apart that few lines run between them.
Across the app's 51 screens: tallest picture 4,356 -> 3,796px, total height
45,744 -> 42,084px, lines-over-boxes 184 -> 120, crossings 13 -> 5, and no
screen is a tall ribbon any more.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTUFNN5bH3aPw2gi2LqbYD
* stuff
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Reuse unsafeIndexRootReason before scanning indexed subprojects so stray manifests at home or broader roots cannot inject unrelated context. Preserve workspace adoption for #964.
Validation: four new regressions fail before the guard and pass after it; 48 relevant tests and npm run build pass. Confirmed the real os.homedir() leak before and after the fix with fixture cleanup.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
* fix(db): graceful FTS5 fallback when Node.js build lacks FTS5 support (#1532)
Official Node.js binaries do not compile FTS5 by default, causing codegraph
init to fail with 'no such module: fts5'. Added runtime FTS5 detection:
- Split schema execution to try FTS5 separately, skip on failure with warning
- Added fts5Available flag to DatabaseConnection and QueryBuilder
- Bulk-load and search paths skip FTS5 operations when unavailable
- Search falls back to LIKE + fuzzy matching when FTS5 is missing
(cherry picked from commit ed708b7f60)
* fix(db): preserve core schema during FTS5 fallback (#1532)
Keep required tables and indexes after the FTS triggers outside the
optional schema block in the upstream #1625 fix. Without this boundary,
simulated-missing-FTS5 indexing still fails on name_segment_vocab.
Add seven regressions using real SQLite with FTS5 creation intercepted,
covering initialization/open, LIKE and fuzzy search, non-FTS schema parity,
bulk no-ops, and real FTS5 search and bulk-load recovery. Credit
@aniruddhaadak80 under Unreleased fixes.
Validation on Linux x64 with Node v22.19.0:
- npm run build passed, including viewer and grammar asset checks.
- 34 tests passed across fts5-fallback, node-sqlite-backend,
sqlite-backend, and db-perf.
- Rebuilt CodeGraph initialization, indexing, reopening, search, and
cross-file callers passed with simulated missing FTS5 and real FTS5.
Fixes#1532.
Supersedes #1625.
---------
Co-authored-by: Aniruddha Adak <aniruddhaadak80@users.noreply.github.com>
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Adapt @uvmplus's PR #1481 (3ecf7479) to the shared symbol lookup and
named-symbol flow resolver on current main. Missing names return not found
with suggestions, and exact matches with no callers stay empty.
Preserve #1512 definition grouping and --file narrowing, #173 qualified
misses, and codegraph_node's intentional fuzzy file lookup. Port the
upstream regression suite and cover the moved shared lookup paths.
Validation on Linux with Node 22: project build, 74 requested tests,
47 related flow tests, and 16 same-fixture CLI/MCP checks pass. Baseline
captured 12 failing tests and 13 failing fixture checks.
Fixes#1473.
Supersedes #1481.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Adapt upstream PR #1485 by @valkyriweb (cc791cfc51)
onto current main. Keep the upstream alias-binding module and six-test suite
verbatim, preserve target-kind gating and default-export bindings, and add
one credited Unreleased changelog entry.
Linux verification (x86_64, Node 22.19.0): TypeScript build and asset copy
pass; the fresh ./impl.js repro changes callers/impact of realImpl from
missing consumerFn to including it. All 6 upstream tests and 231 related
resolver regression tests pass.
Fixes#1482
The Forge PR will supersede upstream PR #1485.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Land upstream PR #1687 by danusha2345 (fix commit 6e9bbb26), using the
PR tip implementation with only a Rust doc-comment placement cleanup.
Read parameter lists and return types positionally in the wasm extractor
and native kernel in lockstep, preserving verbatim signature text.
Verified on Linux x64 with Node 22.19.0: reproduced three undefined
signatures in both backends before the fix, then confirmed all three
expected signatures and exact wasm/kernel parity after rebuilding
TypeScript and the linux-x64 kernel. All 31 focused tests pass: 15 Kotlin
extraction, 6 Kotlin parity, and 10 kernel scaffold checks, with
CODEGRAPH_KERNEL_EXPECT=1 for the native suites.
Add the upstream #1495 changelog bullet while preserving all other
Unreleased entries. Keep EXTRACTION_VERSION unchanged for this bug fix.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
A project CodeGraph has no grammar for was indistinguishable from an empty one: unsupported extensions are filtered out at discovery, so filesDiscovered was 0, the reconciliation in index.ts found no shortfall and recorded index_state as complete, and the CLI printed the same 'No files found to index' it prints for an empty repo.
That silence is what makes it costly over MCP: an empty result reads identically to 'no match', and the agent has been told to trust the graph rather than grep.
The scan already visits every file, so the tally of what it declined to index costs no extra I/O and no second pass. index_state itself is left alone: changing its values would change the status --json contract, which is a call for the maintainer to make.
(cherry picked from commit 2c20892789)
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: netbrah <netbrah@users.noreply.github.com>
Apply upstream commit 1572d90d71 from
PR #1570 by @rongbc.
Clarify that suggested explore call counts are advisory and extra calls
remain available. Sync the MCP initialization guidance and eval probe,
retain the upstream regression tests, close the footer's bold formatting,
and credit the fix under Unreleased in the changelog.
Validation: npm run build; focused Vitest (3 files, 53 tests); source and
dist wording greps; git diff --check.
Fixes#1504
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
`codegraph affected` kept six regexes of its own — `.test.`, `.spec.`,
`/tests/`… — so a Go `foo_test.go`, a Python `test_foo.py` or a JVM
`FooTest.kt` beside the changed file was never reported, and "no tests
affected" read as "no coverage". Use isTestPath from search/query-utils,
the same predicate search and the MCP tools already rank by.
Cherry-picked from danusha2345's upstream PR #1688
(commit 995b6f1f26).
Preserve main's CLI imports and Unreleased entries, and credit the
contributor in the changelog. The default affected depth remains 5.
Fixes#1507.
Supersedes #1688.
Verified on Linux with Node 22.19.0: npm run build; the Go fixture
changes from no affected tests to math_test.go; matching and nonmatching
custom filters still override. Vitest: 3 files, 36 tests passed, including
the upstream Go/Python/Kotlin suite and affected path/dependency coverage.
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
Squash danusha2345's PR #1511 at d282f9e8 onto main 8c9c4761,
preserving its nine non-merge commits and main's existing Unreleased notes.
Calls in Kotlin, Java, TS/JS, Scala, Rust and Python declaration initializers
now retain the owner established by the upstream regression expectations.
Include the upstream CFML, dynamic-dispatch summary and viewer follow-ups.
Linux fail-to-pass validation (Node 22.19.0, rebuilt dist and native kernel):
- Before: TS load belonged to file:app.ts; Python/Kotlin/Scala/Rust calls
vanished; Java lost the field-lambda, anonymous override and eager calls.
- After: all six languages PASS; 12 native/WASM LF/CRLF parity checks PASS.
- Focused initializer regressions: 10 passed with CODEGRAPH_KERNEL=0 and
10 passed with the kernel enabled; Kotlin's grammar fallback is recorded.
- Related regression suites: 879 passed, 1 skipped across 15 test files.
- Evidence: /workspace/cg-1510-repro/before and /workspace/cg-1510-repro/after
(combined test output: after/vitest.log).
Fixes#1510
Supersedes #1511
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
* fix(cli): port upstream symbol lookup consistency (#1656, #1512)
Port ferrine/fix/symbol-lookup-consistency at
c0ccbacd3f onto current main.
Qualified CLI queries use the shared matcher and ambiguous names disclose
their targets. Keep total/limit/truncated and the human truncation notice
from #1674, and share the matcher with main's named-symbol-flow module.
Refs #1512. Upstream PR: #1656.
Co-authored-by: ferres <justferres@yandex.ru>
* fix(cli): group traversal results by definition (#1512)
Extend upstream PR #1656, ported in 7038fb4f, so callers/callees/impact
show separate sections for each definition and accept --file using the
same groupDefinitions helper as MCP. Preserve same-file overload groups,
path/suffix matching, and the explicit fallback when no file matches.
JSON definitions carry their roots, own neighbors/affected nodes, and
edges. Retain the legacy top-level lists as an explicitly labeled union
and preserve #1674 total/limit/truncated; each callers/callees definition
also reports its own limit and truncation metadata.
Validation: npm run build; 141 tests across 14 targeted suites, including
32 CLI regression tests. The Linux /workspace/cg1512-repro failure now
passes for all three commands, with and without --file.
Fixes#1512.
Upstream PR: #1656 (ferrine/fix/symbol-lookup-consistency @ c0ccbacd).
---------
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Co-authored-by: ferres <justferres@yandex.ru>
Land upstream PR #1514 for issue #1513 by cherry-picking
ctype_lab's a94c9dc94e.
Keep allowBodilessStruct as a Rust-only opt-in, with matching behavior in
the wasm/TypeScript walker and native kernel. Create the node before
checking for a body and walk members only when present. Resolve against
main's shared struct/union walker while retaining its stack guard, kinds,
fields, and existing impl-receiver fixes.
Verified FAIL to PASS on Linux x64 with Node 22.19.0 after rebuilding via
tsc, copy-assets, and build:kernel. The identical fixture on main 7b339373
had two structs and two implements edges; fresh wasm (CODEGRAPH_KERNEL=0)
and native indexes now have three of each. UnitStruct and its Greet
implements edge are recovered; tuple and brace structs remain intact.
The native run loaded the rebuilt kernel and completed without fallback.
Focused extraction.test.ts and kernel-rustlang-parity.test.ts runs:
645 tests passed with the kernel disabled, and 645 with it enabled;
all three parity tests ran in each configuration, with no skips.
(cherry picked from commit a94c9dc94e)
Co-authored-by: ctype_lab <cksgud1226@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
An explicit path names the project to rebuild; it is not a hint to go
looking for one. resolveProjectPath's upward walk is right for a query run
from a subdirectory, but for a full re-index it silently rebuilt the
nearest initialized parent's graph when <path> had no index of its own.
Refuse with the parent's path and the way to index <path> itself; a bare
`codegraph index` still resolves from cwd as before.
Fixes#1524
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
* fix(resolution): gate extends/implements to real supertypes
An inheritance reference bound to whatever local symbol shared its name.
The name-matcher scores node kind as a bonus, never a filter, and awards
no bonus at all for inheritance refs, so `use std::error::Error;` +
`impl Error for MapperError {}` resolved to the local `MapperError::Error`
VARIANT — an implementation relationship absent from the source.
Two changes, both needed. Filtering by kind alone was measured and it
only RELOCATES the false edge: with enum members excluded, the same 7
refs moved onto an unrelated local `type Error` alias, which is a legal
supertype kind and therefore harder for a consumer to reject.
1. Eligibility before ranking. `matchByExactName` restricts its candidate
pool to kinds that can BE a supertype, so a legitimate trait outranks
a same-named variant instead of merely losing its edge. `resolveOne`
is wrapped by a gate that applies the same set to every other strategy
at one seam — filtering inside the name-matcher would have missed the
framework, import, chain and CFML paths.
2. Locality. A name imported from outside the repository has no in-repo
referent at all, so no candidate is correct. Only oracles that cannot
be wrong are consulted: Rust `use` paths rooted at a stdlib crate, and
`isExternalImport` for ES modules. Generalizing the Rust side to "the
module path doesn't resolve to a file" was tried and reverted — a
crate re-exporting a sibling's modules (`pub use pupil_core::ports;`)
has no directory to walk, and that version deleted 13 real trait
implementations.
Measured on a Rust/Tauri project (2,682 nodes): the 11 false inheritance
edges are gone, all 59 real trait relationships are preserved, and node
count is unchanged. On this repository as a control, the only edge
removed is a class recorded as extending a function. Synthesized-edge
counts are identical in both.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(resolution): an import never resolves to a member of a type
`import * as path from 'node:path'` is unresolvable — the module is
external — so the name-matcher fell back to finding any node called
`path`, and a common word like path/url/join/get matches a class property
or interface method somewhere in almost any repo. Nothing in any
supported language lets an import bind to a member that only exists
inside a type; you import the type.
Same shape as the inheritance gate that precedes it: eligibility applied
to the candidate pool before ranking, plus the resolveOne gate as the
backstop for every other strategy.
On this repository as a control: 19 imports pointing at methods and 4 at
properties are gone (all of them coincidences — `Walker::join`,
`Telemetry::events`), 3 refs now find the module constant they actually
name, node count unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
* fix(resolution): classify SFC script imports as ES module specifiers
`isExternalImport` had a TS/JS branch listing typescript/tsx/javascript/jsx/
arkts, so for Svelte, Vue and Astro it fell through every branch and returned
false — "not external" — for `import { Foo } from 'some-npm-pkg'`.
An SFC imports inside its `<script>` block (Astro: the `---` frontmatter) with
ordinary ES module syntax; `extractImportMappings` already routes all three
through the same `extractJSImports`. So the classifier disagreed with the
extractor about what those imports are.
Effect on the preceding commit: its locality check asks `isExternalImport`, so
it silently did nothing for SFCs. A class in a `.svelte`/`.vue`/`.astro` file
implementing a type imported from an npm package still bound to whatever local
class shared that name — verified against this branch before the fix, all three
languages.
The language set is now one constant used by both the classifier and the
locality check, so they cannot drift apart again. Relative and aliased
specifiers are unaffected: the branch returns "not external" for `./…`,
workspace members, tsconfig alias prefixes, `@/`, `~/` and `src/` exactly as it
does for `.ts`.
No edge changes on this repository as a control.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---------
Co-authored-by: ctype_lab <cksgud1226@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Land upstream PR #1604 by @maxmilian from commit
27c149524d on current main cece0720.
Fixes#1549.
Use the upstream lsFilesStaged helper at both collection and embedded-repo
discovery call sites. Retry without --recurse-submodules when staged
recursive listing fails, retaining the mode bits needed for gitlinks.
Keep the upstream regression test byte-for-byte and preserve main's
existing extraction/watcher changes, including #1728. Resolve the
changelog conflict with a concise Unreleased entry, and keep the existing
collectGitFiles documentation attached to its function.
Verified on Linux x86_64 with Node 22.19.0 and Git 2.47.3:
- The unchanged upstream test fails against main: expected [ 'a.ts' ]
to include 'dir_b/b.ts'; it passes with the fix.
- The same persistent fixture under a PATH shim rejecting -s with
--recurse-submodules (exit 128) changes scanDirectory from [a.ts]
to [a.ts, dir_b/b.ts], and gitlink watcher roots from [] to [lib/].
- Real-Git controls return both files and the watcher root in both arms.
- 69 related scope/config tests and 23 extraction scanning tests pass.
- npx tsc --noEmit passes.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: newshowardz777 <newshowardz777@users.noreply.github.com>
Land the six-file fix from upstream PR #1691 by danusha2345
(pr-1691 at 6d0e80d52a), preserving
wasm/native extraction parity and exclusive field-type resolution.
Preserve coexistence with the #1566 Map/collection fix merged in #1790,
including nested holder.values.get coverage and the unchanged #1566
Unreleased changelog bullet. EXTRACTION_VERSION remains unchanged.
Align the existing chained-receiver regression with the fix: a declared
service field calls its method, while an anonymous field type does not
bind to unrelated same-named project functions.
Verified on Linux with Node 22.19.0:
- Rebuilt the native kernel and TypeScript/browser distribution.
- Both backends change Outbox::send -> Outbox::send into
Outbox::send -> Mailer::send, keep Relay::forward -> Mailer::send,
and store no self-edges in the issue repro.
- Wasm: 224 tests passed; native kernel: 255 tests passed, no skips.
- All 10 #1566 resolution cases pass on each backend, plus all four
nested-receiver extraction parity cases.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Land the #1624 approach by @danusha2345: re-serve source by default so
subagents and compacted contexts never inherit stale already-sent pointers.
Keep cross-call dedup available through explicit truthy
CODEGRAPH_EXPLORE_DEDUP values for durable contexts.
Preserve current Unreleased entries, credit the contribution, and align
the MCP server guidance with the safe default.
Validation on Linux / Node 22.23.2:
- Reproduced default-on failure before the fix; default-off now passes.
- Focused explore-cross-call-dedup suite: 26 passed.
- TypeScript: npx tsc -p tsconfig.json --noEmit passed.
Fixes#1620.
(cherry picked from commit 63992facab)
Co-authored-by: danusha2345 <ewidusoc498@gmail.com>
* fix(resolution): resolve Python module members through an aliased from-import (#1626)
resolvePythonModuleMember rebuilt the submodule's dotted path by joining the
import source with the LOCAL name. Under 'from pkg import mod as alias' that
produces 'pkg.alias' — a module that does not exist — so the file lookup found
nothing and the call fell through to unresolved_refs with status='failed'.
codegraph_callers then reported the target as having fewer callers than it
does, which is the same wrong 'is this dead code?' answer #578 produced for
the unaliased form.
Join with the exported name instead. For an unaliased import the two names are
identical, so nothing changes there; '*' (the namespace form) keeps using the
local name, which is what it already bound to.
Scope note: the issue also reports 'import top as alias' failing. That form is
a namespace import and binds at source, so it resolves on current main — a
probe against the reverted resolver confirms it already produces its call edge.
The regression test pins both halves so the working one cannot silently break.
Co-Authored-By: Claude <noreply@anthropic.com>
(cherry picked from commit f7a8940e67)
* fix(resolution): restore aliased Python module import edges (#1626)
Use the exported module name in the file-import resolver, matching the member resolver from upstream PR #1635. Keep both aliased call assertions and verify the file-to-file imports edge in the #1626 regression test. Update the Unreleased note to cover file dependencies.
Validation on Node 22.19.0: npm run build; supplied cg1626 repro; vitest run __tests__/resolution.test.ts -t 1626. Pass evidence saved in /workspace/cg1626-PASS.json and /workspace/cg1626-VERIFY.json.
---------
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
* fix(installer): honor CODEX_HOME for the Codex global install (#1627)
Codex resolves its user layer from `CODEX_HOME` and only falls back to
`~/.codex`. The target hardcoded the fallback, so a user on a custom profile
got a correct install into a directory Codex never reads — the MCP entry, the
AGENTS.md block, and detect() all pointed at the wrong profile, and the
failure is silent.
Resolve the global config dir from `CODEX_HOME` when set and non-blank,
mirroring what the copilot-cli target already does for `COPILOT_HOME`. Only
the user layer moves; the project layer (#1531) stays anchored to the project.
The test harness now also clears `CODEX_HOME` in setHome() alongside
HERMES_HOME/COPILOT_HOME — without that, the existing codex tests fail on a
developer machine that has the variable exported.
Note this is only half of #1627: the CLAUDE_CONFIG_DIR half is already
covered by the open PR #1029, which this deliberately does not touch.
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(installer): honor CLAUDE_CONFIG_DIR for global Claude installs
Build on #1633 by @maxmilian and port the CLAUDE_CONFIG_DIR approach
from #1029 by @borfast onto the current installer. Keep the CODEX_HOME
cherry-pick cbb08231 intact.
Resolve non-blank Claude profile paths with path.resolve. Put the global
MCP JSON inside a custom profile while preserving ~/.claude.json for the
default profile. Settings, instructions, detection, and uninstall follow
the selected profile; local installs keep their existing paths.
Clear and restore CLAUDE_CONFIG_DIR in the setHome test harness. Cover
absolute and relative profiles, idempotency, unset/empty/blank fallback,
default-profile preservation, detection/uninstall, and local installs.
Combine the Unreleased note for both environment variables.
Thanks @seanchann for reporting the issue.
Validation on Linux with Node 22.19.0:
- npx tsc -p tsconfig.json
- npx vitest run __tests__/installer-targets.test.ts: 245 passed, 3 skipped
- Reproduced both failures against main e720f6ca; the rebuilt CLI writes
all files into CLAUDE_CONFIG_DIR and CODEX_HOME with no ~/.claude,
~/.claude.json, or ~/.codex created.
Fixes#1627
---------
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Land upstream PR #1634 by @maxmilian, commit
8d398a92e3.
Path-only detection classifies .h files as c, so preloading previously
covered c and cpp but missed objc selected by content-aware detection.
Preload objc alongside cpp whenever c is present. Full indexing and
changed-file reindexing now share preloadLanguagesForFiles().
Retain all four upstream unit tests and place the existing #1628 changelog
entry under Unreleased / Fixes / Symbols, tests and the viewer.
Verified fail -> pass on Linux with the reporter's repro.h as the only
source file, without a .m or .mm grammar seed. Before: Objective-C parser
initialization failure, 0 nodes, index state failed. After: Indexed 1 files,
2 nodes, 1 edge, index state complete; node CGRepro finds the class and
errors.log is absent.
Validation: npx tsc && npm run copy-assets passed; rebuilt CLI is executable.
npx vitest run __tests__/preload-languages.test.ts: 4 tests passed.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>
Co-authored-by: Max Hsu <maxmilian@gmail.com>
Land upstream #1686 (maxmilian + bompus kernel/CG-28 follow-ups)
onto current main. tree-sitter-typescript interface members
(method_signature / property_signature) were never listed in the
TS extractor, so platform .d.ts APIs had no declaration nodes for
call edges. Mirrors on the Rust kernel path; keeps CG-28 damping
for pure-interface declaration files; filters damped files from
the explore RWR seed set.
Co-authored-by: Colby McHenry <colbymchenry@users.noreply.github.com>