@neuralsea/workspace-indexer 0.3.6 → 0.4.0
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.
- package/dist/{chunk-FUUQXFJQ.js → chunk-77UJJ6YQ.js} +512 -395
- package/dist/chunk-MCKGQKYU.js +15 -0
- package/dist/cli.cjs +2580 -374
- package/dist/cli.js +2 -1
- package/dist/index.cjs +2588 -373
- package/dist/index.d.cts +57 -3
- package/dist/index.d.ts +57 -3
- package/dist/index.js +10 -1
- package/dist/sql-wasm-LT2WFO7Q.js +2097 -0
- package/package.json +6 -3
|
@@ -2548,63 +2548,6 @@ var RepoIndexer = class {
|
|
|
2548
2548
|
}
|
|
2549
2549
|
};
|
|
2550
2550
|
|
|
2551
|
-
// src/profiles.ts
|
|
2552
|
-
var DEFAULT_PROFILES = {
|
|
2553
|
-
search: {
|
|
2554
|
-
name: "search",
|
|
2555
|
-
k: 10,
|
|
2556
|
-
weights: { vector: 0.65, lexical: 0.35, recency: 0 },
|
|
2557
|
-
expand: { adjacentChunks: 0, followImports: 0, includeFileSynopsis: false },
|
|
2558
|
-
candidates: { vectorK: 25, lexicalK: 25, maxMergedCandidates: 60 }
|
|
2559
|
-
},
|
|
2560
|
-
refactor: {
|
|
2561
|
-
name: "refactor",
|
|
2562
|
-
k: 15,
|
|
2563
|
-
weights: { vector: 0.55, lexical: 0.35, recency: 0.1 },
|
|
2564
|
-
expand: { adjacentChunks: 1, followImports: 2, includeFileSynopsis: true },
|
|
2565
|
-
candidates: { vectorK: 60, lexicalK: 40, maxMergedCandidates: 140 }
|
|
2566
|
-
},
|
|
2567
|
-
review: {
|
|
2568
|
-
name: "review",
|
|
2569
|
-
k: 20,
|
|
2570
|
-
weights: { vector: 0.45, lexical: 0.35, recency: 0.2 },
|
|
2571
|
-
expand: { adjacentChunks: 1, followImports: 1, includeFileSynopsis: true },
|
|
2572
|
-
candidates: { vectorK: 80, lexicalK: 60, maxMergedCandidates: 180 }
|
|
2573
|
-
},
|
|
2574
|
-
architecture: {
|
|
2575
|
-
name: "architecture",
|
|
2576
|
-
k: 20,
|
|
2577
|
-
weights: { vector: 0.7, lexical: 0.2, recency: 0.1 },
|
|
2578
|
-
expand: { adjacentChunks: 0, followImports: 3, includeFileSynopsis: true },
|
|
2579
|
-
candidates: { vectorK: 120, lexicalK: 40, maxMergedCandidates: 220 }
|
|
2580
|
-
},
|
|
2581
|
-
rca: {
|
|
2582
|
-
name: "rca",
|
|
2583
|
-
k: 25,
|
|
2584
|
-
weights: { vector: 0.5, lexical: 0.25, recency: 0.25 },
|
|
2585
|
-
expand: { adjacentChunks: 2, followImports: 1, includeFileSynopsis: true },
|
|
2586
|
-
candidates: { vectorK: 140, lexicalK: 80, maxMergedCandidates: 260 }
|
|
2587
|
-
},
|
|
2588
|
-
custom: {
|
|
2589
|
-
name: "custom",
|
|
2590
|
-
k: 10,
|
|
2591
|
-
weights: { vector: 0.65, lexical: 0.35, recency: 0 },
|
|
2592
|
-
expand: { adjacentChunks: 0, followImports: 0, includeFileSynopsis: false },
|
|
2593
|
-
candidates: { vectorK: 25, lexicalK: 25, maxMergedCandidates: 60 }
|
|
2594
|
-
}
|
|
2595
|
-
};
|
|
2596
|
-
function deepMergeProfile(base, patch) {
|
|
2597
|
-
if (!patch) return base;
|
|
2598
|
-
const merged = {
|
|
2599
|
-
...base,
|
|
2600
|
-
...patch,
|
|
2601
|
-
weights: { ...base.weights, ...patch.weights ?? {} },
|
|
2602
|
-
expand: { ...base.expand, ...patch.expand ?? {} },
|
|
2603
|
-
candidates: { ...base.candidates, ...patch.candidates ?? {} }
|
|
2604
|
-
};
|
|
2605
|
-
return merged;
|
|
2606
|
-
}
|
|
2607
|
-
|
|
2608
2551
|
// src/indexer/repoDiscovery.ts
|
|
2609
2552
|
import fs10 from "fs";
|
|
2610
2553
|
import path13 from "path";
|
|
@@ -2767,9 +2710,163 @@ function mergeIndexerConfig(target, patch) {
|
|
|
2767
2710
|
}
|
|
2768
2711
|
}
|
|
2769
2712
|
|
|
2770
|
-
// src/store/
|
|
2713
|
+
// src/store/workspace/db.ts
|
|
2714
|
+
import Database3 from "better-sqlite3";
|
|
2715
|
+
import fs11 from "fs";
|
|
2716
|
+
import path14 from "path";
|
|
2717
|
+
function detectFts5Support(db) {
|
|
2718
|
+
try {
|
|
2719
|
+
const rows = db.prepare(`PRAGMA compile_options`).all();
|
|
2720
|
+
if (rows.some((r) => String(r.compile_options ?? "").includes("ENABLE_FTS5"))) return true;
|
|
2721
|
+
} catch {
|
|
2722
|
+
}
|
|
2723
|
+
try {
|
|
2724
|
+
db.exec(`
|
|
2725
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS __fts5_probe USING fts5(x);
|
|
2726
|
+
DROP TABLE __fts5_probe;
|
|
2727
|
+
`);
|
|
2728
|
+
return true;
|
|
2729
|
+
} catch {
|
|
2730
|
+
return false;
|
|
2731
|
+
}
|
|
2732
|
+
}
|
|
2733
|
+
var BetterSqlite3Adapter = class {
|
|
2734
|
+
db;
|
|
2735
|
+
capabilities;
|
|
2736
|
+
constructor(dbPath) {
|
|
2737
|
+
this.db = new Database3(dbPath);
|
|
2738
|
+
this.capabilities = { supportsFts5: detectFts5Support(this.db) };
|
|
2739
|
+
}
|
|
2740
|
+
pragma(sql) {
|
|
2741
|
+
this.db.pragma(sql);
|
|
2742
|
+
}
|
|
2743
|
+
exec(sql) {
|
|
2744
|
+
this.db.exec(sql);
|
|
2745
|
+
}
|
|
2746
|
+
prepare(sql) {
|
|
2747
|
+
return this.db.prepare(sql);
|
|
2748
|
+
}
|
|
2749
|
+
transaction(fn) {
|
|
2750
|
+
return this.db.transaction(fn);
|
|
2751
|
+
}
|
|
2752
|
+
close() {
|
|
2753
|
+
this.db.close();
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
var betterSqlite3Adapter = {
|
|
2757
|
+
open(dbPath) {
|
|
2758
|
+
fs11.mkdirSync(path14.dirname(dbPath), { recursive: true });
|
|
2759
|
+
const db = new BetterSqlite3Adapter(dbPath);
|
|
2760
|
+
db.pragma("journal_mode = WAL");
|
|
2761
|
+
return db;
|
|
2762
|
+
}
|
|
2763
|
+
};
|
|
2764
|
+
|
|
2765
|
+
// src/store/workspace/sqlJsAdapter.ts
|
|
2771
2766
|
import fs12 from "fs";
|
|
2772
2767
|
import path15 from "path";
|
|
2768
|
+
function detectFts5Support2(db) {
|
|
2769
|
+
try {
|
|
2770
|
+
db.exec(`
|
|
2771
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS __fts5_probe USING fts5(x);
|
|
2772
|
+
DROP TABLE __fts5_probe;
|
|
2773
|
+
`);
|
|
2774
|
+
return true;
|
|
2775
|
+
} catch {
|
|
2776
|
+
return false;
|
|
2777
|
+
}
|
|
2778
|
+
}
|
|
2779
|
+
var SqlJsStatement = class {
|
|
2780
|
+
constructor(stmt) {
|
|
2781
|
+
this.stmt = stmt;
|
|
2782
|
+
}
|
|
2783
|
+
run(...args) {
|
|
2784
|
+
this.stmt.run(args);
|
|
2785
|
+
return void 0;
|
|
2786
|
+
}
|
|
2787
|
+
get(...args) {
|
|
2788
|
+
this.stmt.bind(args);
|
|
2789
|
+
const hasRow = this.stmt.step();
|
|
2790
|
+
if (!hasRow) {
|
|
2791
|
+
this.stmt.reset();
|
|
2792
|
+
return void 0;
|
|
2793
|
+
}
|
|
2794
|
+
const row = this.stmt.getAsObject();
|
|
2795
|
+
this.stmt.reset();
|
|
2796
|
+
return row;
|
|
2797
|
+
}
|
|
2798
|
+
all(...args) {
|
|
2799
|
+
this.stmt.bind(args);
|
|
2800
|
+
const rows = [];
|
|
2801
|
+
while (this.stmt.step()) rows.push(this.stmt.getAsObject());
|
|
2802
|
+
this.stmt.reset();
|
|
2803
|
+
return rows;
|
|
2804
|
+
}
|
|
2805
|
+
};
|
|
2806
|
+
var SqlJsDbAdapter = class {
|
|
2807
|
+
constructor(db, dbPath) {
|
|
2808
|
+
this.db = db;
|
|
2809
|
+
this.dbPath = dbPath;
|
|
2810
|
+
this.capabilities = { supportsFts5: detectFts5Support2(db) };
|
|
2811
|
+
}
|
|
2812
|
+
capabilities;
|
|
2813
|
+
pragma(sql) {
|
|
2814
|
+
this.exec(`PRAGMA ${sql}`);
|
|
2815
|
+
}
|
|
2816
|
+
exec(sql) {
|
|
2817
|
+
this.db.exec(sql);
|
|
2818
|
+
}
|
|
2819
|
+
prepare(sql) {
|
|
2820
|
+
return new SqlJsStatement(this.db.prepare(sql));
|
|
2821
|
+
}
|
|
2822
|
+
transaction(fn) {
|
|
2823
|
+
return () => {
|
|
2824
|
+
this.db.exec("BEGIN");
|
|
2825
|
+
try {
|
|
2826
|
+
const out = fn();
|
|
2827
|
+
this.db.exec("COMMIT");
|
|
2828
|
+
return out;
|
|
2829
|
+
} catch (e) {
|
|
2830
|
+
try {
|
|
2831
|
+
this.db.exec("ROLLBACK");
|
|
2832
|
+
} catch {
|
|
2833
|
+
}
|
|
2834
|
+
throw e;
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2837
|
+
}
|
|
2838
|
+
close() {
|
|
2839
|
+
if (this.dbPath && this.dbPath !== ":memory:") {
|
|
2840
|
+
fs12.mkdirSync(path15.dirname(this.dbPath), { recursive: true });
|
|
2841
|
+
const bytes = this.db.export();
|
|
2842
|
+
fs12.writeFileSync(this.dbPath, Buffer.from(bytes));
|
|
2843
|
+
}
|
|
2844
|
+
this.db.close();
|
|
2845
|
+
}
|
|
2846
|
+
};
|
|
2847
|
+
async function sqlJsAdapter(opts = {}) {
|
|
2848
|
+
let init;
|
|
2849
|
+
try {
|
|
2850
|
+
const mod = await import("./sql-wasm-LT2WFO7Q.js");
|
|
2851
|
+
init = mod?.default ?? mod;
|
|
2852
|
+
} catch (e) {
|
|
2853
|
+
throw new Error(`sqlJsAdapter requires optional dependency 'sql.js' (install it to use this adapter): ${String(e?.message ?? e)}`);
|
|
2854
|
+
}
|
|
2855
|
+
const SQL = await init({ locateFile: opts.locateFile, wasmBinary: opts.wasmBinary });
|
|
2856
|
+
return {
|
|
2857
|
+
open(dbPath) {
|
|
2858
|
+
const abs = path15.resolve(dbPath);
|
|
2859
|
+
const exists = fs12.existsSync(abs);
|
|
2860
|
+
const bytes = exists ? new Uint8Array(fs12.readFileSync(abs)) : void 0;
|
|
2861
|
+
const db = bytes ? new SQL.Database(bytes) : new SQL.Database();
|
|
2862
|
+
return new SqlJsDbAdapter(db, abs);
|
|
2863
|
+
}
|
|
2864
|
+
};
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
// src/store/workspaceStore.ts
|
|
2868
|
+
import fs14 from "fs";
|
|
2869
|
+
import path17 from "path";
|
|
2773
2870
|
|
|
2774
2871
|
// src/store/workspace/unitOfWork.ts
|
|
2775
2872
|
var UnitOfWork = class {
|
|
@@ -2989,32 +3086,11 @@ var RepoLinksRepository = class {
|
|
|
2989
3086
|
};
|
|
2990
3087
|
|
|
2991
3088
|
// src/store/workspace/factory.ts
|
|
2992
|
-
import
|
|
2993
|
-
import
|
|
3089
|
+
import fs13 from "fs";
|
|
3090
|
+
import path16 from "path";
|
|
2994
3091
|
|
|
2995
|
-
// src/store/workspace/
|
|
2996
|
-
|
|
2997
|
-
var BetterSqlite3Adapter = class {
|
|
2998
|
-
db;
|
|
2999
|
-
constructor(dbPath) {
|
|
3000
|
-
this.db = new Database3(dbPath);
|
|
3001
|
-
}
|
|
3002
|
-
pragma(sql) {
|
|
3003
|
-
this.db.pragma(sql);
|
|
3004
|
-
}
|
|
3005
|
-
exec(sql) {
|
|
3006
|
-
this.db.exec(sql);
|
|
3007
|
-
}
|
|
3008
|
-
prepare(sql) {
|
|
3009
|
-
return this.db.prepare(sql);
|
|
3010
|
-
}
|
|
3011
|
-
transaction(fn) {
|
|
3012
|
-
return this.db.transaction(fn);
|
|
3013
|
-
}
|
|
3014
|
-
close() {
|
|
3015
|
-
this.db.close();
|
|
3016
|
-
}
|
|
3017
|
-
};
|
|
3092
|
+
// src/store/workspace/fts5.sql
|
|
3093
|
+
var fts5_default = "CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(\n id UNINDEXED,\n repo_id UNINDEXED,\n repo_root UNINDEXED,\n path,\n language,\n kind,\n text,\n tokenize='unicode61'\n);\n\n";
|
|
3018
3094
|
|
|
3019
3095
|
// src/store/workspace/fts.ts
|
|
3020
3096
|
var NoopFtsStrategy = class {
|
|
@@ -3038,18 +3114,7 @@ var Fts5Strategy = class {
|
|
|
3038
3114
|
enabled = true;
|
|
3039
3115
|
ins = null;
|
|
3040
3116
|
init(db) {
|
|
3041
|
-
db.exec(
|
|
3042
|
-
CREATE VIRTUAL TABLE IF NOT EXISTS chunks_fts USING fts5(
|
|
3043
|
-
id UNINDEXED,
|
|
3044
|
-
repo_id UNINDEXED,
|
|
3045
|
-
repo_root UNINDEXED,
|
|
3046
|
-
path,
|
|
3047
|
-
language,
|
|
3048
|
-
kind,
|
|
3049
|
-
text,
|
|
3050
|
-
tokenize='unicode61'
|
|
3051
|
-
);
|
|
3052
|
-
`);
|
|
3117
|
+
db.exec(fts5_default);
|
|
3053
3118
|
}
|
|
3054
3119
|
clearRepo(repoId) {
|
|
3055
3120
|
this.db.prepare(`DELETE FROM chunks_fts WHERE repo_id = ?`).run(repoId);
|
|
@@ -3133,109 +3198,26 @@ var WorkspaceMigrator = class {
|
|
|
3133
3198
|
}
|
|
3134
3199
|
};
|
|
3135
3200
|
|
|
3201
|
+
// src/store/workspace/baseSchema.sql
|
|
3202
|
+
var baseSchema_default = "CREATE TABLE IF NOT EXISTS meta (\n k TEXT PRIMARY KEY,\n v TEXT NOT NULL\n);\n\nCREATE TABLE IF NOT EXISTS repos (\n repo_id TEXT PRIMARY KEY,\n repo_root TEXT NOT NULL,\n head_commit TEXT NOT NULL,\n head_branch TEXT NOT NULL,\n updated_at INTEGER NOT NULL\n);\n\nCREATE UNIQUE INDEX IF NOT EXISTS idx_repos_root ON repos(repo_root);\n\nCREATE TABLE IF NOT EXISTS files (\n repo_id TEXT NOT NULL,\n path TEXT NOT NULL,\n hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n language TEXT NOT NULL,\n size INTEGER NOT NULL,\n PRIMARY KEY(repo_id, path)\n);\n\nCREATE INDEX IF NOT EXISTS idx_files_repo ON files(repo_id);\n\nCREATE TABLE IF NOT EXISTS chunks (\n id TEXT PRIMARY KEY,\n repo_id TEXT NOT NULL,\n repo_root TEXT NOT NULL,\n path TEXT NOT NULL,\n language TEXT NOT NULL,\n kind TEXT NOT NULL DEFAULT 'chunk',\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n content_hash TEXT NOT NULL,\n tokens INTEGER NOT NULL,\n file_mtime INTEGER NOT NULL,\n text TEXT NOT NULL,\n embedding BLOB NOT NULL\n);\n\nCREATE INDEX IF NOT EXISTS idx_chunks_repo_path ON chunks(repo_id, path);\nCREATE INDEX IF NOT EXISTS idx_chunks_kind_repo_path ON chunks(kind, repo_id, path);\n\nCREATE TABLE IF NOT EXISTS edges (\n repo_id TEXT NOT NULL,\n from_path TEXT NOT NULL,\n kind TEXT NOT NULL,\n value TEXT NOT NULL,\n PRIMARY KEY(repo_id, from_path, kind, value)\n);\n\nCREATE INDEX IF NOT EXISTS idx_edges_repo_from ON edges(repo_id, from_path);\n\nCREATE TABLE IF NOT EXISTS symbols (\n id TEXT PRIMARY KEY,\n repo_id TEXT NOT NULL,\n repo_root TEXT NOT NULL,\n path TEXT NOT NULL,\n language TEXT NOT NULL,\n name TEXT NOT NULL,\n kind TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n start_char INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n end_char INTEGER NOT NULL,\n container_name TEXT NOT NULL DEFAULT '',\n detail TEXT NOT NULL DEFAULT ''\n);\n\nCREATE INDEX IF NOT EXISTS idx_symbols_repo_path ON symbols(repo_id, path);\nCREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);\n\nCREATE TABLE IF NOT EXISTS symbol_edges (\n repo_id TEXT NOT NULL,\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n kind TEXT NOT NULL,\n from_path TEXT NOT NULL,\n to_path TEXT NOT NULL,\n PRIMARY KEY(repo_id, from_id, to_id, kind)\n);\n\nCREATE INDEX IF NOT EXISTS idx_symbol_edges_from ON symbol_edges(repo_id, from_id);\nCREATE INDEX IF NOT EXISTS idx_symbol_edges_paths ON symbol_edges(repo_id, from_path);\n\n";
|
|
3203
|
+
|
|
3136
3204
|
// src/store/workspace/factory.ts
|
|
3137
|
-
function createWorkspaceDb(dbPath) {
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
db.pragma("journal_mode = WAL");
|
|
3141
|
-
return db;
|
|
3205
|
+
function createWorkspaceDb(dbPath, opts = {}) {
|
|
3206
|
+
fs13.mkdirSync(path16.dirname(dbPath), { recursive: true });
|
|
3207
|
+
return (opts.db ?? betterSqlite3Adapter).open(dbPath);
|
|
3142
3208
|
}
|
|
3143
3209
|
function createWorkspaceBaseSchema(db) {
|
|
3144
|
-
db.exec(
|
|
3145
|
-
CREATE TABLE IF NOT EXISTS meta (
|
|
3146
|
-
k TEXT PRIMARY KEY,
|
|
3147
|
-
v TEXT NOT NULL
|
|
3148
|
-
);
|
|
3149
|
-
|
|
3150
|
-
CREATE TABLE IF NOT EXISTS repos (
|
|
3151
|
-
repo_id TEXT PRIMARY KEY,
|
|
3152
|
-
repo_root TEXT NOT NULL,
|
|
3153
|
-
head_commit TEXT NOT NULL,
|
|
3154
|
-
head_branch TEXT NOT NULL,
|
|
3155
|
-
updated_at INTEGER NOT NULL
|
|
3156
|
-
);
|
|
3157
|
-
|
|
3158
|
-
CREATE UNIQUE INDEX IF NOT EXISTS idx_repos_root ON repos(repo_root);
|
|
3159
|
-
|
|
3160
|
-
CREATE TABLE IF NOT EXISTS files (
|
|
3161
|
-
repo_id TEXT NOT NULL,
|
|
3162
|
-
path TEXT NOT NULL,
|
|
3163
|
-
hash TEXT NOT NULL,
|
|
3164
|
-
mtime INTEGER NOT NULL,
|
|
3165
|
-
language TEXT NOT NULL,
|
|
3166
|
-
size INTEGER NOT NULL,
|
|
3167
|
-
PRIMARY KEY(repo_id, path)
|
|
3168
|
-
);
|
|
3169
|
-
|
|
3170
|
-
CREATE INDEX IF NOT EXISTS idx_files_repo ON files(repo_id);
|
|
3171
|
-
|
|
3172
|
-
CREATE TABLE IF NOT EXISTS chunks (
|
|
3173
|
-
id TEXT PRIMARY KEY,
|
|
3174
|
-
repo_id TEXT NOT NULL,
|
|
3175
|
-
repo_root TEXT NOT NULL,
|
|
3176
|
-
path TEXT NOT NULL,
|
|
3177
|
-
language TEXT NOT NULL,
|
|
3178
|
-
kind TEXT NOT NULL DEFAULT 'chunk',
|
|
3179
|
-
start_line INTEGER NOT NULL,
|
|
3180
|
-
end_line INTEGER NOT NULL,
|
|
3181
|
-
content_hash TEXT NOT NULL,
|
|
3182
|
-
tokens INTEGER NOT NULL,
|
|
3183
|
-
file_mtime INTEGER NOT NULL,
|
|
3184
|
-
text TEXT NOT NULL,
|
|
3185
|
-
embedding BLOB NOT NULL
|
|
3186
|
-
);
|
|
3187
|
-
|
|
3188
|
-
CREATE INDEX IF NOT EXISTS idx_chunks_repo_path ON chunks(repo_id, path);
|
|
3189
|
-
CREATE INDEX IF NOT EXISTS idx_chunks_kind_repo_path ON chunks(kind, repo_id, path);
|
|
3190
|
-
|
|
3191
|
-
CREATE TABLE IF NOT EXISTS edges (
|
|
3192
|
-
repo_id TEXT NOT NULL,
|
|
3193
|
-
from_path TEXT NOT NULL,
|
|
3194
|
-
kind TEXT NOT NULL,
|
|
3195
|
-
value TEXT NOT NULL,
|
|
3196
|
-
PRIMARY KEY(repo_id, from_path, kind, value)
|
|
3197
|
-
);
|
|
3198
|
-
|
|
3199
|
-
CREATE INDEX IF NOT EXISTS idx_edges_repo_from ON edges(repo_id, from_path);
|
|
3200
|
-
|
|
3201
|
-
CREATE TABLE IF NOT EXISTS symbols (
|
|
3202
|
-
id TEXT PRIMARY KEY,
|
|
3203
|
-
repo_id TEXT NOT NULL,
|
|
3204
|
-
repo_root TEXT NOT NULL,
|
|
3205
|
-
path TEXT NOT NULL,
|
|
3206
|
-
language TEXT NOT NULL,
|
|
3207
|
-
name TEXT NOT NULL,
|
|
3208
|
-
kind TEXT NOT NULL,
|
|
3209
|
-
start_line INTEGER NOT NULL,
|
|
3210
|
-
start_char INTEGER NOT NULL,
|
|
3211
|
-
end_line INTEGER NOT NULL,
|
|
3212
|
-
end_char INTEGER NOT NULL,
|
|
3213
|
-
container_name TEXT NOT NULL DEFAULT '',
|
|
3214
|
-
detail TEXT NOT NULL DEFAULT ''
|
|
3215
|
-
);
|
|
3216
|
-
|
|
3217
|
-
CREATE INDEX IF NOT EXISTS idx_symbols_repo_path ON symbols(repo_id, path);
|
|
3218
|
-
CREATE INDEX IF NOT EXISTS idx_symbols_name ON symbols(name);
|
|
3219
|
-
|
|
3220
|
-
CREATE TABLE IF NOT EXISTS symbol_edges (
|
|
3221
|
-
repo_id TEXT NOT NULL,
|
|
3222
|
-
from_id TEXT NOT NULL,
|
|
3223
|
-
to_id TEXT NOT NULL,
|
|
3224
|
-
kind TEXT NOT NULL,
|
|
3225
|
-
from_path TEXT NOT NULL,
|
|
3226
|
-
to_path TEXT NOT NULL,
|
|
3227
|
-
PRIMARY KEY(repo_id, from_id, to_id, kind)
|
|
3228
|
-
);
|
|
3229
|
-
|
|
3230
|
-
CREATE INDEX IF NOT EXISTS idx_symbol_edges_from ON symbol_edges(repo_id, from_id);
|
|
3231
|
-
CREATE INDEX IF NOT EXISTS idx_symbol_edges_paths ON symbol_edges(repo_id, from_path);
|
|
3232
|
-
`);
|
|
3210
|
+
db.exec(baseSchema_default);
|
|
3233
3211
|
}
|
|
3234
3212
|
function createWorkspaceFts(db, meta, opts = {}) {
|
|
3235
3213
|
if (opts.fts === "off") {
|
|
3236
3214
|
meta.set("fts", "0");
|
|
3237
3215
|
return new NoopFtsStrategy();
|
|
3238
3216
|
}
|
|
3217
|
+
if (!db.capabilities.supportsFts5) {
|
|
3218
|
+
meta.set("fts", "0");
|
|
3219
|
+
return new NoopFtsStrategy();
|
|
3220
|
+
}
|
|
3239
3221
|
try {
|
|
3240
3222
|
const fts = new Fts5Strategy(db);
|
|
3241
3223
|
fts.init(db);
|
|
@@ -3252,16 +3234,31 @@ function migrateWorkspaceDb(db, meta) {
|
|
|
3252
3234
|
}
|
|
3253
3235
|
|
|
3254
3236
|
// src/store/workspaceStore.ts
|
|
3237
|
+
function createWorkspaceStore(dbPath, opts = {}) {
|
|
3238
|
+
return new WorkspaceStore(dbPath, opts);
|
|
3239
|
+
}
|
|
3240
|
+
async function defaultWorkspaceDbFactory() {
|
|
3241
|
+
try {
|
|
3242
|
+
return await sqlJsAdapter();
|
|
3243
|
+
} catch {
|
|
3244
|
+
return betterSqlite3Adapter;
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
async function createWorkspaceStoreAsync(dbPath, opts = {}) {
|
|
3248
|
+
const dbFactory = opts.db ? await Promise.resolve(opts.db) : await defaultWorkspaceDbFactory();
|
|
3249
|
+
return new WorkspaceStore(dbPath, { ...opts, db: dbFactory });
|
|
3250
|
+
}
|
|
3255
3251
|
var WorkspaceStore = class {
|
|
3256
3252
|
constructor(dbPath, opts = {}) {
|
|
3257
3253
|
this.dbPath = dbPath;
|
|
3258
3254
|
this.opts = opts;
|
|
3259
|
-
this.db = createWorkspaceDb(dbPath);
|
|
3255
|
+
this.db = createWorkspaceDb(dbPath, { db: opts.db });
|
|
3260
3256
|
this.uow = new UnitOfWork(this.db);
|
|
3261
3257
|
createWorkspaceBaseSchema(this.db);
|
|
3262
3258
|
this.meta = new MetaRepository(this.db);
|
|
3263
3259
|
migrateWorkspaceDb(this.db, this.meta);
|
|
3264
3260
|
const fts = createWorkspaceFts(this.db, this.meta, opts);
|
|
3261
|
+
this.ftsEnabledInternal = fts.enabled;
|
|
3265
3262
|
this.repoHeads = new RepoHeadsRepository(this.db);
|
|
3266
3263
|
this.files = new FilesRepository(this.db);
|
|
3267
3264
|
this.edges = new EdgesRepository(this.db);
|
|
@@ -3271,6 +3268,7 @@ var WorkspaceStore = class {
|
|
|
3271
3268
|
}
|
|
3272
3269
|
db;
|
|
3273
3270
|
uow;
|
|
3271
|
+
ftsEnabledInternal;
|
|
3274
3272
|
meta;
|
|
3275
3273
|
repoHeads;
|
|
3276
3274
|
files;
|
|
@@ -3279,6 +3277,9 @@ var WorkspaceStore = class {
|
|
|
3279
3277
|
symbols;
|
|
3280
3278
|
chunks;
|
|
3281
3279
|
opts;
|
|
3280
|
+
get ftsEnabled() {
|
|
3281
|
+
return this.ftsEnabledInternal;
|
|
3282
|
+
}
|
|
3282
3283
|
setMeta(k, v) {
|
|
3283
3284
|
this.meta.set(k, v);
|
|
3284
3285
|
}
|
|
@@ -3362,9 +3363,9 @@ var WorkspaceStore = class {
|
|
|
3362
3363
|
* The chunk boundaries are approximate; the stored row includes start/end line.
|
|
3363
3364
|
*/
|
|
3364
3365
|
getChunkTextFallback(row) {
|
|
3365
|
-
const abs =
|
|
3366
|
+
const abs = path17.join(row.repo_root, row.path.split("/").join(path17.sep));
|
|
3366
3367
|
try {
|
|
3367
|
-
const raw =
|
|
3368
|
+
const raw = fs14.readFileSync(abs, "utf8");
|
|
3368
3369
|
const lines = raw.split(/\r?\n/);
|
|
3369
3370
|
const start = Math.max(1, row.start_line);
|
|
3370
3371
|
const end = Math.max(start, row.end_line);
|
|
@@ -3834,11 +3835,11 @@ ${hint}`);
|
|
|
3834
3835
|
}
|
|
3835
3836
|
|
|
3836
3837
|
// src/indexer/workspaceLinker.ts
|
|
3837
|
-
import
|
|
3838
|
-
import
|
|
3838
|
+
import fs15 from "fs";
|
|
3839
|
+
import path18 from "path";
|
|
3839
3840
|
function readText(absPath) {
|
|
3840
3841
|
try {
|
|
3841
|
-
return
|
|
3842
|
+
return fs15.readFileSync(absPath, "utf8");
|
|
3842
3843
|
} catch {
|
|
3843
3844
|
return null;
|
|
3844
3845
|
}
|
|
@@ -3868,7 +3869,7 @@ var NestedRepoLinkStrategy = class {
|
|
|
3868
3869
|
for (const child of sorted) {
|
|
3869
3870
|
for (const parent of sorted) {
|
|
3870
3871
|
if (child.repoId === parent.repoId) continue;
|
|
3871
|
-
if (child.absRoot.startsWith(parent.absRoot +
|
|
3872
|
+
if (child.absRoot.startsWith(parent.absRoot + path18.sep)) {
|
|
3872
3873
|
out.push({
|
|
3873
3874
|
fromRepoId: child.repoId,
|
|
3874
3875
|
toRepoId: parent.repoId,
|
|
@@ -3888,7 +3889,7 @@ var NpmDependencyLinkStrategy = class {
|
|
|
3888
3889
|
const out = [];
|
|
3889
3890
|
const depSections = ["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"];
|
|
3890
3891
|
for (const r of ctx.repos) {
|
|
3891
|
-
const pkg = readJson(
|
|
3892
|
+
const pkg = readJson(path18.join(r.absRoot, "package.json"));
|
|
3892
3893
|
if (!pkg) continue;
|
|
3893
3894
|
for (const sec of depSections) {
|
|
3894
3895
|
const deps = pkg?.[sec];
|
|
@@ -3906,13 +3907,13 @@ var NpmDependencyLinkStrategy = class {
|
|
|
3906
3907
|
}
|
|
3907
3908
|
};
|
|
3908
3909
|
function parseGoModule(absRepoRoot) {
|
|
3909
|
-
const raw = readText(
|
|
3910
|
+
const raw = readText(path18.join(absRepoRoot, "go.mod"));
|
|
3910
3911
|
if (!raw) return null;
|
|
3911
3912
|
const m = raw.match(/^\s*module\s+(.+)\s*$/m);
|
|
3912
3913
|
return m ? String(m[1]).trim() : null;
|
|
3913
3914
|
}
|
|
3914
3915
|
function parseGoRequires(absRepoRoot) {
|
|
3915
|
-
const raw = readText(
|
|
3916
|
+
const raw = readText(path18.join(absRepoRoot, "go.mod"));
|
|
3916
3917
|
if (!raw) return [];
|
|
3917
3918
|
const out = [];
|
|
3918
3919
|
for (const line of raw.split(/\r?\n/)) {
|
|
@@ -3952,13 +3953,13 @@ function walkFiles(root, opts, onFile) {
|
|
|
3952
3953
|
if (depth > maxDepth) return;
|
|
3953
3954
|
let ents = [];
|
|
3954
3955
|
try {
|
|
3955
|
-
ents =
|
|
3956
|
+
ents = fs15.readdirSync(dir, { withFileTypes: true });
|
|
3956
3957
|
} catch {
|
|
3957
3958
|
return;
|
|
3958
3959
|
}
|
|
3959
3960
|
for (const e of ents) {
|
|
3960
3961
|
if (seen >= maxFiles) return;
|
|
3961
|
-
const abs =
|
|
3962
|
+
const abs = path18.join(dir, e.name);
|
|
3962
3963
|
if (opts.shouldVisit && !opts.shouldVisit(abs, e)) continue;
|
|
3963
3964
|
if (e.isDirectory()) {
|
|
3964
3965
|
if (isSkippableDir(e.name)) continue;
|
|
@@ -3982,7 +3983,7 @@ function collectVsCodeLanguagesForRepo(absRepoRoot) {
|
|
|
3982
3983
|
shouldVisit: (_abs, dirent) => !(dirent.isDirectory() && isSkippableDir(dirent.name))
|
|
3983
3984
|
},
|
|
3984
3985
|
(absPath) => {
|
|
3985
|
-
if (
|
|
3986
|
+
if (path18.basename(absPath) !== "package.json") return;
|
|
3986
3987
|
const pkg = readJson(absPath);
|
|
3987
3988
|
const langs = pkg?.contributes?.languages;
|
|
3988
3989
|
if (!Array.isArray(langs)) return;
|
|
@@ -4011,7 +4012,7 @@ function repoUsedExtensions(absRepoRoot, exts) {
|
|
|
4011
4012
|
shouldVisit: (_abs, dirent) => !(dirent.isDirectory() && isSkippableDir(dirent.name))
|
|
4012
4013
|
},
|
|
4013
4014
|
(absPath) => {
|
|
4014
|
-
const ext =
|
|
4015
|
+
const ext = path18.extname(absPath).toLowerCase();
|
|
4015
4016
|
if (!ext) return;
|
|
4016
4017
|
if (exts.has(ext)) used.add(ext);
|
|
4017
4018
|
}
|
|
@@ -4083,12 +4084,12 @@ var WorkspaceLinker = class _WorkspaceLinker {
|
|
|
4083
4084
|
const repos = repoRoots.map((repoRoot) => ({
|
|
4084
4085
|
repoRoot,
|
|
4085
4086
|
repoId: repoIdFromRoot(repoRoot),
|
|
4086
|
-
absRoot:
|
|
4087
|
+
absRoot: path18.resolve(repoRoot)
|
|
4087
4088
|
}));
|
|
4088
4089
|
const npmNameToRepoId = /* @__PURE__ */ new Map();
|
|
4089
4090
|
const goModuleToRepoId = /* @__PURE__ */ new Map();
|
|
4090
4091
|
for (const r of repos) {
|
|
4091
|
-
const pkg = readJson(
|
|
4092
|
+
const pkg = readJson(path18.join(r.absRoot, "package.json"));
|
|
4092
4093
|
const name = typeof pkg?.name === "string" ? pkg.name : null;
|
|
4093
4094
|
if (name) npmNameToRepoId.set(name, r.repoId);
|
|
4094
4095
|
const mod = parseGoModule(r.absRoot);
|
|
@@ -4132,14 +4133,265 @@ async function linkWorkspaceRepos(args) {
|
|
|
4132
4133
|
return { repos: ctx.repos, links };
|
|
4133
4134
|
}
|
|
4134
4135
|
|
|
4136
|
+
// src/profiles.ts
|
|
4137
|
+
var DEFAULT_PROFILES = {
|
|
4138
|
+
search: {
|
|
4139
|
+
name: "search",
|
|
4140
|
+
k: 10,
|
|
4141
|
+
weights: { vector: 0.65, lexical: 0.35, recency: 0 },
|
|
4142
|
+
expand: { adjacentChunks: 0, followImports: 0, includeFileSynopsis: false },
|
|
4143
|
+
candidates: { vectorK: 25, lexicalK: 25, maxMergedCandidates: 60 }
|
|
4144
|
+
},
|
|
4145
|
+
refactor: {
|
|
4146
|
+
name: "refactor",
|
|
4147
|
+
k: 15,
|
|
4148
|
+
weights: { vector: 0.55, lexical: 0.35, recency: 0.1 },
|
|
4149
|
+
expand: { adjacentChunks: 1, followImports: 2, includeFileSynopsis: true },
|
|
4150
|
+
candidates: { vectorK: 60, lexicalK: 40, maxMergedCandidates: 140 }
|
|
4151
|
+
},
|
|
4152
|
+
review: {
|
|
4153
|
+
name: "review",
|
|
4154
|
+
k: 20,
|
|
4155
|
+
weights: { vector: 0.45, lexical: 0.35, recency: 0.2 },
|
|
4156
|
+
expand: { adjacentChunks: 1, followImports: 1, includeFileSynopsis: true },
|
|
4157
|
+
candidates: { vectorK: 80, lexicalK: 60, maxMergedCandidates: 180 }
|
|
4158
|
+
},
|
|
4159
|
+
architecture: {
|
|
4160
|
+
name: "architecture",
|
|
4161
|
+
k: 20,
|
|
4162
|
+
weights: { vector: 0.7, lexical: 0.2, recency: 0.1 },
|
|
4163
|
+
expand: { adjacentChunks: 0, followImports: 3, includeFileSynopsis: true },
|
|
4164
|
+
candidates: { vectorK: 120, lexicalK: 40, maxMergedCandidates: 220 }
|
|
4165
|
+
},
|
|
4166
|
+
rca: {
|
|
4167
|
+
name: "rca",
|
|
4168
|
+
k: 25,
|
|
4169
|
+
weights: { vector: 0.5, lexical: 0.25, recency: 0.25 },
|
|
4170
|
+
expand: { adjacentChunks: 2, followImports: 1, includeFileSynopsis: true },
|
|
4171
|
+
candidates: { vectorK: 140, lexicalK: 80, maxMergedCandidates: 260 }
|
|
4172
|
+
},
|
|
4173
|
+
custom: {
|
|
4174
|
+
name: "custom",
|
|
4175
|
+
k: 10,
|
|
4176
|
+
weights: { vector: 0.65, lexical: 0.35, recency: 0 },
|
|
4177
|
+
expand: { adjacentChunks: 0, followImports: 0, includeFileSynopsis: false },
|
|
4178
|
+
candidates: { vectorK: 25, lexicalK: 25, maxMergedCandidates: 60 }
|
|
4179
|
+
}
|
|
4180
|
+
};
|
|
4181
|
+
function deepMergeProfile(base, patch) {
|
|
4182
|
+
if (!patch) return base;
|
|
4183
|
+
const merged = {
|
|
4184
|
+
...base,
|
|
4185
|
+
...patch,
|
|
4186
|
+
weights: { ...base.weights, ...patch.weights ?? {} },
|
|
4187
|
+
expand: { ...base.expand, ...patch.expand ?? {} },
|
|
4188
|
+
candidates: { ...base.candidates, ...patch.candidates ?? {} }
|
|
4189
|
+
};
|
|
4190
|
+
return merged;
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4135
4193
|
// src/indexer/workspaceIndexer.ts
|
|
4136
|
-
import
|
|
4194
|
+
import path20 from "path";
|
|
4195
|
+
|
|
4196
|
+
// src/indexer/workspaceRetrieveCandidates.ts
|
|
4197
|
+
import path19 from "path";
|
|
4198
|
+
function resolveWorkspaceProfile(config, opts) {
|
|
4199
|
+
const name = opts?.profile ?? "search";
|
|
4200
|
+
const base = DEFAULT_PROFILES[name] ?? DEFAULT_PROFILES.search;
|
|
4201
|
+
const configPatch = config.profiles?.[name] ?? {};
|
|
4202
|
+
const merged1 = deepMergeProfile(base, configPatch);
|
|
4203
|
+
const merged2 = deepMergeProfile(merged1, opts?.profileOverrides);
|
|
4204
|
+
const w = merged2.weights;
|
|
4205
|
+
const sum = Math.max(1e-6, w.vector + w.lexical + w.recency);
|
|
4206
|
+
merged2.weights = { vector: w.vector / sum, lexical: w.lexical / sum, recency: w.recency / sum };
|
|
4207
|
+
return merged2;
|
|
4208
|
+
}
|
|
4137
4209
|
function halfLifeDaysForProfile(profileName) {
|
|
4138
4210
|
if (profileName === "rca") return 7;
|
|
4139
4211
|
if (profileName === "review") return 14;
|
|
4140
4212
|
if (profileName === "refactor") return 21;
|
|
4141
4213
|
return 30;
|
|
4142
4214
|
}
|
|
4215
|
+
function buildWorkspaceLexByRepoRoot(args) {
|
|
4216
|
+
const { workspaceStore, repos, query, lexicalK, repoFilters } = args;
|
|
4217
|
+
const ftq = ftsQueryFromText(query);
|
|
4218
|
+
if (!ftq) return { lexByRepoRoot: /* @__PURE__ */ new Map(), count: 0 };
|
|
4219
|
+
const allowRoots = repoFilters ? new Set(repoFilters.map((r) => path19.resolve(r))) : null;
|
|
4220
|
+
const repoIds = allowRoots ? repos.filter((r) => allowRoots.has(path19.resolve(r.repoRoot))).map((r) => r.repoId) : void 0;
|
|
4221
|
+
const rows = workspaceStore.searchFts(ftq, lexicalK, repoIds);
|
|
4222
|
+
const lexByRepoRoot = /* @__PURE__ */ new Map();
|
|
4223
|
+
for (const r of rows) {
|
|
4224
|
+
const row = workspaceStore.getChunkById(r.id);
|
|
4225
|
+
if (!row) continue;
|
|
4226
|
+
const rootKey = path19.resolve(row.repo_root);
|
|
4227
|
+
const arr = lexByRepoRoot.get(rootKey) ?? [];
|
|
4228
|
+
arr.push({ id: r.id, score: bm25ToScore01(r.bm25) });
|
|
4229
|
+
lexByRepoRoot.set(rootKey, arr);
|
|
4230
|
+
}
|
|
4231
|
+
return { lexByRepoRoot, count: rows.length };
|
|
4232
|
+
}
|
|
4233
|
+
async function collectWorkspaceCandidates(args) {
|
|
4234
|
+
const { repos, qVec, query, vectorK, lexicalK, profile, opts, lexByRepoRoot, canUseWorkspaceLex } = args;
|
|
4235
|
+
const repoFilters = opts.filters?.repoRoots;
|
|
4236
|
+
const langFilter = opts.filters?.language;
|
|
4237
|
+
const pathPrefix = opts.filters?.pathPrefix;
|
|
4238
|
+
const candidates = [];
|
|
4239
|
+
let vecCount = 0;
|
|
4240
|
+
let lexCount = 0;
|
|
4241
|
+
for (const repo of repos) {
|
|
4242
|
+
if (repoFilters && !repoFilters.includes(repo.repoRoot)) continue;
|
|
4243
|
+
let includePaths = opts.scope?.includePaths?.slice();
|
|
4244
|
+
if (opts.scope?.changedOnly) {
|
|
4245
|
+
try {
|
|
4246
|
+
const changed = await listChangedFiles(repo.repoRoot, opts.scope.baseRef ?? "HEAD~1");
|
|
4247
|
+
includePaths = includePaths ? includePaths.filter((p) => changed.includes(p)) : changed;
|
|
4248
|
+
} catch {
|
|
4249
|
+
}
|
|
4250
|
+
}
|
|
4251
|
+
const [vHits, lHits] = await Promise.all([
|
|
4252
|
+
repo.vectorCandidates(qVec, vectorK, includePaths),
|
|
4253
|
+
canUseWorkspaceLex ? Promise.resolve(lexByRepoRoot?.get(path19.resolve(repo.repoRoot)) ?? []) : repo.lexicalCandidates(query, lexicalK, includePaths)
|
|
4254
|
+
]);
|
|
4255
|
+
vecCount += vHits.length;
|
|
4256
|
+
if (!canUseWorkspaceLex) lexCount += lHits.length;
|
|
4257
|
+
const m = /* @__PURE__ */ new Map();
|
|
4258
|
+
for (const vh of vHits) {
|
|
4259
|
+
const id = vh.id;
|
|
4260
|
+
const vector01 = vectorCosineToScore01(vh.score);
|
|
4261
|
+
m.set(id, { repo, id, vector01, combined: 0 });
|
|
4262
|
+
}
|
|
4263
|
+
for (const lh of lHits) {
|
|
4264
|
+
const id = lh.id;
|
|
4265
|
+
const prev = m.get(id);
|
|
4266
|
+
if (prev) prev.lexical01 = lh.score;
|
|
4267
|
+
else m.set(id, { repo, id, lexical01: lh.score, combined: 0 });
|
|
4268
|
+
}
|
|
4269
|
+
const halfLife = halfLifeDaysForProfile(profile.name);
|
|
4270
|
+
for (const c of m.values()) {
|
|
4271
|
+
const meta = repo.getChunkMeta(c.id);
|
|
4272
|
+
if (!meta) continue;
|
|
4273
|
+
if (langFilter && meta.language !== langFilter) continue;
|
|
4274
|
+
if (pathPrefix && !meta.path.startsWith(pathPrefix)) continue;
|
|
4275
|
+
c.recency01 = profile.weights.recency > 0 ? recencyScore(meta.fileMtimeMs, halfLife) : 0;
|
|
4276
|
+
let kindFactor = 1;
|
|
4277
|
+
if (meta.kind === "synopsis" && profile.name === "search") kindFactor = 0.85;
|
|
4278
|
+
if (meta.kind === "synopsis" && profile.name === "architecture") kindFactor = 1.05;
|
|
4279
|
+
const v = c.vector01 ?? 0;
|
|
4280
|
+
const l = c.lexical01 ?? 0;
|
|
4281
|
+
const r = c.recency01 ?? 0;
|
|
4282
|
+
c.combined = clamp(kindFactor * (profile.weights.vector * v + profile.weights.lexical * l + profile.weights.recency * r), 0, 1);
|
|
4283
|
+
candidates.push(c);
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4286
|
+
return { candidates, vecCount, lexCount };
|
|
4287
|
+
}
|
|
4288
|
+
function rankWorkspaceCandidates(args) {
|
|
4289
|
+
const { candidates, maxMerged, k } = args;
|
|
4290
|
+
candidates.sort((a, b) => b.combined - a.combined);
|
|
4291
|
+
const merged = candidates.slice(0, maxMerged);
|
|
4292
|
+
const top = merged.slice(0, k);
|
|
4293
|
+
const hits = top.map((c) => {
|
|
4294
|
+
const meta = c.repo.getChunkMeta(c.id);
|
|
4295
|
+
const preview = makePreview(c.repo.getChunkText(c.id));
|
|
4296
|
+
return {
|
|
4297
|
+
score: c.combined,
|
|
4298
|
+
scoreBreakdown: { vector: c.vector01, lexical: c.lexical01, recency: c.recency01 },
|
|
4299
|
+
chunk: { ...meta, preview }
|
|
4300
|
+
};
|
|
4301
|
+
});
|
|
4302
|
+
return { merged, hits };
|
|
4303
|
+
}
|
|
4304
|
+
|
|
4305
|
+
// src/indexer/workspaceRetrieveContext.ts
|
|
4306
|
+
async function warmSymbolGraphForHits(repos, hits) {
|
|
4307
|
+
const byRepo = /* @__PURE__ */ new Map();
|
|
4308
|
+
for (const h of hits) {
|
|
4309
|
+
const s = byRepo.get(h.chunk.repoRoot) ?? /* @__PURE__ */ new Set();
|
|
4310
|
+
s.add(h.chunk.path);
|
|
4311
|
+
byRepo.set(h.chunk.repoRoot, s);
|
|
4312
|
+
}
|
|
4313
|
+
for (const [repoRoot, paths] of byRepo) {
|
|
4314
|
+
const repo = repos.find((r) => r.repoRoot === repoRoot);
|
|
4315
|
+
if (!repo) continue;
|
|
4316
|
+
await repo.warmSymbolGraphEdges(Array.from(paths), { maxFiles: 6 });
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
async function fetchGraphNeighborFiles(args) {
|
|
4320
|
+
const { graphStore, repos, hits, profile, workspaceRoot, emitProgress } = args;
|
|
4321
|
+
if (!graphStore?.neighborFiles) return [];
|
|
4322
|
+
const seeds = [];
|
|
4323
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4324
|
+
for (const h of hits) {
|
|
4325
|
+
const repo = repos.find((r) => r.repoRoot === h.chunk.repoRoot);
|
|
4326
|
+
if (!repo) continue;
|
|
4327
|
+
const key = `${repo.repoId}:${h.chunk.path}`;
|
|
4328
|
+
if (seen.has(key)) continue;
|
|
4329
|
+
seen.add(key);
|
|
4330
|
+
seeds.push({ repoId: repo.repoId, path: h.chunk.path });
|
|
4331
|
+
if (seeds.length >= 4) break;
|
|
4332
|
+
}
|
|
4333
|
+
if (seeds.length === 0) return [];
|
|
4334
|
+
const startedAt = Date.now();
|
|
4335
|
+
emitProgress({ type: "workspace/retrieve/graph/start", workspaceRoot, seeds: seeds.length });
|
|
4336
|
+
try {
|
|
4337
|
+
const neighbors = await graphStore.neighborFiles({
|
|
4338
|
+
seeds,
|
|
4339
|
+
limit: profile.name === "architecture" ? 16 : 10,
|
|
4340
|
+
kinds: ["definition", "reference", "implementation", "typeDefinition"]
|
|
4341
|
+
});
|
|
4342
|
+
emitProgress({ type: "workspace/retrieve/graph/done", workspaceRoot, neighbors: neighbors.length, ms: Date.now() - startedAt });
|
|
4343
|
+
return neighbors;
|
|
4344
|
+
} catch {
|
|
4345
|
+
return [];
|
|
4346
|
+
}
|
|
4347
|
+
}
|
|
4348
|
+
async function buildContextBlocks(args) {
|
|
4349
|
+
const { repos, hits, graphNeighborFiles, profile } = args;
|
|
4350
|
+
const contextBlocks = [];
|
|
4351
|
+
const seenKey = /* @__PURE__ */ new Set();
|
|
4352
|
+
const addBlock = (repoRoot, filePath, startLine, endLine, text, reason) => {
|
|
4353
|
+
const key = `${repoRoot}:${filePath}:${startLine}:${endLine}:${text.length}:${reason}`;
|
|
4354
|
+
if (seenKey.has(key)) return;
|
|
4355
|
+
seenKey.add(key);
|
|
4356
|
+
if (!text.trim()) return;
|
|
4357
|
+
contextBlocks.push({ repoRoot, path: filePath, startLine, endLine, text, reason });
|
|
4358
|
+
};
|
|
4359
|
+
try {
|
|
4360
|
+
const byRepoId = /* @__PURE__ */ new Map();
|
|
4361
|
+
for (const r of repos) byRepoId.set(r.repoId, r);
|
|
4362
|
+
for (const n of graphNeighborFiles.slice(0, 10)) {
|
|
4363
|
+
const repo = byRepoId.get(n.repoId);
|
|
4364
|
+
if (!repo) continue;
|
|
4365
|
+
const chunkId = await repo.getRepresentativeChunkIdForFile(n.path, true);
|
|
4366
|
+
if (!chunkId) continue;
|
|
4367
|
+
const meta = repo.getChunkMeta(chunkId);
|
|
4368
|
+
if (!meta) continue;
|
|
4369
|
+
const text = repo.getChunkText(chunkId);
|
|
4370
|
+
addBlock(meta.repoRoot, meta.path, meta.startLine, meta.endLine, text, `graph neighbor (${n.weight})`);
|
|
4371
|
+
}
|
|
4372
|
+
} catch {
|
|
4373
|
+
}
|
|
4374
|
+
for (const h of hits) {
|
|
4375
|
+
const repo = repos.find((r) => r.repoRoot === h.chunk.repoRoot);
|
|
4376
|
+
if (!repo) continue;
|
|
4377
|
+
const hitText = repo.getChunkText(h.chunk.id);
|
|
4378
|
+
addBlock(h.chunk.repoRoot, h.chunk.path, h.chunk.startLine, h.chunk.endLine, hitText, "primary hit");
|
|
4379
|
+
const expanded = await repo.expandContext(h.chunk.id, {
|
|
4380
|
+
adjacentChunks: profile.expand.adjacentChunks ?? 0,
|
|
4381
|
+
followImports: profile.expand.followImports ?? 0,
|
|
4382
|
+
includeFileSynopsis: profile.expand.includeFileSynopsis ?? false
|
|
4383
|
+
});
|
|
4384
|
+
for (const ex of expanded) {
|
|
4385
|
+
const meta = repo.getChunkMeta(ex.id);
|
|
4386
|
+
if (!meta) continue;
|
|
4387
|
+
const text = repo.getChunkText(ex.id);
|
|
4388
|
+
addBlock(meta.repoRoot, meta.path, meta.startLine, meta.endLine, text, ex.reason);
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
return contextBlocks;
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
// src/indexer/workspaceIndexer.ts
|
|
4143
4395
|
var WorkspaceIndexer = class {
|
|
4144
4396
|
constructor(workspaceRoot, embedder, config = {}) {
|
|
4145
4397
|
this.workspaceRoot = workspaceRoot;
|
|
@@ -4147,23 +4399,30 @@ var WorkspaceIndexer = class {
|
|
|
4147
4399
|
this.config = { ...config };
|
|
4148
4400
|
if (!this.config.cacheDir) this.config.cacheDir = defaultCacheDir();
|
|
4149
4401
|
this.progress = asProgressSink(this.config.progress);
|
|
4150
|
-
const wsId = sha256Hex(
|
|
4151
|
-
|
|
4152
|
-
this.workspaceStore = new WorkspaceStore(dbPath);
|
|
4153
|
-
this.workspaceStore.setMeta("workspaceRoot", path17.resolve(this.workspaceRoot));
|
|
4402
|
+
const wsId = sha256Hex(path20.resolve(this.workspaceRoot)).slice(0, 16);
|
|
4403
|
+
this.workspaceDbPath = path20.join(this.config.cacheDir, "workspace", wsId, "workspace.sqlite");
|
|
4154
4404
|
}
|
|
4155
4405
|
repos = [];
|
|
4156
4406
|
config;
|
|
4157
4407
|
progress = asProgressSink();
|
|
4158
4408
|
workspaceStore = null;
|
|
4159
4409
|
graphStore = null;
|
|
4410
|
+
workspaceDbPath;
|
|
4160
4411
|
emitProgress(event) {
|
|
4161
4412
|
try {
|
|
4162
4413
|
this.progress?.emit(event);
|
|
4163
4414
|
} catch {
|
|
4164
4415
|
}
|
|
4165
4416
|
}
|
|
4417
|
+
async ensureWorkspaceStore() {
|
|
4418
|
+
if (this.workspaceStore) return this.workspaceStore;
|
|
4419
|
+
const ws = await createWorkspaceStoreAsync(this.workspaceDbPath, { db: this.config.workspace?.db });
|
|
4420
|
+
ws.setMeta("workspaceRoot", path20.resolve(this.workspaceRoot));
|
|
4421
|
+
this.workspaceStore = ws;
|
|
4422
|
+
return ws;
|
|
4423
|
+
}
|
|
4166
4424
|
async open() {
|
|
4425
|
+
await this.ensureWorkspaceStore();
|
|
4167
4426
|
if (!this.graphStore && this.config.workspace?.graph?.provider === "neo4j") {
|
|
4168
4427
|
try {
|
|
4169
4428
|
const n = this.config.workspace.graph.neo4j;
|
|
@@ -4235,195 +4494,49 @@ var WorkspaceIndexer = class {
|
|
|
4235
4494
|
getRepoIndexers() {
|
|
4236
4495
|
return this.repos.slice();
|
|
4237
4496
|
}
|
|
4238
|
-
resolveProfile(opts) {
|
|
4239
|
-
const name = opts?.profile ?? "search";
|
|
4240
|
-
const base = DEFAULT_PROFILES[name] ?? DEFAULT_PROFILES.search;
|
|
4241
|
-
const configPatch = this.config.profiles?.[name] ?? {};
|
|
4242
|
-
const merged1 = deepMergeProfile(base, configPatch);
|
|
4243
|
-
const merged2 = deepMergeProfile(merged1, opts?.profileOverrides);
|
|
4244
|
-
const w = merged2.weights;
|
|
4245
|
-
const sum = Math.max(1e-6, w.vector + w.lexical + w.recency);
|
|
4246
|
-
merged2.weights = { vector: w.vector / sum, lexical: w.lexical / sum, recency: w.recency / sum };
|
|
4247
|
-
return merged2;
|
|
4248
|
-
}
|
|
4249
4497
|
async retrieve(query, opts = {}) {
|
|
4250
4498
|
if (this.repos.length === 0) await this.open();
|
|
4251
|
-
const profile = this.
|
|
4499
|
+
const profile = resolveWorkspaceProfile(this.config, opts);
|
|
4252
4500
|
const startedAt = Date.now();
|
|
4253
4501
|
this.emitProgress({ type: "workspace/retrieve/start", workspaceRoot: this.workspaceRoot, profile: profile.name, query });
|
|
4254
4502
|
const qVec = (await this.embedder.embed([query]))[0];
|
|
4255
4503
|
const vectorK = profile.candidates?.vectorK ?? Math.max(profile.k * 3, 30);
|
|
4256
4504
|
const lexicalK = profile.candidates?.lexicalK ?? Math.max(profile.k * 3, 30);
|
|
4257
4505
|
const maxMerged = profile.candidates?.maxMergedCandidates ?? Math.max(profile.k * 8, 120);
|
|
4258
|
-
const
|
|
4259
|
-
const
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
const rootKey = path17.resolve(row.repo_root);
|
|
4277
|
-
const arr = workspaceLexByRepoRoot.get(rootKey) ?? [];
|
|
4278
|
-
arr.push({ id: r.id, score: bm25ToScore01(r.bm25) });
|
|
4279
|
-
workspaceLexByRepoRoot.set(rootKey, arr);
|
|
4280
|
-
}
|
|
4281
|
-
}
|
|
4282
|
-
}
|
|
4283
|
-
for (const repo of this.repos) {
|
|
4284
|
-
if (repoFilters && !repoFilters.includes(repo.repoRoot)) continue;
|
|
4285
|
-
let includePaths = opts.scope?.includePaths?.slice();
|
|
4286
|
-
if (opts.scope?.changedOnly) {
|
|
4287
|
-
try {
|
|
4288
|
-
const changed = await listChangedFiles(repo.repoRoot, opts.scope.baseRef ?? "HEAD~1");
|
|
4289
|
-
includePaths = includePaths ? includePaths.filter((p) => changed.includes(p)) : changed;
|
|
4290
|
-
} catch {
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
const [vHits, lHits] = await Promise.all([
|
|
4294
|
-
repo.vectorCandidates(qVec, vectorK, includePaths),
|
|
4295
|
-
canUseWorkspaceLex ? Promise.resolve(workspaceLexByRepoRoot.get(path17.resolve(repo.repoRoot)) ?? []) : repo.lexicalCandidates(query, lexicalK, includePaths)
|
|
4296
|
-
]);
|
|
4297
|
-
vecCount += vHits.length;
|
|
4298
|
-
if (!canUseWorkspaceLex) lexCount += lHits.length;
|
|
4299
|
-
const m = /* @__PURE__ */ new Map();
|
|
4300
|
-
for (const vh of vHits) {
|
|
4301
|
-
const id = vh.id;
|
|
4302
|
-
const vector01 = vectorCosineToScore01(vh.score);
|
|
4303
|
-
m.set(id, { repo, id, vector01, combined: 0 });
|
|
4304
|
-
}
|
|
4305
|
-
for (const lh of lHits) {
|
|
4306
|
-
const id = lh.id;
|
|
4307
|
-
const prev = m.get(id);
|
|
4308
|
-
if (prev) prev.lexical01 = lh.score;
|
|
4309
|
-
else m.set(id, { repo, id, lexical01: lh.score, combined: 0 });
|
|
4310
|
-
}
|
|
4311
|
-
const halfLife = halfLifeDaysForProfile(profile.name);
|
|
4312
|
-
for (const c of m.values()) {
|
|
4313
|
-
const meta = repo.getChunkMeta(c.id);
|
|
4314
|
-
if (!meta) continue;
|
|
4315
|
-
if (langFilter && meta.language !== langFilter) continue;
|
|
4316
|
-
if (pathPrefix && !meta.path.startsWith(pathPrefix)) continue;
|
|
4317
|
-
c.recency01 = profile.weights.recency > 0 ? recencyScore(meta.fileMtimeMs, halfLife) : 0;
|
|
4318
|
-
let kindFactor = 1;
|
|
4319
|
-
if (meta.kind === "synopsis" && profile.name === "search") kindFactor = 0.85;
|
|
4320
|
-
if (meta.kind === "synopsis" && profile.name === "architecture") kindFactor = 1.05;
|
|
4321
|
-
const v = c.vector01 ?? 0;
|
|
4322
|
-
const l = c.lexical01 ?? 0;
|
|
4323
|
-
const r = c.recency01 ?? 0;
|
|
4324
|
-
c.combined = clamp(
|
|
4325
|
-
kindFactor * (profile.weights.vector * v + profile.weights.lexical * l + profile.weights.recency * r),
|
|
4326
|
-
0,
|
|
4327
|
-
1
|
|
4328
|
-
);
|
|
4329
|
-
candidates.push(c);
|
|
4330
|
-
}
|
|
4331
|
-
}
|
|
4332
|
-
candidates.sort((a, b) => b.combined - a.combined);
|
|
4333
|
-
const merged = candidates.slice(0, maxMerged);
|
|
4334
|
-
const top = merged.slice(0, profile.k);
|
|
4335
|
-
const hits = top.map((c) => {
|
|
4336
|
-
const meta = c.repo.getChunkMeta(c.id);
|
|
4337
|
-
const preview = makePreview(c.repo.getChunkText(c.id));
|
|
4338
|
-
return {
|
|
4339
|
-
score: c.combined,
|
|
4340
|
-
scoreBreakdown: { vector: c.vector01, lexical: c.lexical01, recency: c.recency01 },
|
|
4341
|
-
chunk: { ...meta, preview }
|
|
4342
|
-
};
|
|
4506
|
+
const canUseWorkspaceLex = !!this.workspaceStore && this.workspaceStore.ftsEnabled && this.config.storage?.ftsMode !== "off" && !opts.scope?.includePaths && !opts.scope?.changedOnly;
|
|
4507
|
+
const { lexByRepoRoot, count: workspaceLexCount } = canUseWorkspaceLex && profile.weights.lexical > 0 && this.workspaceStore ? buildWorkspaceLexByRepoRoot({
|
|
4508
|
+
workspaceStore: this.workspaceStore,
|
|
4509
|
+
repos: this.repos,
|
|
4510
|
+
query,
|
|
4511
|
+
lexicalK,
|
|
4512
|
+
repoFilters: opts.filters?.repoRoots
|
|
4513
|
+
}) : { lexByRepoRoot: void 0, count: 0 };
|
|
4514
|
+
const { candidates, vecCount, lexCount } = await collectWorkspaceCandidates({
|
|
4515
|
+
repos: this.repos,
|
|
4516
|
+
qVec,
|
|
4517
|
+
query,
|
|
4518
|
+
vectorK,
|
|
4519
|
+
lexicalK,
|
|
4520
|
+
profile,
|
|
4521
|
+
opts,
|
|
4522
|
+
lexByRepoRoot,
|
|
4523
|
+
canUseWorkspaceLex
|
|
4343
4524
|
});
|
|
4525
|
+
const { merged, hits } = rankWorkspaceCandidates({ candidates, maxMerged, k: profile.k });
|
|
4526
|
+
const totalLexCount = (canUseWorkspaceLex ? workspaceLexCount : 0) + lexCount;
|
|
4344
4527
|
try {
|
|
4345
|
-
|
|
4346
|
-
for (const h of hits) {
|
|
4347
|
-
const s = byRepo.get(h.chunk.repoRoot) ?? /* @__PURE__ */ new Set();
|
|
4348
|
-
s.add(h.chunk.path);
|
|
4349
|
-
byRepo.set(h.chunk.repoRoot, s);
|
|
4350
|
-
}
|
|
4351
|
-
for (const [repoRoot, paths] of byRepo) {
|
|
4352
|
-
const repo = this.repos.find((r) => r.repoRoot === repoRoot);
|
|
4353
|
-
if (!repo) continue;
|
|
4354
|
-
await repo.warmSymbolGraphEdges(Array.from(paths), { maxFiles: 6 });
|
|
4355
|
-
}
|
|
4528
|
+
await warmSymbolGraphForHits(this.repos, hits);
|
|
4356
4529
|
} catch {
|
|
4357
4530
|
}
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
if (seen.has(key)) continue;
|
|
4368
|
-
seen.add(key);
|
|
4369
|
-
seeds.push({ repoId: repo.repoId, path: h.chunk.path });
|
|
4370
|
-
if (seeds.length >= 4) break;
|
|
4371
|
-
}
|
|
4372
|
-
if (seeds.length > 0) {
|
|
4373
|
-
const gs = Date.now();
|
|
4374
|
-
this.emitProgress({ type: "workspace/retrieve/graph/start", workspaceRoot: this.workspaceRoot, seeds: seeds.length });
|
|
4375
|
-
graphNeighborFiles = await this.graphStore.neighborFiles({
|
|
4376
|
-
seeds,
|
|
4377
|
-
limit: profile.name === "architecture" ? 16 : 10,
|
|
4378
|
-
kinds: ["definition", "reference", "implementation", "typeDefinition"]
|
|
4379
|
-
});
|
|
4380
|
-
this.emitProgress({ type: "workspace/retrieve/graph/done", workspaceRoot: this.workspaceRoot, neighbors: graphNeighborFiles.length, ms: Date.now() - gs });
|
|
4381
|
-
}
|
|
4382
|
-
}
|
|
4383
|
-
} catch {
|
|
4384
|
-
graphNeighborFiles = [];
|
|
4385
|
-
}
|
|
4386
|
-
const contextBlocks = [];
|
|
4387
|
-
const seenKey = /* @__PURE__ */ new Set();
|
|
4388
|
-
const addBlock = (repoRoot, path19, startLine, endLine, text, reason) => {
|
|
4389
|
-
const key = `${repoRoot}:${path19}:${startLine}:${endLine}:${text.length}:${reason}`;
|
|
4390
|
-
if (seenKey.has(key)) return;
|
|
4391
|
-
seenKey.add(key);
|
|
4392
|
-
if (!text.trim()) return;
|
|
4393
|
-
contextBlocks.push({ repoRoot, path: path19, startLine, endLine, text, reason });
|
|
4394
|
-
};
|
|
4395
|
-
try {
|
|
4396
|
-
const byRepoId = /* @__PURE__ */ new Map();
|
|
4397
|
-
for (const r of this.repos) byRepoId.set(r.repoId, r);
|
|
4398
|
-
for (const n of graphNeighborFiles.slice(0, 10)) {
|
|
4399
|
-
const repo = byRepoId.get(n.repoId);
|
|
4400
|
-
if (!repo) continue;
|
|
4401
|
-
const chunkId = await repo.getRepresentativeChunkIdForFile(n.path, true);
|
|
4402
|
-
if (!chunkId) continue;
|
|
4403
|
-
const meta = repo.getChunkMeta(chunkId);
|
|
4404
|
-
if (!meta) continue;
|
|
4405
|
-
const text = repo.getChunkText(chunkId);
|
|
4406
|
-
addBlock(meta.repoRoot, meta.path, meta.startLine, meta.endLine, text, `graph neighbor (${n.weight})`);
|
|
4407
|
-
}
|
|
4408
|
-
} catch {
|
|
4409
|
-
}
|
|
4410
|
-
for (const h of hits) {
|
|
4411
|
-
const repo = this.repos.find((r) => r.repoRoot === h.chunk.repoRoot);
|
|
4412
|
-
if (!repo) continue;
|
|
4413
|
-
const text = repo.getChunkText(h.chunk.id);
|
|
4414
|
-
addBlock(h.chunk.repoRoot, h.chunk.path, h.chunk.startLine, h.chunk.endLine, text, "primary hit");
|
|
4415
|
-
const expanded = await repo.expandContext(h.chunk.id, {
|
|
4416
|
-
adjacentChunks: profile.expand.adjacentChunks ?? 0,
|
|
4417
|
-
followImports: profile.expand.followImports ?? 0,
|
|
4418
|
-
includeFileSynopsis: profile.expand.includeFileSynopsis ?? false
|
|
4419
|
-
});
|
|
4420
|
-
for (const ex of expanded) {
|
|
4421
|
-
const meta = repo.getChunkMeta(ex.id);
|
|
4422
|
-
if (!meta) continue;
|
|
4423
|
-
const t = repo.getChunkText(ex.id);
|
|
4424
|
-
addBlock(meta.repoRoot, meta.path, meta.startLine, meta.endLine, t, ex.reason);
|
|
4425
|
-
}
|
|
4426
|
-
}
|
|
4531
|
+
const graphNeighborFiles = await fetchGraphNeighborFiles({
|
|
4532
|
+
graphStore: this.graphStore,
|
|
4533
|
+
repos: this.repos,
|
|
4534
|
+
hits,
|
|
4535
|
+
profile,
|
|
4536
|
+
workspaceRoot: this.workspaceRoot,
|
|
4537
|
+
emitProgress: (e) => this.emitProgress(e)
|
|
4538
|
+
});
|
|
4539
|
+
const contextBlocks = await buildContextBlocks({ repos: this.repos, hits, graphNeighborFiles, profile });
|
|
4427
4540
|
const bundle = {
|
|
4428
4541
|
hits,
|
|
4429
4542
|
context: contextBlocks,
|
|
@@ -4432,7 +4545,7 @@ var WorkspaceIndexer = class {
|
|
|
4432
4545
|
reposSearched: this.repos.length,
|
|
4433
4546
|
candidates: {
|
|
4434
4547
|
vector: vecCount,
|
|
4435
|
-
lexical:
|
|
4548
|
+
lexical: totalLexCount,
|
|
4436
4549
|
merged: merged.length,
|
|
4437
4550
|
returned: hits.length
|
|
4438
4551
|
}
|
|
@@ -4444,7 +4557,7 @@ var WorkspaceIndexer = class {
|
|
|
4444
4557
|
profile: profile.name,
|
|
4445
4558
|
ms: Date.now() - startedAt,
|
|
4446
4559
|
hits: hits.length,
|
|
4447
|
-
candidates: { vector: vecCount, lexical:
|
|
4560
|
+
candidates: { vector: vecCount, lexical: totalLexCount, merged: merged.length }
|
|
4448
4561
|
});
|
|
4449
4562
|
return bundle;
|
|
4450
4563
|
}
|
|
@@ -4581,11 +4694,11 @@ var HashEmbeddingsProvider = class {
|
|
|
4581
4694
|
};
|
|
4582
4695
|
|
|
4583
4696
|
// src/config.ts
|
|
4584
|
-
import
|
|
4585
|
-
import
|
|
4697
|
+
import fs16 from "fs";
|
|
4698
|
+
import path21 from "path";
|
|
4586
4699
|
function loadConfigFile(filePath) {
|
|
4587
|
-
const abs =
|
|
4588
|
-
const raw =
|
|
4700
|
+
const abs = path21.resolve(filePath);
|
|
4701
|
+
const raw = fs16.readFileSync(abs, "utf8");
|
|
4589
4702
|
const json = JSON.parse(raw);
|
|
4590
4703
|
const cfg = { ...json };
|
|
4591
4704
|
if (json.redact?.patterns && Array.isArray(json.redact.patterns)) {
|
|
@@ -4615,11 +4728,13 @@ export {
|
|
|
4615
4728
|
NoopAnnIndex,
|
|
4616
4729
|
createAnnIndex,
|
|
4617
4730
|
RepoIndexer,
|
|
4618
|
-
DEFAULT_PROFILES,
|
|
4619
|
-
deepMergeProfile,
|
|
4620
4731
|
discoverGitRepos,
|
|
4621
4732
|
pickRepoOverride,
|
|
4622
4733
|
mergeIndexerConfig,
|
|
4734
|
+
betterSqlite3Adapter,
|
|
4735
|
+
sqlJsAdapter,
|
|
4736
|
+
createWorkspaceStore,
|
|
4737
|
+
createWorkspaceStoreAsync,
|
|
4623
4738
|
WorkspaceStore,
|
|
4624
4739
|
Neo4jGraphStore,
|
|
4625
4740
|
createNeo4jGraphStore,
|
|
@@ -4629,6 +4744,8 @@ export {
|
|
|
4629
4744
|
VsCodeContributesLanguageLinkStrategy,
|
|
4630
4745
|
WorkspaceLinker,
|
|
4631
4746
|
linkWorkspaceRepos,
|
|
4747
|
+
DEFAULT_PROFILES,
|
|
4748
|
+
deepMergeProfile,
|
|
4632
4749
|
WorkspaceIndexer,
|
|
4633
4750
|
OllamaEmbeddingsProvider,
|
|
4634
4751
|
OpenAIEmbeddingsProvider,
|