gitnexus 1.6.4-rc.40 → 1.6.4-rc.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,7 +66,8 @@ export function resolvePythonImportTarget(parsedImport, workspaceIndex) {
66
66
  * Precedence order:
67
67
  * 1. Workspace-root direct hit (`<pathLike>.py`, `<pathLike>/__init__.py`).
68
68
  * 2. Closest-ancestor match walking up from the importer's directory.
69
- * 3. Suffix fallback (first match).
69
+ * 3. Suffix fallback (deterministic: fewest path segments, then
70
+ * lexicographic on the normalized path).
70
71
  *
71
72
  * Root wins over ancestor by construction — if both `services/sync.py` and
72
73
  * `backend/services/sync.py` exist, `backend/routers/cron.py`'s
@@ -104,18 +105,44 @@ function resolveAbsoluteFromFiles(pathLike, allFilePaths, fromFile) {
104
105
  return candidatePkg;
105
106
  }
106
107
  }
107
- // Existing suffix-match fallback (preserved for monorepo/nested-repo
108
- // layouts that don't share a directory ancestor with the importer).
108
+ // Suffix-match fallback (preserved for monorepo/nested-repo layouts
109
+ // that don't share a directory ancestor with the importer).
110
+ //
111
+ // Tie-break order when multiple files match the same suffix:
112
+ // 1. Fewest path segments (shorter, more canonical paths win — `lib/x.py`
113
+ // beats `tooling/extras/x.py`).
114
+ // 2. Lexicographic order over the normalized path (final stable
115
+ // tiebreak independent of file-set insertion order).
116
+ //
117
+ // Without an explicit tie-break the previous implementation returned
118
+ // the first match in `Set` iteration order, which depended on file
119
+ // ingestion order and produced non-deterministic edges across runs in
120
+ // multi-directory collision repos.
109
121
  const suffixFile = `/${directFile}`;
110
122
  const suffixPkg = `/${directPkg}`;
111
- let suffixMatch = null;
123
+ const matches = [];
112
124
  for (const raw of allFilePaths) {
113
- const f = raw.replace(/\\/g, '/');
114
- if (suffixMatch === null && (f.endsWith(suffixFile) || f.endsWith(suffixPkg))) {
115
- suffixMatch = raw;
125
+ const norm = raw.replace(/\\/g, '/');
126
+ if (norm.endsWith(suffixFile) || norm.endsWith(suffixPkg)) {
127
+ matches.push({ raw, norm });
116
128
  }
117
129
  }
118
- return suffixMatch;
130
+ if (matches.length === 0)
131
+ return null;
132
+ if (matches.length === 1)
133
+ return matches[0].raw;
134
+ matches.sort((a, b) => {
135
+ const aDepth = a.norm.split('/').length;
136
+ const bDepth = b.norm.split('/').length;
137
+ if (aDepth !== bDepth)
138
+ return aDepth - bDepth;
139
+ if (a.norm < b.norm)
140
+ return -1;
141
+ if (a.norm > b.norm)
142
+ return 1;
143
+ return 0;
144
+ });
145
+ return matches[0].raw;
119
146
  }
120
147
  /**
121
148
  * Does the repo contain a module/package named `leadingSegment` somewhere
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitnexus",
3
- "version": "1.6.4-rc.40",
3
+ "version": "1.6.4-rc.41",
4
4
  "description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
5
5
  "author": "Abhigyan Patwari",
6
6
  "license": "PolyForm-Noncommercial-1.0.0",