pi-shazam 0.18.2 → 0.19.1

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.
@@ -19,7 +19,7 @@ export declare function saveGraphCache(graph: RepoGraph, fileMtimes: Map<string,
19
19
  export type GraphCacheData = GraphCacheDataExport;
20
20
  /**
21
21
  * Load a persistent graph cache. Returns null if missing, corrupt, wrong
22
- * version, or older than 7 days.
22
+ * version, or older than 1 day.
23
23
  */
24
24
  export declare function loadGraphCache(cachePath: string): GraphCacheData | null;
25
25
  //# sourceMappingURL=cache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../core/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,IAAI,oBAAoB,EAAE,MAAM,YAAY,CAAC;AASpF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAO9D;AA0BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAsBzG;AAED,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAElD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAwBvE"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../core/cache.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,IAAI,oBAAoB,EAAE,MAAM,YAAY,CAAC;AASpF;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAc9D;AA0BD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAsBzG;AAED,MAAM,MAAM,cAAc,GAAG,oBAAoB,CAAC;AAElD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAwBvE"}
@@ -24,7 +24,15 @@ export function getProjectCacheDir(projectPath) {
24
24
  const hash = createHash("sha256").update(canonical).digest("hex").slice(0, 8);
25
25
  const projectName = canonical.split("/").pop() || "unknown";
26
26
  const cacheDir = join(CACHE_ROOT, `${projectName}_${hash}`);
27
- mkdirSync(cacheDir, { recursive: true });
27
+ try {
28
+ mkdirSync(cacheDir, { recursive: true });
29
+ }
30
+ catch (err) {
31
+ // Cache directory is a best-effort optimization. If we cannot create it
32
+ // (EACCES, EROFS, ENOSPC, ENAMETOOLONG), degrade gracefully: log a
33
+ // warning and continue without caching. The scan itself still works.
34
+ console.warn(`[pi-shazam] getProjectCacheDir: cannot create cache directory ${cacheDir}: ${err}`);
35
+ }
28
36
  return cacheDir;
29
37
  }
30
38
  // -- Persistent graph cache (V2) ----------------------------------------------
@@ -83,7 +91,7 @@ export function saveGraphCache(graph, fileMtimes, cachePath) {
83
91
  }
84
92
  /**
85
93
  * Load a persistent graph cache. Returns null if missing, corrupt, wrong
86
- * version, or older than 7 days.
94
+ * version, or older than 1 day.
87
95
  */
88
96
  export function loadGraphCache(cachePath) {
89
97
  if (!existsSync(cachePath))
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../core/cache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../core/cache.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../core/encoding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC3C,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,KAAK,EAAE,MAAM,CAAC;gBAElB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAOrD;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2CzD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC7E"}
1
+ {"version":3,"file":"encoding.d.ts","sourceRoot":"","sources":["../../core/encoding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH;;;;GAIG;AACH,qBAAa,iBAAkB,SAAQ,KAAK;IAC3C,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,KAAK,EAAE,MAAM,CAAC;gBAElB,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAOrD;AAQD;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2DzD;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyD7E"}
@@ -68,8 +68,24 @@ export function readFileAdaptive(filePath) {
68
68
  // Try UTF-8 first
69
69
  const utf8Result = tryDecode(validationBuffer, "utf-8");
70
70
  if (utf8Result !== null) {
71
- // UTF-8 validation passed on chunk -- decode full buffer
72
- return buffer.length > VALIDATION_CHUNK_SIZE ? buffer.toString("utf-8") : utf8Result;
71
+ // UTF-8 validation passed on chunk.
72
+ // For large files, the first 64KB may be valid UTF-8 while later bytes
73
+ // are GBK/GB2312 (#438). Decode full buffer as UTF-8, then check
74
+ // replacement character ratio on the full decoded string. If >5%,
75
+ // fall back to GBK -> GB2312 on the full buffer.
76
+ if (buffer.length > VALIDATION_CHUNK_SIZE) {
77
+ const fullUtf8 = buffer.toString("utf-8");
78
+ if (_replacementRatio(fullUtf8) <= 0.05)
79
+ return fullUtf8;
80
+ const fullGbk = iconv.decode(buffer, "gbk");
81
+ if (_replacementRatio(fullGbk) <= 0.05)
82
+ return fullGbk;
83
+ const fullGb = iconv.decode(buffer, "gb2312");
84
+ if (_replacementRatio(fullGb) <= 0.05)
85
+ return fullGb;
86
+ return fullUtf8;
87
+ }
88
+ return utf8Result;
73
89
  }
74
90
  // Try GBK
75
91
  const gbkResult = tryDecode(validationBuffer, "gbk");
@@ -111,7 +127,24 @@ export async function readFileAdaptiveAsync(filePath) {
111
127
  // Try UTF-8 first
112
128
  const utf8Result = tryDecode(validationBuffer, "utf-8");
113
129
  if (utf8Result !== null) {
114
- return buffer.length > VALIDATION_CHUNK_SIZE ? buffer.toString("utf-8") : utf8Result;
130
+ // UTF-8 validation passed on chunk.
131
+ // For large files, the first 64KB may be valid UTF-8 while later bytes
132
+ // are GBK/GB2312 (#438). Decode full buffer as UTF-8, then check
133
+ // replacement character ratio on the full decoded string. If >5%,
134
+ // fall back to GBK -> GB2312 on the full buffer.
135
+ if (buffer.length > VALIDATION_CHUNK_SIZE) {
136
+ const fullUtf8 = buffer.toString("utf-8");
137
+ if (_replacementRatio(fullUtf8) <= 0.05)
138
+ return fullUtf8;
139
+ const fullGbk = iconv.decode(buffer, "gbk");
140
+ if (_replacementRatio(fullGbk) <= 0.05)
141
+ return fullGbk;
142
+ const fullGb = iconv.decode(buffer, "gb2312");
143
+ if (_replacementRatio(fullGb) <= 0.05)
144
+ return fullGb;
145
+ return fullUtf8;
146
+ }
147
+ return utf8Result;
115
148
  }
116
149
  // Try GBK
117
150
  const gbkResult = tryDecode(validationBuffer, "gbk");
@@ -199,6 +232,20 @@ function isValidUtf8(buffer) {
199
232
  }
200
233
  return true;
201
234
  }
235
+ /**
236
+ * Compute the ratio of Unicode replacement characters (U+FFFD) in a string.
237
+ * Returns 0-1. Used to detect encoding misdetection for large files (#438).
238
+ */
239
+ function _replacementRatio(str) {
240
+ if (str.length === 0)
241
+ return 0;
242
+ let count = 0;
243
+ for (const ch of str) {
244
+ if (ch === "\uFFFD")
245
+ count++;
246
+ }
247
+ return count / str.length;
248
+ }
202
249
  /**
203
250
  * Try to decode a buffer with a given encoding.
204
251
  * Returns the decoded string if successful, or null if invalid.
@@ -220,12 +267,7 @@ function tryDecode(buffer, encoding) {
220
267
  // Replacement-character ratio check (#368): iconv-lite emits U+FFFD for
221
268
  // unmappable bytes. If >5% of decoded characters are replacements,
222
269
  // the encoding is wrong -- reject to try the next fallback.
223
- let replacementCount = 0;
224
- for (const ch of str) {
225
- if (ch === "�")
226
- replacementCount++;
227
- }
228
- if (replacementCount / str.length > 0.05)
270
+ if (_replacementRatio(str) > 0.05)
229
271
  return null;
230
272
  return str;
231
273
  }
@@ -1 +1 @@
1
- {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../core/encoding.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,QAAQ,IAAI,aAAa,EAAE,IAAI,IAAI,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAChF,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,6DAA6D;AAC7D,4EAA4E;AAC5E,qBAAqB;AACrB,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAEtC;;;;GAIG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAC3B,IAAI,CAAS;IACb,IAAI,CAAS;IACb,KAAK,CAAS;IAE9B,YAAY,IAAY,EAAE,IAAY,EAAE,KAAa;QACpD,KAAK,CAAC,mBAAmB,IAAI,YAAY,KAAK,MAAM,IAAI,EAAE,CAAC,CAAC;QAC5D,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;CACD;AAED,iEAAiE;AACjE,mDAAmD;AACnD,MAAM,qBAAqB,GAAG,EAAE,GAAG,IAAI,CAAC;AAExC,gFAAgF;AAEhF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAChD,gDAAgD;IAChD,IAAI,QAAgB,CAAC;IACrB,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAChC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC;QACrB,IAAI,QAAQ,GAAG,aAAa,EAAE,CAAC;YAC9B,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;QAChE,CAAC;IACF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;YACtC,MAAM,GAAG,CAAC,CAAC,0BAA0B;QACtC,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,iDAAiD,QAAQ,KAAK,GAAG,EAAE,CAAC,CAAC;QAClF,4GAA4G;IAC7G,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAEtC,gDAAgD;IAChD,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpH,kBAAkB;IAClB,MAAM,UAAU,GAAG,SAAS,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACxD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACzB,yDAAyD;QACzD,OAAO,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACtF,CAAC;IAED,UAAU;IACV,MAAM,SAAS,GAAG,SAAS,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,CAAC;IAED,aAAa;IACb,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1F,CAAC;IAED,sCAAsC;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,QAAgB;IAC3D,gDAAgD;IAChD,IAAI,CAAC;QACJ,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC;QACvC,IAAI,IAAI,CAAC,IAAI,GAAG,aAAa,EAAE,CAAC;YAC/B,MAAM,IAAI,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,aAAa,CAAC,CAAC;QACjE,CAAC;IACF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACd,IAAI,GAAG,YAAY,iBAAiB,EAAE,CAAC;YACtC,MAAM,GAAG,CAAC;QACX,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,sDAAsD,QAAQ,KAAK,GAAG,EAAE,CAAC,CAAC;QACvF,kFAAkF;IACnF,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,CAAC;IAE7C,gDAAgD;IAChD,wEAAwE;IACxE,MAAM,gBAAgB,GAAG,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAEpH,kBAAkB;IAClB,MAAM,UAAU,GAAG,SAAS,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IACxD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACzB,OAAO,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;IACtF,CAAC;IAED,UAAU;IACV,MAAM,SAAS,GAAG,SAAS,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC;IACrD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,CAAC;IAED,aAAa;IACb,MAAM,QAAQ,GAAG,SAAS,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IACvD,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC,MAAM,GAAG,qBAAqB,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC1F,CAAC;IAED,sCAAsC;IACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,gFAAgF;AAEhF;;;;;;;GAOG;AACH,SAAS,WAAW,CAAC,MAAc;IAClC,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,CAAE,CAAC;QAExB,iCAAiC;QACjC,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;YACjB,CAAC,EAAE,CAAC;YACJ,SAAS;QACV,CAAC;QAED,2CAA2C;QAC3C,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YAC5B,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW;QACxB,CAAC;aAAM,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACnC,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW;QACxB,CAAC;aAAM,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;YACnC,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW;QACxB,CAAC;aAAM,CAAC;YACP,iEAAiE;YACjE,OAAO,KAAK,CAAC;QACd,CAAC;QAED,yCAAyC;QACzC,kEAAkE;QAClE,+DAA+D;QAC/D,4DAA4D;QAC5D,yDAAyD;QACzD,IAAI,CAAC,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM;YAAE,MAAM;QAEtC,6CAA6C;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACjC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;YAC1B,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,KAAK,CAAC;QACxC,CAAC;QAED,2CAA2C;QAC3C,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YAClB,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,CAAC;YAC1D,IAAI,EAAE,GAAG,IAAI;gBAAE,OAAO,KAAK,CAAC,CAAC,gCAAgC;QAC9D,CAAC;aAAM,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,CAAC;YAC5F,IAAI,EAAE,GAAG,KAAK;gBAAE,OAAO,KAAK,CAAC,CAAC,iCAAiC;YAC/D,IAAI,EAAE,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM;gBAAE,OAAO,KAAK,CAAC,CAAC,YAAY;QAC7D,CAAC;aAAM,IAAI,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,MAAM,EAAE,GACP,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBACrB,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAC/B,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAE,GAAG,IAAI,CAAC,CAAC;YACzB,IAAI,EAAE,GAAG,OAAO;gBAAE,OAAO,KAAK,CAAC,CAAC,iCAAiC;YACjE,IAAI,EAAE,GAAG,QAAQ;gBAAE,OAAO,KAAK,CAAC,CAAC,uBAAuB;QACzD,CAAC;QAED,CAAC,IAAI,MAAM,CAAC;IACb,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,SAAS,SAAS,CAAC,MAAc,EAAE,QAAgB;IAClD,IAAI,CAAC;QACJ,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YAC1B,sEAAsE;YACtE,iDAAiD;YACjD,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;YACtC,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;QAED,wDAAwD;QACxD,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC3C,gEAAgE;QAChE,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACvD,wEAAwE;QACxE,oEAAoE;QACpE,4DAA4D;QAC5D,IAAI,gBAAgB,GAAG,CAAC,CAAC;QACzB,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACtB,IAAI,EAAE,KAAK,GAAG;gBAAE,gBAAgB,EAAE,CAAC;QACpC,CAAC;QACD,IAAI,gBAAgB,GAAG,GAAG,CAAC,MAAM,GAAG,IAAI;YAAE,OAAO,IAAI,CAAC;QACtD,OAAO,GAAG,CAAC;IACZ,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;QAC9D,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC"}
1
+ {"version":3,"file":"encoding.js","sourceRoot":"","sources":["../../core/encoding.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../core/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,YAAY,CAAC;AAwB1D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AA0BD;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAKjC;AAmBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,GAAE,MAAY,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAGjG;AA8UD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAavF"}
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../core/scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,SAAS,EAAgB,MAAM,YAAY,CAAC;AAsD1D;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AA0BD;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAOjC;AAmBD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,WAAW,GAAE,MAAY,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAGjG;AAkVD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,SAAS,CAavF"}
@@ -21,7 +21,33 @@ const MAX_FILES = 20_000;
21
21
  const SOURCE_EXTS = new Set(Object.keys(EXT_TO_LANG));
22
22
  // -- In-memory cache ---------------------------------------------------------
23
23
  let cachedGraph = null;
24
+ /**
25
+ * Cache for existsSync results to avoid repeated syscalls during import resolution.
26
+ * Keyed by absolute path; cleared when scanProject starts fresh.
27
+ */
28
+ let _existsCache = null;
29
+ function existsCached(absPath) {
30
+ if (!_existsCache) {
31
+ _existsCache = new Map();
32
+ }
33
+ const cached = _existsCache.get(absPath);
34
+ if (cached !== undefined)
35
+ return cached;
36
+ const result = existsSync(absPath);
37
+ _existsCache.set(absPath, result);
38
+ return result;
39
+ }
40
+ function clearExistsCache() {
41
+ _existsCache = null;
42
+ }
24
43
  let cachedProjectPath = "";
44
+ let _scannerAdapter = null;
45
+ function getScannerAdapter() {
46
+ if (!_scannerAdapter) {
47
+ _scannerAdapter = new TreeSitterAdapter(() => { });
48
+ }
49
+ return _scannerAdapter;
50
+ }
25
51
  // C3: Module-level project root override. When Pi detects the project in a
26
52
  // subdirectory (ctx.cwd != process.cwd()), index.ts calls setProjectRoot()
27
53
  // so the scanner uses the same root as LSP, not process.cwd().
@@ -62,6 +88,8 @@ export function resetCache() {
62
88
  cachedProjectPath = "";
63
89
  cachedFiles = new Map();
64
90
  _projectRootOverride = null;
91
+ clearExistsCache();
92
+ _scannerAdapter = null;
65
93
  }
66
94
  /**
67
95
  * Get per-file modification times for all source files in the project.
@@ -126,6 +154,7 @@ function removeEdgesForFile(graph, relPath) {
126
154
  graph.fileImports.delete(relPath);
127
155
  graph.fileCalls.delete(relPath);
128
156
  graph.fileImportBindings.delete(relPath);
157
+ graph.fileRefs.delete(relPath);
129
158
  // Use reverse edge index to clean cross-file references: O(K) not O(E)
130
159
  for (const targetId of symIds) {
131
160
  const sourceIds = graph.targetToSources.get(targetId);
@@ -194,6 +223,7 @@ function removeFileData(graph, relPath) {
194
223
  graph.fileImports.delete(relPath);
195
224
  graph.fileCalls.delete(relPath);
196
225
  graph.fileImportBindings.delete(relPath);
226
+ graph.fileRefs.delete(relPath);
197
227
  // Use reverse edge index to clean cross-file references: O(K) not O(E)
198
228
  for (const targetId of symIdSet) {
199
229
  const sourceIds = graph.targetToSources.get(targetId);
@@ -353,9 +383,11 @@ function buildEdgesForFile(graph, root, relPath, entry) {
353
383
  if (entry.imports.length > 0) {
354
384
  // Store resolved file paths (not raw module specifiers) so
355
385
  // incrementalScanProject can match them against relPath for dependent detection
356
- graph.fileImports.set(relPath, entry.imports.map(([m]) => resolveImport(m, relPath, root, graph)));
386
+ graph.fileImports.set(relPath, entry.imports.map(([m]) => resolveImport(m, relPath, root, graph)).filter((f) => f !== null));
357
387
  for (const [importedModule] of entry.imports) {
358
388
  const resolvedImport = resolveImport(importedModule, relPath, root, graph);
389
+ if (!resolvedImport)
390
+ continue;
359
391
  const targetFileSyms = graph.fileSymbols.get(resolvedImport) || [];
360
392
  for (const srcId of thisFileSymIds) {
361
393
  for (const tgtId of targetFileSyms) {
@@ -402,6 +434,8 @@ function buildEdgesForFile(graph, root, relPath, entry) {
402
434
  if (!localSym)
403
435
  continue;
404
436
  const resolvedModule = resolveImport(binding.module, relPath, root, graph);
437
+ if (!resolvedModule)
438
+ continue;
405
439
  const sourceSym = findSymbolByNameInFile(binding.importedName, resolvedModule, graph);
406
440
  if (sourceSym) {
407
441
  addEdge(graph, createEdge(localSym.id, sourceSym.id, 0.8, "import-binding", 1.0));
@@ -446,7 +480,7 @@ export function scanProject(projectPath, log) {
446
480
  function _scanProject(projectPath, log) {
447
481
  const root = resolve(projectPath);
448
482
  const logger = log ?? (() => { });
449
- const adapter = new TreeSitterAdapter(logger);
483
+ const adapter = getScannerAdapter();
450
484
  const files = collectSourceFiles(root, MAX_FILES);
451
485
  logger(`Scanned ${files.length} source files`);
452
486
  // Check in-memory cache first (same process, fastest path)
@@ -851,43 +885,181 @@ function addEdge(graph, edge) {
851
885
  }
852
886
  // -- Import resolution ---------------------------------------------------------
853
887
  /**
854
- * Resolve a relative import path to a file path that matches the fileSymbols keys.
855
- * Handles extensionless imports (e.g., "./foo" -> "./foo.ts" or "./foo/index.ts").
856
- * Accepts projectRoot for absolute-path disk validation (fixes #102).
888
+ * Check if any candidate path exists, using graph lookup first then cached disk check.
889
+ */
890
+ function tryCandidate(graph, root, relCandidate) {
891
+ if (graph && graph.fileSymbols.has(relCandidate))
892
+ return relCandidate;
893
+ if (existsCached(join(root, relCandidate)))
894
+ return relCandidate;
895
+ return null;
896
+ }
897
+ /**
898
+ * Resolve a relative or language-specific import path to a file path that matches fileSymbols keys.
899
+ * Handles JS/TS extensionless imports, Python dotted modules, Rust mod declarations,
900
+ * Go relative imports, and Dart package/relative imports.
857
901
  */
858
902
  function resolveImport(importPath, fromFile, root, graph) {
903
+ const fromDir = dirname(fromFile);
904
+ const fromExt = fromFile.slice(fromFile.lastIndexOf(".")).toLowerCase();
905
+ const absRoot = resolve(root);
906
+ // Dart: package: imports map to lib/ directory (standard Dart layout)
907
+ if (importPath.startsWith("package:")) {
908
+ const pkgPath = importPath.slice("package:".length);
909
+ const slashIdx = pkgPath.indexOf("/");
910
+ if (slashIdx > 0) {
911
+ const libRel = `lib/${pkgPath.slice(slashIdx + 1)}`;
912
+ const candidates = [libRel, `${libRel}.dart`];
913
+ for (const c of candidates) {
914
+ const found = tryCandidate(graph, root, c);
915
+ if (found)
916
+ return found;
917
+ }
918
+ }
919
+ return importPath;
920
+ }
921
+ // Relative imports (./ or ../) - cross-language handling
859
922
  if (importPath.startsWith(".")) {
860
- const fromDir = dirname(fromFile);
861
- let resolved = join(fromDir, importPath);
862
- const candidates = [
863
- resolved,
864
- `${resolved}.ts`,
865
- `${resolved}.tsx`,
866
- `${resolved}.js`,
867
- `${resolved}.jsx`,
868
- `${resolved}.mjs`,
869
- `${resolved}.cjs`,
870
- `${resolved}.mts`,
871
- `${resolved}.cts`,
872
- `${resolved}/index.ts`,
873
- `${resolved}/index.tsx`,
874
- `${resolved}/index.js`,
923
+ const resolved = join(fromDir, importPath);
924
+ // JS/TS candidates
925
+ if ([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"].includes(fromExt) || fromExt === "") {
926
+ const jsCandidates = [
927
+ resolved,
928
+ `${resolved}.ts`,
929
+ `${resolved}.tsx`,
930
+ `${resolved}.js`,
931
+ `${resolved}.jsx`,
932
+ `${resolved}.mjs`,
933
+ `${resolved}.cjs`,
934
+ `${resolved}.mts`,
935
+ `${resolved}.cts`,
936
+ `${resolved}/index.ts`,
937
+ `${resolved}/index.tsx`,
938
+ `${resolved}/index.js`,
939
+ ];
940
+ for (const c of jsCandidates) {
941
+ const found = tryCandidate(graph, root, c);
942
+ if (found)
943
+ return found;
944
+ }
945
+ return null;
946
+ }
947
+ // Python relative import: from .foo import bar or from .. import baz
948
+ if (fromExt === ".py") {
949
+ const pyCandidates = [`${resolved}.py`, join(resolved, "__init__.py")];
950
+ for (const c of pyCandidates) {
951
+ const found = tryCandidate(graph, root, c);
952
+ if (found)
953
+ return found;
954
+ }
955
+ return null;
956
+ }
957
+ // Rust relative mod/use: typically resolved through module system,
958
+ // but `super::` paths are parent-relative. Try direct file match.
959
+ if (fromExt === ".rs") {
960
+ const rsCandidates = [`${resolved}.rs`, join(resolved, "mod.rs")];
961
+ for (const c of rsCandidates) {
962
+ const found = tryCandidate(graph, root, c);
963
+ if (found)
964
+ return found;
965
+ }
966
+ return null;
967
+ }
968
+ // Go relative imports
969
+ if (fromExt === ".go") {
970
+ const goFile = `${resolved}.go`;
971
+ const found = tryCandidate(graph, root, goFile);
972
+ if (found)
973
+ return found;
974
+ // Directory-based package (look for .go files in dir)
975
+ if (existsCached(join(absRoot, resolved))) {
976
+ return resolved;
977
+ }
978
+ return null;
979
+ }
980
+ // Dart relative imports
981
+ if (fromExt === ".dart") {
982
+ const dartCandidates = [resolved, `${resolved}.dart`];
983
+ for (const c of dartCandidates) {
984
+ const found = tryCandidate(graph, root, c);
985
+ if (found)
986
+ return found;
987
+ }
988
+ return null;
989
+ }
990
+ return null;
991
+ }
992
+ // Python dotted import: foo.bar.baz -> foo/bar/baz.py or foo/bar/baz/__init__.py
993
+ if (fromExt === ".py" && /^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*$/.test(importPath)) {
994
+ const relPath = importPath.replace(/\./g, "/");
995
+ // Check if we're in a src/ layout by looking for src/ or the import from project root
996
+ const pyCandidates = [
997
+ `${relPath}.py`,
998
+ join(relPath, "__init__.py"),
999
+ join("src", `${relPath}.py`),
1000
+ join("src", relPath, "__init__.py"),
875
1001
  ];
876
- if (graph) {
1002
+ for (const c of pyCandidates) {
1003
+ const found = tryCandidate(graph, root, c);
1004
+ if (found)
1005
+ return found;
1006
+ }
1007
+ return null;
1008
+ }
1009
+ // Rust mod X; -> X.rs or X/mod.rs (sibling to current file's directory)
1010
+ // Rust crate:: paths: crate::foo::bar -> src/foo/bar.rs relative to crate root
1011
+ if (fromExt === ".rs") {
1012
+ if (importPath.startsWith("crate::")) {
1013
+ // Find crate root (directory containing Cargo.toml) by walking up
1014
+ const cratePath = importPath.slice("crate::".length).replace(/::/g, "/");
1015
+ let crateRoot = fromDir;
1016
+ while (crateRoot !== ".") {
1017
+ if (existsCached(join(root, crateRoot, "Cargo.toml")))
1018
+ break;
1019
+ const parent = dirname(crateRoot);
1020
+ if (parent === crateRoot)
1021
+ break;
1022
+ crateRoot = parent;
1023
+ }
1024
+ const candidates = [`${crateRoot}/${cratePath}.rs`, `${crateRoot}/${cratePath}/mod.rs`];
1025
+ for (const c of candidates) {
1026
+ const found = tryCandidate(graph, root, c);
1027
+ if (found)
1028
+ return found;
1029
+ }
1030
+ return candidates[0];
1031
+ }
1032
+ // mod X; or use X::Y without crate:: - try sibling module (X.rs or X/mod.rs)
1033
+ if (!importPath.includes("::") && /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(importPath)) {
1034
+ const candidates = [join(fromDir, `${importPath}.rs`), join(fromDir, importPath, "mod.rs")];
877
1035
  for (const c of candidates) {
878
- if (graph.fileSymbols.has(c))
879
- return c;
1036
+ const found = tryCandidate(graph, root, c);
1037
+ if (found)
1038
+ return found;
880
1039
  }
1040
+ return candidates[0];
881
1041
  }
882
- // Disk validation using absolute paths (root-aware, fixes #102).
883
- for (const c of candidates) {
884
- if (existsSync(join(root, c))) {
885
- return c;
1042
+ // super:: paths
1043
+ if (importPath.startsWith("super::")) {
1044
+ const parentPath = importPath.slice("super::".length).replace(/::/g, "/");
1045
+ const candidates = [join(dirname(fromDir), `${parentPath}.rs`), join(dirname(fromDir), parentPath, "mod.rs")];
1046
+ for (const c of candidates) {
1047
+ const found = tryCandidate(graph, root, c);
1048
+ if (found)
1049
+ return found;
886
1050
  }
1051
+ return candidates[0];
887
1052
  }
888
- // When no candidate exists on disk, return the first candidate.
889
- return candidates[0];
890
1053
  }
1054
+ // Go standard library or external package imports (non-relative) - return as-is
1055
+ if (fromExt === ".go") {
1056
+ return importPath;
1057
+ }
1058
+ // Dart non-relative, non-package imports - return as-is
1059
+ if (fromExt === ".dart") {
1060
+ return importPath;
1061
+ }
1062
+ // Default: return the import path unchanged (JS/TS bare specifiers, external crates, etc.)
891
1063
  return importPath;
892
1064
  }
893
1065
  // -- Symbol lookup helpers ----------------------------------------------------