Skip to content

package.json workspaces cross-repo IMPORTS still produce zero edges (v0.7.0 follow-up to #308) #408

Closed

Description

@GonEbal

Summary

Following the v0.7.0 fix in #308 (tsconfig.json paths), cross-package IMPORTS still produce zero edges for monorepos that use package.json workspaces + Lerna/Yarn workspaces (the most common JS monorepo pattern) instead of tsconfig path aliases.

The README claims this is supported via generic @myorg/pkg manifest resolution in pass_pkgmap.c:

Generic package / module resolution — bare specifiers like @myorg/pkg, github.com/foo/bar, use my_crate::foo resolved via manifest scanning (package.json, go.mod, Cargo.toml, ...)

However, in my testing on v0.7.0 (macOS arm64), pass_pkgmap.c either does not run or silently produces zero entries — no pkgmap.scan_repo / pkgmap.scan / pkgmap.build log lines appear during indexing, and zero cross-package IMPORTS edges are produced.

Environment

  • codebase-memory-mcp: 0.7.0 (verified --version)
  • OS: macOS 24.6.0 (Darwin arm64)
  • Install method: official install.sh (ui variant)

Minimal reproduction

mkdir -p cbm-test/pkg-a/src cbm-test/pkg-b/src

cat > cbm-test/pkg-a/package.json <<EOF
{"name": "@test/pkg-a", "main": "src/index.js"}
EOF
cat > cbm-test/pkg-b/package.json <<EOF
{"name": "@test/pkg-b", "main": "src/index.js"}
EOF

cat > cbm-test/pkg-a/src/index.js <<EOF
import { foo } from '@test/pkg-b';
export const a = () => foo();
EOF
cat > cbm-test/pkg-b/src/index.js <<EOF
export const foo = () => 42;
EOF

codebase-memory-mcp cli index_repository '{"repo_path":"/tmp/cbm-test"}' 2>&1 | grep -iE "pkgmap"
# → no output (expected: pkgmap.scan_repo / pkgmap.build log lines)

codebase-memory-mcp cli query_graph '{"project":"tmp-cbm-test","query":"MATCH (a)-[r:IMPORTS]->(b) RETURN a.file_path, b.file_path"}'
# → 0 rows

Expected: an IMPORTS edge from pkg-a/src/index.js to pkg-b/src/index.js because the pkgmap should resolve @test/pkg-b via the package.json "name" field.

Actual: 0 IMPORTS edges, no pkgmap log lines.

Real-world impact

I'm indexing a 13-repo monorepo workspace (~140K nodes, ~214K edges, 13K files). All repos are Lerna+Yarn workspaces publishing internal packages under @pandora/ / @commerce-exp/. Cross-repo imports use the published package name. Expected behavior: graph treats them as a single fleet with normal IMPORTS edges. Actual: every cross-repo import is dropped.

Workaround attempted: synthesize a root tsconfig.json at the workspace level with paths mapping every internal @pandora/foo → <repo>/packages/foo/src/index.ts. This did trigger path_alias.c (saw path_alias.files.cap_hit kept=256_of_more warn) but still produced zero cross-repo edges because:

  1. CBM_PATH_ALIAS_MAX_ENTRIES = 256 per single tsconfig (we have 328+ packages → 70+ silently dropped)
  2. CBM_PATH_ALIAS_MAX_FILES = 256 total tsconfigs per repo walk (we have 352 → root tsconfig may not be among the 256 selected)
  3. cbm_path_alias_find_for_file picks the nearest ancestor scope, so every source file inside an inner package picks up its own local tsconfig.json rather than the workspace-root one we wrote, never seeing our cross-repo paths

Suggested improvements

  1. Diagnose pass_pkgmap.c silent failure on JS/TS workspaces (no log emission at all suggests it isn't being invoked or returns NULL before logging). The walker logic in pkgmap_walk_dir looks correct from the source. Add an info log even when 0 entries are produced.
  2. Honor package.json workspaces arrays so a root manifest with "workspaces": ["packages/*"] (or globs across child repos) gives a scope to bare-specifier resolution that spans them.
  3. Aggregate tsconfig path aliases from ancestors rather than nearest-only — or, when a file matches no nearer alias, fall back to ancestors instead of stopping at the first tsconfig found.
  4. Raise (or make configurable) the CBM_PATH_ALIAS_MAX_ENTRIES = 256 and CBM_PATH_ALIAS_MAX_FILES = 256 caps. Real monorepos easily exceed both.
  5. Document the limitation in the README under "Cross-repo intelligence" — specifically that @myorg/pkg resolution currently does not bridge across package.json-workspaces sibling repos, even though the README example "@myorg/pkg" implies it does.

Happy to test fixes against a public 13-repo repro if helpful.

Activity

  1. added
    bugSomething isn't working
    parsing/qualityGraph extraction bugs, false positives, missing edges
    on Jun 6, 2026
  2. DeusData commented on Jun 7, 2026

    @DeusData
    Owner

    Update: I dug into this and found + fixed one real gap — the repo-wide manifest walk (cbm_pkgmap_scan_repo) was a no-op on Windows, so package.json workspace names were never resolved there (cross-package IMPORTS = 0). It's now cross-platform and depth-bounded (cannot hang on directory junctions) on main (586729b), with a regression test.

    That said, I want to be careful: on macOS/Linux I can't reproduce zero cross-package edges with a standard workspaces layout — a fixture where packages/b imports a sibling by its name (@org/a) resolves to a cross-package IMPORTS edge for me (now covered by contract_edge_workspaces_imports_issue408). Since your report was on macOS, your specific layout may be hitting a different path.

    Could you share a minimal repro? Specifically:

    • the root package.json and a couple of package package.json files (do the packages set "name"? "main" or "exports"?),
    • one example cross-package import statement,
    • and whether any pkgmap.scan_repo / pkgmap.build lines appear in the logs (now visible with CBM_LOG_LEVEL=debug).

    Leaving this open pending that — happy to chase the macOS case once I can reproduce it.

  3. GonEbal commented on Jun 10, 2026

    @GonEbal
    Author

    Thanks for the quick turnaround on the Windows fix — and for keeping this open while we narrow down the macOS path.

    Below is a minimal canonical-workspaces repro on macOS (Darwin arm64, codebase-memory-mcp 0.7.0 from the published install.sh) that produces 0 IMPORTS edges and 0 pkgmap.* log lines even with CBM_LOG_LEVEL=debug. This is much smaller than my original case and uses the exact layout your new contract_edge_workspaces_imports_issue408 fixture should be modeled on, so it should be easy to compare against.

    Files

    /tmp/cbm-issue408-repro/package.json:

    {
      "name": "monorepo-root",
      "private": true,
      "workspaces": ["packages/*"]
    }

    /tmp/cbm-issue408-repro/packages/pkg-a/package.json:

    {
      "name": "@test/pkg-a",
      "version": "1.0.0",
      "main": "src/index.js"
    }

    /tmp/cbm-issue408-repro/packages/pkg-b/package.json:

    {
      "name": "@test/pkg-b",
      "version": "1.0.0",
      "main": "src/index.js"
    }

    packages/pkg-a/src/index.js:

    import { foo } from '@test/pkg-b';
    export const a = () => foo();

    packages/pkg-b/src/index.js:

    export const foo = () => 42;

    Command + result

    $ CBM_LOG_LEVEL=debug codebase-memory-mcp cli index_repository \
        '{"repo_path":"/tmp/cbm-issue408-repro"}' 2>&1 | grep -iE "pkgmap|workspace"
    # → (no output)
    

    Full pipeline log lines that do appear (no pkgmap pass anywhere in the sequence):

    pipeline.discover files=2
    pipeline.route path=full
    pass.start pass=structure files=2
    pass.done  pass=structure nodes=8 edges=4
    pass.start pass=definitions files=2
    pass.done  pass=definitions defs=4 calls=1 imports=0 errors=0
    pass.start pass=k8s files=2
    pass.start pass=lsp_cross files=2
    pass.start pass=calls files=2
    pass.start pass=usages files=2
    pass.start pass=semantic files=2
    pass.start pass=tests
    pass.start pass=similarity
    pass.start pass=semantic_edges
    pipeline.done nodes=12 edges=9 elapsed_ms=71
    

    And the graph confirms:

    $ codebase-memory-mcp cli query_graph \
        '{"project":"tmp-cbm-issue408-repro","query":"MATCH (a)-[r:IMPORTS]->(b) RETURN a.qualified_name, b.qualified_name"}'
    {"columns":["a.qualified_name","b.qualified_name"],"rows":[],"total":0}
    

    So on macOS the pkgmap pass appears not to be scheduled at all (it’s not in the pass.start sequence), which would explain both the imports=0 counter in pass=definitions and the absence of any pkgmap.* log lines. That lines up with what I noticed earlier when reading pass_pkgmap.c: the walker logic looks right, it just doesn’t seem to be invoked on this platform.

    Answers to your questions

    • Do the packages set "name"? "main" / "exports"? Yes to name and main; no exports in the repro. In my real-world workspace the inner packages additionally set module and types, but no exports. Happy to test an exports-only variant if useful.
    • Cross-package import statement — see packages/pkg-a/src/index.js above (import { foo } from '@test/pkg-b';).
    • pkgmap.scan_repo / pkgmap.build in logs? None, even at CBM_LOG_LEVEL=debug.

    Env

    • codebase-memory-mcp 0.7.0 (release binary; commit 586729b on main not yet shipped)
    • macOS 15.x, Darwin 24.6.0 arm64
    • Install: official install.sh (ui variant) → ~/.local/bin/codebase-memory-mcp

    Happy to test a pre-release with the 586729b fix on macOS if you can publish one, or build from main against a tag if you’d prefer. Also glad to run additional repro variants (exports-only, nested workspaces, scoped vs unscoped names, .js vs .ts) — just say the word.

  4. DeusData commented on Jun 12, 2026

    @DeusData
    Owner

    Thanks for the minimal canonical-workspaces repro — exactly what's needed. Will investigate why the macOS path produces zero pkgmap log lines even at debug level.

  5. DeusData commented on Jun 26, 2026

    @DeusData
    Owner

    This is fixed. cbm_pkgmap_build_from_repo now also walks the filesystem for package.json manifests that the main discoverer filters out, then resolves a workspace specifier (@org/pkg) to the sibling package's entry-module QN — so a bare-specifier import like import { fromA } from '@org/a' between workspace packages produces the cross-package IMPORTS edge.

    Guarded with a fixture whose only possible IMPORTS edge is the cross-package one (no relative imports, no dependencies field), so the guard genuinely exercises workspace resolution.

    Closing as fixed — reopen if a specific monorepo layout still yields zero cross-package edges. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edges

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions