@wrongstack/tools 0.303.0 → 0.305.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.
@@ -2713,6 +2713,7 @@ import {
2713
2713
  useDaemonPerfDefaults,
2714
2714
  watchProjectTree
2715
2715
  } from "@wrongstack/core/utils";
2716
+ import { bindProjectEndpoint } from "@wrongstack/persistence";
2716
2717
 
2717
2718
  // src/codebase-index/indexer.ts
2718
2719
  import { expectDefined as expectDefined5 } from "@wrongstack/core/utils";
@@ -2726,6 +2727,86 @@ import {
2726
2727
  isFrugalPerf
2727
2728
  } from "@wrongstack/core/utils";
2728
2729
 
2730
+ // src/codebase-index/content-hash.ts
2731
+ var PRIME64_1 = 0x9e3779b185ebca87n;
2732
+ var PRIME64_2 = 0xc2b2ae3d27d4eb4fn;
2733
+ var PRIME64_3 = 0x165667b19e3779f9n;
2734
+ var PRIME64_4 = 0x85ebca77c2b2ae63n;
2735
+ var PRIME64_5 = 0x27d4eb2f165667c5n;
2736
+ var MASK64 = 0xffffffffffffffffn;
2737
+ function mul64(a, b) {
2738
+ return (a & MASK64) * (b & MASK64) & MASK64;
2739
+ }
2740
+ function rotl64(x, n) {
2741
+ const v = x & MASK64;
2742
+ return (v << BigInt(n) | v >> BigInt(64 - n)) & MASK64;
2743
+ }
2744
+ function readU64LE(buf, off) {
2745
+ let v = 0n;
2746
+ for (let i = 7; i >= 0; i--) {
2747
+ v = v << 8n | BigInt(buf[off + i] ?? 0);
2748
+ }
2749
+ return v & MASK64;
2750
+ }
2751
+ function readU32LE(buf, off) {
2752
+ return (BigInt(buf[off] ?? 0) | BigInt(buf[off + 1] ?? 0) << 8n | BigInt(buf[off + 2] ?? 0) << 16n | BigInt(buf[off + 3] ?? 0) << 24n) & MASK64;
2753
+ }
2754
+ function xxh64Round(acc, lane) {
2755
+ return mul64(rotl64(acc + mul64(lane, PRIME64_2) & MASK64, 31), PRIME64_1);
2756
+ }
2757
+ function xxh64MergeRound(acc, val) {
2758
+ return mul64(acc ^ xxh64Round(0n, val), PRIME64_1) + PRIME64_4 & MASK64;
2759
+ }
2760
+ function xxhash64Hex(buf, explicitLen) {
2761
+ const length = explicitLen ?? buf.length;
2762
+ let h;
2763
+ let off = 0;
2764
+ if (length >= 32) {
2765
+ let v1 = PRIME64_1 + PRIME64_2 & MASK64;
2766
+ let v2 = PRIME64_2;
2767
+ let v3 = 0n;
2768
+ let v4 = 0n - PRIME64_1 & MASK64;
2769
+ const end32 = length - 32;
2770
+ while (off <= end32) {
2771
+ v1 = xxh64Round(v1, readU64LE(buf, off));
2772
+ v2 = xxh64Round(v2, readU64LE(buf, off + 8));
2773
+ v3 = xxh64Round(v3, readU64LE(buf, off + 16));
2774
+ v4 = xxh64Round(v4, readU64LE(buf, off + 24));
2775
+ off += 32;
2776
+ }
2777
+ h = rotl64(v1, 1) + rotl64(v2, 7) + rotl64(v3, 12) + rotl64(v4, 18) & MASK64;
2778
+ h = xxh64MergeRound(h, v1);
2779
+ h = xxh64MergeRound(h, v2);
2780
+ h = xxh64MergeRound(h, v3);
2781
+ h = xxh64MergeRound(h, v4);
2782
+ } else {
2783
+ h = PRIME64_5;
2784
+ }
2785
+ h = h + BigInt(length) & MASK64;
2786
+ while (off + 8 <= length) {
2787
+ const k1 = xxh64Round(0n, readU64LE(buf, off));
2788
+ h = mul64(rotl64(h ^ k1, 27), PRIME64_1) + PRIME64_4 & MASK64;
2789
+ off += 8;
2790
+ }
2791
+ if (off + 4 <= length) {
2792
+ h = mul64(rotl64(h ^ mul64(readU32LE(buf, off), PRIME64_1), 23), PRIME64_2) + PRIME64_3 & MASK64;
2793
+ off += 4;
2794
+ }
2795
+ while (off < length) {
2796
+ h = mul64(rotl64(h ^ mul64(BigInt(buf[off] ?? 0), PRIME64_5), 11), PRIME64_1) & MASK64;
2797
+ off += 1;
2798
+ }
2799
+ h = (h ^ h >> 33n) & MASK64;
2800
+ h = mul64(h, PRIME64_2);
2801
+ h = (h ^ h >> 29n) & MASK64;
2802
+ h = mul64(h, PRIME64_3);
2803
+ h = (h ^ h >> 32n) & MASK64;
2804
+ return h.toString(16).padStart(16, "0");
2805
+ }
2806
+ function xxhash64String(content) {
2807
+ return xxhash64Hex(new TextEncoder().encode(content));
2808
+ }
2809
+
2729
2810
  // src/codebase-index/gitignore.ts
2730
2811
  import * as fs from "node:fs/promises";
2731
2812
  import * as path from "node:path";
@@ -3757,86 +3838,6 @@ function getParserPool() {
3757
3838
  return _pool;
3758
3839
  }
3759
3840
 
3760
- // src/codebase-index/content-hash.ts
3761
- var PRIME64_1 = 0x9e3779b185ebca87n;
3762
- var PRIME64_2 = 0xc2b2ae3d27d4eb4fn;
3763
- var PRIME64_3 = 0x165667b19e3779f9n;
3764
- var PRIME64_4 = 0x85ebca77c2b2ae63n;
3765
- var PRIME64_5 = 0x27d4eb2f165667c5n;
3766
- var MASK64 = 0xffffffffffffffffn;
3767
- function mul64(a, b) {
3768
- return (a & MASK64) * (b & MASK64) & MASK64;
3769
- }
3770
- function rotl64(x, n) {
3771
- const v = x & MASK64;
3772
- return (v << BigInt(n) | v >> BigInt(64 - n)) & MASK64;
3773
- }
3774
- function readU64LE(buf, off) {
3775
- let v = 0n;
3776
- for (let i = 7; i >= 0; i--) {
3777
- v = v << 8n | BigInt(buf[off + i] ?? 0);
3778
- }
3779
- return v & MASK64;
3780
- }
3781
- function readU32LE(buf, off) {
3782
- return (BigInt(buf[off] ?? 0) | BigInt(buf[off + 1] ?? 0) << 8n | BigInt(buf[off + 2] ?? 0) << 16n | BigInt(buf[off + 3] ?? 0) << 24n) & MASK64;
3783
- }
3784
- function xxh64Round(acc, lane) {
3785
- return mul64(rotl64(acc + mul64(lane, PRIME64_2) & MASK64, 31), PRIME64_1);
3786
- }
3787
- function xxh64MergeRound(acc, val) {
3788
- return mul64(acc ^ xxh64Round(0n, val), PRIME64_1) + PRIME64_4 & MASK64;
3789
- }
3790
- function xxhash64Hex(buf, explicitLen) {
3791
- const length = explicitLen ?? buf.length;
3792
- let h;
3793
- let off = 0;
3794
- if (length >= 32) {
3795
- let v1 = PRIME64_1 + PRIME64_2 & MASK64;
3796
- let v2 = PRIME64_2;
3797
- let v3 = 0n;
3798
- let v4 = 0n - PRIME64_1 & MASK64;
3799
- const end32 = length - 32;
3800
- while (off <= end32) {
3801
- v1 = xxh64Round(v1, readU64LE(buf, off));
3802
- v2 = xxh64Round(v2, readU64LE(buf, off + 8));
3803
- v3 = xxh64Round(v3, readU64LE(buf, off + 16));
3804
- v4 = xxh64Round(v4, readU64LE(buf, off + 24));
3805
- off += 32;
3806
- }
3807
- h = rotl64(v1, 1) + rotl64(v2, 7) + rotl64(v3, 12) + rotl64(v4, 18) & MASK64;
3808
- h = xxh64MergeRound(h, v1);
3809
- h = xxh64MergeRound(h, v2);
3810
- h = xxh64MergeRound(h, v3);
3811
- h = xxh64MergeRound(h, v4);
3812
- } else {
3813
- h = PRIME64_5;
3814
- }
3815
- h = h + BigInt(length) & MASK64;
3816
- while (off + 8 <= length) {
3817
- const k1 = xxh64Round(0n, readU64LE(buf, off));
3818
- h = mul64(rotl64(h ^ k1, 27), PRIME64_1) + PRIME64_4 & MASK64;
3819
- off += 8;
3820
- }
3821
- if (off + 4 <= length) {
3822
- h = mul64(rotl64(h ^ mul64(readU32LE(buf, off), PRIME64_1), 23), PRIME64_2) + PRIME64_3 & MASK64;
3823
- off += 4;
3824
- }
3825
- while (off < length) {
3826
- h = mul64(rotl64(h ^ mul64(BigInt(buf[off] ?? 0), PRIME64_5), 11), PRIME64_1) & MASK64;
3827
- off += 1;
3828
- }
3829
- h = (h ^ h >> 33n) & MASK64;
3830
- h = mul64(h, PRIME64_2);
3831
- h = (h ^ h >> 29n) & MASK64;
3832
- h = mul64(h, PRIME64_3);
3833
- h = (h ^ h >> 32n) & MASK64;
3834
- return h.toString(16).padStart(16, "0");
3835
- }
3836
- function xxhash64String(content) {
3837
- return xxhash64Hex(new TextEncoder().encode(content));
3838
- }
3839
-
3840
3841
  // src/codebase-index/writer.ts
3841
3842
  import { expectDefined as expectDefined4 } from "@wrongstack/core/utils";
3842
3843
  import * as fs8 from "node:fs";
@@ -5426,7 +5427,7 @@ var IndexStore = class _IndexStore {
5426
5427
  const ftsSchema = this.stmt(
5427
5428
  "SELECT sql FROM sqlite_master WHERE type='table' AND name='symbols_fts'"
5428
5429
  ).get();
5429
- if (ftsSchema?.sql && ftsSchema.sql.includes("unicode61")) {
5430
+ if (ftsSchema?.sql?.includes("unicode61")) {
5430
5431
  this.db.exec("DROP TABLE IF EXISTS symbols_fts");
5431
5432
  }
5432
5433
  this.db.exec(SYMBOLS_FTS_SQL);
@@ -5919,9 +5920,13 @@ var IndexStore = class _IndexStore {
5919
5920
  sim: cosineSimilarity(queryVec, decodeVector(r.vector))
5920
5921
  })).sort((a, b) => b.sim - a.sim);
5921
5922
  const bm25Rank = /* @__PURE__ */ new Map();
5922
- bm25Rows.forEach((r, i) => bm25Rank.set(r.id, i));
5923
+ bm25Rows.forEach((r, i) => {
5924
+ bm25Rank.set(r.id, i);
5925
+ });
5923
5926
  const vecRank = /* @__PURE__ */ new Map();
5924
- vecScores.forEach((r, i) => vecRank.set(r.id, i));
5927
+ vecScores.forEach((r, i) => {
5928
+ vecRank.set(r.id, i);
5929
+ });
5925
5930
  const fused = reciprocalRankFusion(bm25Rank, vecRank, 60);
5926
5931
  const fusedScore = new Map(fused);
5927
5932
  const sorted = [...bm25Rows].sort(
@@ -6531,6 +6536,9 @@ var YIELD_EVERY_N = 50;
6531
6536
  function resolveParallelBatch() {
6532
6537
  return indexParallelBatchSize(availableParallelism());
6533
6538
  }
6539
+ function shouldUseParserWorkerPool(candidateFileCount, parseBatchCount) {
6540
+ return !isFrugalPerf() && candidateFileCount >= WORKER_POOL_THRESHOLD && parseBatchCount > 1;
6541
+ }
6534
6542
  function yieldEventLoop() {
6535
6543
  return new Promise((resolve4) => setImmediate(resolve4));
6536
6544
  }
@@ -6707,11 +6715,7 @@ async function resolveProjectRelations(store, projectRoot2, opts) {
6707
6715
  const structure = await detectModuleRoots(projectRoot2, indexedFiles);
6708
6716
  if (opts.signal?.aborted) return;
6709
6717
  store.setFilePackages(assignPackageLabels(structure, indexedFiles));
6710
- const resolver = new ModuleResolver(
6711
- structure,
6712
- indexedFiles,
6713
- store.getNamespaceDeclarations()
6714
- );
6718
+ const resolver = new ModuleResolver(structure, indexedFiles, store.getNamespaceDeclarations());
6715
6719
  const pending = store.getUnresolvedImports(opts.onlyFiles);
6716
6720
  const resolutions = [];
6717
6721
  for (const entry of pending) {
@@ -6736,6 +6740,10 @@ async function runIndexerWithStore(store, opts) {
6736
6740
  const errors = [];
6737
6741
  const langStats = {};
6738
6742
  let filesIndexed = 0;
6743
+ let filesParsed = 0;
6744
+ let filesSkipped = 0;
6745
+ let filesEmpty = 0;
6746
+ let filesFailed = 0;
6739
6747
  let symbolsIndexed = 0;
6740
6748
  const isGitIgnored = await loadGitignoreMatcher(projectRoot2);
6741
6749
  let files;
@@ -6777,12 +6785,14 @@ async function runIndexerWithStore(store, opts) {
6777
6785
  langStats[meta.lang] = (langStats[meta.lang] ?? 0) + meta.symbolCount;
6778
6786
  symbolsIndexed += meta.symbolCount;
6779
6787
  filesIndexed++;
6788
+ filesSkipped++;
6780
6789
  filesPreSkipped++;
6781
6790
  return false;
6782
6791
  });
6783
6792
  if (filesPreSkipped > 0) opts.onProgress?.(filesPreSkipped, totalFilesForProgress);
6784
6793
  }
6785
6794
  const parallelBatch = resolveParallelBatch();
6795
+ const parserPoolCandidateCount = files.length;
6786
6796
  let filesSinceLastYield = 0;
6787
6797
  for (let batchStart = 0; batchStart < files.length; batchStart += parallelBatch) {
6788
6798
  const batchEnd = Math.min(batchStart + parallelBatch, files.length);
@@ -6875,7 +6885,7 @@ async function runIndexerWithStore(store, opts) {
6875
6885
  });
6876
6886
  }
6877
6887
  if (toParse.length > 0) {
6878
- let pool = toParse.length >= WORKER_POOL_THRESHOLD ? getParserPool() : null;
6888
+ let pool = shouldUseParserWorkerPool(parserPoolCandidateCount, toParse.length) ? getParserPool() : null;
6879
6889
  if (pool) {
6880
6890
  try {
6881
6891
  await pool.ensureReady();
@@ -6925,12 +6935,14 @@ async function runIndexerWithStore(store, opts) {
6925
6935
  const err = settled.reason;
6926
6936
  if (err instanceof Error && isAbortError(err)) throw err;
6927
6937
  errors.push(`batch error: ${file}: ${err instanceof Error ? err.message : String(err)}`);
6938
+ filesFailed++;
6928
6939
  continue;
6929
6940
  }
6930
6941
  const result = settled.value;
6931
6942
  if (result.error) {
6932
6943
  if (result.missing) store.deleteFile(file);
6933
6944
  errors.push(`${file}: ${result.error}`);
6945
+ filesFailed++;
6934
6946
  continue;
6935
6947
  }
6936
6948
  const { stat: stat2, lang, parsed: parsed2 } = result;
@@ -6938,6 +6950,7 @@ async function runIndexerWithStore(store, opts) {
6938
6950
  langStats[lang] = (langStats[lang] ?? 0) + result.skippedMeta.symbolCount;
6939
6951
  symbolsIndexed += result.skippedMeta.symbolCount;
6940
6952
  filesIndexed++;
6953
+ filesSkipped++;
6941
6954
  const stored = existingMeta.get(file);
6942
6955
  if (stored && stored.mtimeMs !== result.skippedMeta.mtimeMs) {
6943
6956
  store.upsertFile({
@@ -6962,6 +6975,7 @@ async function runIndexerWithStore(store, opts) {
6962
6975
  contentHash: result.contentHash ?? ""
6963
6976
  });
6964
6977
  filesIndexed++;
6978
+ filesEmpty++;
6965
6979
  }
6966
6980
  continue;
6967
6981
  }
@@ -6975,6 +6989,7 @@ async function runIndexerWithStore(store, opts) {
6975
6989
  contentHash: result.contentHash ?? ""
6976
6990
  });
6977
6991
  filesIndexed++;
6992
+ filesEmpty++;
6978
6993
  continue;
6979
6994
  }
6980
6995
  batchEntries.push({
@@ -6996,6 +7011,7 @@ async function runIndexerWithStore(store, opts) {
6996
7011
  symbolsIndexed += count;
6997
7012
  langStats[entry.lang] = (langStats[entry.lang] ?? 0) + count;
6998
7013
  filesIndexed++;
7014
+ filesParsed++;
6999
7015
  }
7000
7016
  } catch (err) {
7001
7017
  const message = err instanceof Error ? err.message : String(err);
@@ -7008,6 +7024,7 @@ async function runIndexerWithStore(store, opts) {
7008
7024
  symbolsIndexed += symbolsWithIds.length;
7009
7025
  langStats[entry.lang] = (langStats[entry.lang] ?? 0) + symbolsWithIds.length;
7010
7026
  filesIndexed++;
7027
+ filesParsed++;
7011
7028
  if (entry.refs.length > 0 && symbolsWithIds.length > 0) {
7012
7029
  const fallbackBatch = assignRefsToSymbols2(entry.refs, symbolsWithIds);
7013
7030
  if (fallbackBatch.length > 0) store.insertRefsBatch(fallbackBatch);
@@ -7025,6 +7042,7 @@ async function runIndexerWithStore(store, opts) {
7025
7042
  contentHash: entry.contentHash
7026
7043
  });
7027
7044
  } catch (innerErr) {
7045
+ filesFailed++;
7028
7046
  errors.push(
7029
7047
  `fallback write failed: ${entry.file}: ${innerErr instanceof Error ? innerErr.message : String(innerErr)}`
7030
7048
  );
@@ -7057,6 +7075,12 @@ async function runIndexerWithStore(store, opts) {
7057
7075
  const durationMs = Date.now() - startMs;
7058
7076
  return {
7059
7077
  filesIndexed,
7078
+ fileOutcomes: {
7079
+ parsed: filesParsed,
7080
+ skipped: filesSkipped,
7081
+ empty: filesEmpty,
7082
+ failed: filesFailed
7083
+ },
7060
7084
  symbolsIndexed,
7061
7085
  langStats,
7062
7086
  durationMs,
@@ -7195,7 +7219,6 @@ import * as fs10 from "node:fs";
7195
7219
  import * as os3 from "node:os";
7196
7220
  import * as path13 from "node:path";
7197
7221
  import { fileURLToPath as fileURLToPath3 } from "node:url";
7198
- import { assertUnixSocketPathWithinLimit } from "@wrongstack/core/utils";
7199
7222
  var PROJECT_INDEX_SERVER_PROTOCOL_VERSION = 1;
7200
7223
  var PROJECT_INDEX_SERVER_METADATA_FILE = "server.json";
7201
7224
  var PROJECT_INDEX_SERVER_SOCKET_DIR = `wsci-v${PROJECT_INDEX_SERVER_PROTOCOL_VERSION}`;
@@ -7237,12 +7260,6 @@ function projectIndexServerMetadataPath(projectRoot2, indexDir2) {
7237
7260
  PROJECT_INDEX_SERVER_METADATA_FILE
7238
7261
  );
7239
7262
  }
7240
- function ensureProjectIndexSocketDirectory(endpoint2) {
7241
- if (process.platform !== "win32") {
7242
- assertUnixSocketPathWithinLimit(endpoint2, "codebase-index");
7243
- fs10.mkdirSync(path13.dirname(endpoint2), { recursive: true, mode: 448 });
7244
- }
7245
- }
7246
7263
 
7247
7264
  // src/codebase-index/project-server-protocol.ts
7248
7265
  var PROJECT_INDEX_SERVER_MAX_FRAME_CHARS = 64 * 1024 * 1024;
@@ -7854,27 +7871,32 @@ async function stop(_reason) {
7854
7871
  }
7855
7872
  await stopMemoryWatchdog();
7856
7873
  }
7857
- ensureProjectIndexSocketDirectory(endpoint);
7858
- server.once("error", (error) => {
7859
- if (error.code === "EADDRINUSE") {
7874
+ void (async () => {
7875
+ const bind = await bindProjectEndpoint({ server, endpoint, service: "codebase-index" });
7876
+ if (bind.outcome === "already-owned") {
7860
7877
  process.exitCode = 0;
7861
7878
  return;
7862
7879
  }
7863
- process.stderr.write(`codebase-index server failed: ${error.message}
7880
+ if (bind.outcome === "failed") {
7881
+ process.stderr.write(`codebase-index server failed: ${bind.error.message}
7864
7882
  `);
7865
- process.exitCode = 1;
7866
- });
7867
- server.listen(endpoint, () => {
7868
- if (process.platform !== "win32") {
7869
- try {
7870
- fs11.chmodSync(endpoint, 384);
7871
- } catch {
7872
- }
7883
+ process.exitCode = 1;
7884
+ return;
7873
7885
  }
7886
+ if (bind.reclaimedStaleEndpoint) {
7887
+ process.stderr.write(`codebase-index server reclaimed stale endpoint ${endpoint}
7888
+ `);
7889
+ }
7890
+ server.on("error", (error) => {
7891
+ if (stopping) return;
7892
+ process.stderr.write(`codebase-index server error: ${error.message}
7893
+ `);
7894
+ process.exitCode = 1;
7895
+ });
7874
7896
  writeMetadata();
7875
7897
  markMetadataWritten?.();
7876
7898
  scheduleIdleStop();
7877
- });
7899
+ })();
7878
7900
  process.once("SIGINT", () => void stop("SIGINT"));
7879
7901
  process.once("SIGTERM", () => void stop("SIGTERM"));
7880
7902
  //# sourceMappingURL=project-server.js.map
@@ -76,6 +76,17 @@ export interface SearchResult {
76
76
  /** Result of a full reindex. */
77
77
  export interface IndexResult {
78
78
  filesIndexed: number;
79
+ /** Outcome detail for this run. Optional for compatibility with older project daemons. */
80
+ fileOutcomes?: {
81
+ /** Files parsed and committed with one or more symbols. */
82
+ parsed: number;
83
+ /** Files reused from trusted metadata or an unchanged content hash. */
84
+ skipped: number;
85
+ /** Files successfully represented in the index with zero symbols. */
86
+ empty: number;
87
+ /** Files that could not be read, parsed, or committed. */
88
+ failed: number;
89
+ } | undefined;
79
90
  symbolsIndexed: number;
80
91
  langStats: Record<SymbolLang, number>;
81
92
  durationMs: number;