dsh-codegraph-visualizer 0.1.1 → 0.3.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.
Files changed (58) hide show
  1. package/README.md +391 -226
  2. package/assets/icon-180.png +0 -0
  3. package/assets/icon.svg +30 -0
  4. package/cordis.patch.yml +22 -17
  5. package/dist/CodeGraphAdapter-BNIK0xHU.js +422 -0
  6. package/dist/CodeGraphAdapter-BNIK0xHU.js.map +1 -0
  7. package/dist/CodeGraphAdapter-CXj1hbdm.js +10 -0
  8. package/dist/FileSystemAdapter-CgasSGbB.js +524 -0
  9. package/dist/FileSystemAdapter-CgasSGbB.js.map +1 -0
  10. package/dist/LensAdapter-C9Saf_i_.js +89 -0
  11. package/dist/LensAdapter-C9Saf_i_.js.map +1 -0
  12. package/dist/Logger-DUIJSeNu.js +80 -0
  13. package/dist/Logger-DUIJSeNu.js.map +1 -0
  14. package/dist/TreeSitterAdapter-C-EWy8br.js +631 -0
  15. package/dist/TreeSitterAdapter-C-EWy8br.js.map +1 -0
  16. package/dist/TreeSitterAdapter-C6FcO2_s.js +8 -0
  17. package/dist/client/index.css +8963 -1724
  18. package/dist/client/index.css.map +1 -0
  19. package/dist/client/index.d.ts +634 -0
  20. package/dist/client/index.d.ts.map +1 -0
  21. package/dist/client/index.esm.js +57197 -20713
  22. package/dist/client/index.js.map +1 -0
  23. package/dist/client/{index.js → worker/layoutWorker.js} +7657 -8787
  24. package/dist/client.js +90426 -0
  25. package/dist/codeGraphDb-B-vpZmpm.js +9 -0
  26. package/dist/codeGraphDb-T6K3dK5D.js +357 -0
  27. package/dist/codeGraphDb-T6K3dK5D.js.map +1 -0
  28. package/dist/codeGraphRows-BhZX34uB.js +6 -0
  29. package/dist/codeGraphRows-C7hqu35E.js +246 -0
  30. package/dist/codeGraphRows-C7hqu35E.js.map +1 -0
  31. package/dist/constants-CQq93l3e.js +399 -0
  32. package/dist/constants-CQq93l3e.js.map +1 -0
  33. package/dist/graphFingerprint-CeARo7jG.js +4 -0
  34. package/dist/graphFingerprint-PuxORZUF.js +277 -0
  35. package/dist/graphFingerprint-PuxORZUF.js.map +1 -0
  36. package/dist/graphMetrics-C0F30730.js +555 -0
  37. package/dist/graphMetrics-C0F30730.js.map +1 -0
  38. package/dist/index.d.ts +572 -9
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +14819 -2009
  41. package/dist/index.js.map +1 -1
  42. package/dist/inheritanceEnhancer-Bi3UoYJS.js +291 -0
  43. package/dist/inheritanceEnhancer-Bi3UoYJS.js.map +1 -0
  44. package/dist/layerUtils-DDm-EsaD.js +72 -0
  45. package/dist/layerUtils-DDm-EsaD.js.map +1 -0
  46. package/dist/nativeIndex-CABbgERW.js +347 -0
  47. package/dist/nativeIndex-CABbgERW.js.map +1 -0
  48. package/dist/nativeIndex-esaDOsq8.js +5 -0
  49. package/dist/treeSitterExtractors-B1ybKNrC.js +394 -0
  50. package/dist/treeSitterExtractors-B1ybKNrC.js.map +1 -0
  51. package/dist/types-BUDxI_00.js +23 -0
  52. package/dist/types-BUDxI_00.js.map +1 -0
  53. package/locale/en.json +6 -0
  54. package/locale/zh-CN.json +6 -0
  55. package/locale/zh.json +6 -0
  56. package/package.json +100 -20
  57. package/dist/client-cjs/index.cjs +0 -44283
  58. package/dist/client-cjs/index.css +0 -2404
@@ -0,0 +1,347 @@
1
+ import { scoped } from "./Logger-DUIJSeNu.js";
2
+ import { join, normalize } from "node:path";
3
+ import { createRequire } from "node:module";
4
+ import { existsSync, mkdirSync, rmSync } from "node:fs";
5
+
6
+ //#region src/adapters/nativeIndex.ts
7
+ const log = scoped("native-index");
8
+ const require = createRequire(import.meta.url);
9
+ /**
10
+ * 原生索引 DDL——**逐列复用上游 schema**(见模块头注)。
11
+ * `edges.id` 刻意不建主键:上游 edges 的 id 是 INTEGER 自增,而本插件的
12
+ * GraphEdge.id 是字符串(`tsedge:` 前缀等)。为了「同列名同语义」,原生库的
13
+ * edges 用与上游相同的列布局,但 source+target+kind 联合去重由写侧保证,
14
+ * 自增 id 仅作行标识(读侧 EDGE_ROW_COLUMNS 会 SELECT id,上游行是数字自增、
15
+ * 原生行也是数字自增——同型)。
16
+ */
17
+ const NATIVE_MIGRATION_SQL = [
18
+ `CREATE TABLE IF NOT EXISTS nodes (
19
+ id TEXT PRIMARY KEY,
20
+ kind TEXT NOT NULL,
21
+ name TEXT NOT NULL,
22
+ file_path TEXT NOT NULL DEFAULT '',
23
+ start_line INTEGER NOT NULL DEFAULT 0,
24
+ signature TEXT,
25
+ docstring TEXT,
26
+ is_exported INTEGER NOT NULL DEFAULT 0
27
+ )`,
28
+ `CREATE TABLE IF NOT EXISTS edges (
29
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
30
+ source TEXT NOT NULL,
31
+ target TEXT NOT NULL,
32
+ kind TEXT NOT NULL,
33
+ metadata TEXT,
34
+ line INTEGER
35
+ )`,
36
+ `CREATE INDEX IF NOT EXISTS idx_native_nodes_kind ON nodes(kind)`,
37
+ `CREATE INDEX IF NOT EXISTS idx_native_nodes_file ON nodes(file_path)`,
38
+ `CREATE INDEX IF NOT EXISTS idx_native_edges_source ON edges(source)`,
39
+ `CREATE INDEX IF NOT EXISTS idx_native_edges_target ON edges(target)`,
40
+ `CREATE TABLE IF NOT EXISTS index_meta (
41
+ workspace TEXT PRIMARY KEY,
42
+ fingerprint TEXT NOT NULL,
43
+ node_count INTEGER NOT NULL,
44
+ edge_count INTEGER NOT NULL,
45
+ indexed_at INTEGER NOT NULL,
46
+ gitignore_present INTEGER NOT NULL DEFAULT 0,
47
+ gitignore_rules INTEGER NOT NULL DEFAULT 0,
48
+ ignored_entries INTEGER NOT NULL DEFAULT 0
49
+ )`
50
+ ];
51
+ /**
52
+ * 老库升级 ALTER(cycle-141 第七轮):CREATE IF NOT EXISTS 不会给已存在的表补列。
53
+ * **必须容错执行**——新库建表已含这些列,ALTER 会报 duplicate column;这条失败
54
+ * 是幂等成功而不是错误。此前把 ALTER 混进 NATIVE_MIGRATION_SQL 让 getWriteDb 的
55
+ * try/catch 整体失败 → 每次打开连接都返回 null → 全部写入静默失败(13 个用例
56
+ * EPERM/0 行的现场)。
57
+ */
58
+ const NATIVE_UPGRADE_SQL = [
59
+ `ALTER TABLE index_meta ADD COLUMN gitignore_present INTEGER NOT NULL DEFAULT 0`,
60
+ `ALTER TABLE index_meta ADD COLUMN gitignore_rules INTEGER NOT NULL DEFAULT 0`,
61
+ `ALTER TABLE index_meta ADD COLUMN ignored_entries INTEGER NOT NULL DEFAULT 0`
62
+ ];
63
+ /** 原生索引写连接(每工作区一个;与 codeGraphDb 的只读池隔离)。 */
64
+ const writePool = new Map();
65
+ /**
66
+ * 折叠路径中的重复反斜杠(cycle-141 第六轮)。
67
+ *
68
+ * ## 为什么不能只信调用方的转义形态
69
+ *
70
+ * workspace/repoId 沿 LLM 工具调用 / 宿主注册表传递时,JSON 转义层数不保证恒定:
71
+ * 真机实证(dsh-anic index_meta 同分钟两条记录)——`D:\Projects\...`(单反斜杠,
72
+ * 正常扫描链)与 `D:\\Projects\\...`(双反斜杠字面量,另一条调用链)先后写入。
73
+ * Windows 文件 API 对重复分隔符宽容(readdir 双反斜杠路径照样成功),扫描不报错,
74
+ * 但 **id/file_path 带毒入库**:此后按单反斜杠 id 查询(children/edges join)全部落空,
75
+ * 客户端拿到的 bootstrap id 与后续按需请求的 nodeId 永远对不上。
76
+ *
77
+ * 这里刻意**不用** `path.normalize`:它会把 `/` 统一成 `\`,破坏原生索引 id 的
78
+ * 分隔符约定(FileSystemAdapter 用 `${dirPath}/${entry}` 拼,读侧 SQL 也按 `/`
79
+ * 做噪音过滤)。只折叠 `\\` → `\`,其余逐字保留。
80
+ */
81
+ function collapseRepeatedBackslashes(p) {
82
+ return p.replace(/\\{2,}/g, "\\");
83
+ }
84
+ function resolveNativeIndexPath(workspacePath) {
85
+ const root = collapseRepeatedBackslashes(workspacePath && workspacePath !== "." ? workspacePath : process.cwd());
86
+ if (root.includes("..") || normalize(root).includes("..")) throw new Error(`Invalid workspace path: ${workspacePath}`);
87
+ const normalized = normalize(root);
88
+ return join(normalized, ".codegraph-visualizer", "native-index.db");
89
+ }
90
+ function getWriteDb(indexPath) {
91
+ const existing = writePool.get(indexPath);
92
+ if (existing) return existing;
93
+ try {
94
+ const { DatabaseSync } = require("node:sqlite");
95
+ mkdirSync(join(indexPath, ".."), { recursive: true });
96
+ const db = new DatabaseSync(indexPath);
97
+ for (const ddl of NATIVE_MIGRATION_SQL) db.exec(ddl);
98
+ for (const ddl of NATIVE_UPGRADE_SQL) try {
99
+ db.exec(ddl);
100
+ } catch {}
101
+ writePool.set(indexPath, db);
102
+ return db;
103
+ } catch (e) {
104
+ log.warn("native index open failed", {
105
+ indexPath,
106
+ error: String(e)
107
+ });
108
+ return null;
109
+ }
110
+ }
111
+ /** 关闭全部写连接(dispose/测试清池;与 closeAllDbConnections 同型)。 */
112
+ function closeNativeIndexConnections() {
113
+ for (const db of writePool.values()) try {
114
+ db.close();
115
+ } catch {}
116
+ writePool.clear();
117
+ }
118
+ function writeNativeIndex(workspacePath, fingerprint, nodes, edges, coverage = {
119
+ gitignorePresent: false,
120
+ gitignoreRules: 0,
121
+ ignoredEntries: 0
122
+ }) {
123
+ let indexPath;
124
+ try {
125
+ workspacePath = collapseRepeatedBackslashes(workspacePath);
126
+ indexPath = resolveNativeIndexPath(workspacePath);
127
+ } catch (e) {
128
+ log.warn("native index path rejected", { error: String(e) });
129
+ return false;
130
+ }
131
+ const db = getWriteDb(indexPath);
132
+ if (!db) return false;
133
+ try {
134
+ const meta = db.prepare("SELECT fingerprint, node_count, edge_count FROM index_meta WHERE workspace = ?").get(workspacePath);
135
+ if (meta && meta.fingerprint === fingerprint && meta.node_count === nodes.length && meta.edge_count === edges.length) return false;
136
+ db.exec("BEGIN");
137
+ try {
138
+ db.exec("DELETE FROM nodes");
139
+ db.exec("DELETE FROM edges");
140
+ const insertNode = db.prepare("INSERT OR REPLACE INTO nodes (id, kind, name, file_path, start_line, signature, docstring, is_exported) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
141
+ for (const n of nodes) {
142
+ const props = n.properties ?? {};
143
+ const exported = props.isExported === true || props.is_exported === 1 || props.is_exported === true;
144
+ insertNode.run(collapseRepeatedBackslashes(String(n.id)), n.type, n.label, collapseRepeatedBackslashes(n.filePath ?? ""), n.lineNumber ?? 0, typeof props.signature === "string" ? props.signature : null, typeof props.docstring === "string" ? props.docstring : null, exported ? 1 : 0);
145
+ }
146
+ const insertEdge = db.prepare("INSERT INTO edges (source, target, kind, metadata, line) VALUES (?, ?, ?, NULL, ?)");
147
+ for (const e of edges) {
148
+ const props = e.properties ?? {};
149
+ const line = typeof props.line === "number" && Number.isFinite(props.line) ? Math.round(props.line) : null;
150
+ insertEdge.run(collapseRepeatedBackslashes(String(e.source)), collapseRepeatedBackslashes(String(e.target)), e.type, line);
151
+ }
152
+ db.prepare("INSERT OR REPLACE INTO index_meta (workspace, fingerprint, node_count, edge_count, indexed_at, gitignore_present, gitignore_rules, ignored_entries) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run(workspacePath, fingerprint, nodes.length, edges.length, Date.now(), coverage.gitignorePresent ? 1 : 0, coverage.gitignoreRules, coverage.ignoredEntries);
153
+ db.exec("COMMIT");
154
+ log.info("native index written", {
155
+ workspacePath,
156
+ nodes: nodes.length,
157
+ edges: edges.length,
158
+ fingerprint: fingerprint.slice(0, 12)
159
+ });
160
+ return true;
161
+ } catch (inner) {
162
+ db.exec("ROLLBACK");
163
+ throw inner;
164
+ }
165
+ } catch (e) {
166
+ log.warn("native index write failed", { error: String(e) });
167
+ return false;
168
+ }
169
+ }
170
+ /** 读取某工作区的索引元数据(null = 未索引 / 读失败)。 */
171
+ function readNativeIndexMeta(workspacePath) {
172
+ let indexPath;
173
+ try {
174
+ indexPath = resolveNativeIndexPath(workspacePath);
175
+ } catch {
176
+ return null;
177
+ }
178
+ if (!existsSync(indexPath)) return null;
179
+ const db = getWriteDb(indexPath);
180
+ if (!db) return null;
181
+ try {
182
+ const row = db.prepare("SELECT fingerprint, node_count, edge_count, indexed_at FROM index_meta WHERE workspace = ?").get(workspacePath);
183
+ if (!row) return null;
184
+ return {
185
+ fingerprint: row.fingerprint,
186
+ nodeCount: row.node_count,
187
+ edgeCount: row.edge_count,
188
+ indexedAt: row.indexed_at
189
+ };
190
+ } catch (e) {
191
+ log.warn("native index meta read failed", { error: String(e) });
192
+ return null;
193
+ }
194
+ }
195
+ /**
196
+ * 读取某工作区的索引覆盖范围(null = 未索引 / 老库无列 / 读失败)。
197
+ *
198
+ * 老库的列是 `ALTER TABLE ... DEFAULT 0` 补出来的——读到 0/0/0 是「升级前索引」
199
+ * 的诚实值,不编造。管理面板据此渲染「索引覆盖范围」行。
200
+ */
201
+ function readNativeIndexCoverage(workspacePath) {
202
+ let indexPath;
203
+ try {
204
+ indexPath = resolveNativeIndexPath(workspacePath);
205
+ } catch {
206
+ return null;
207
+ }
208
+ if (!existsSync(indexPath)) return null;
209
+ const db = getWriteDb(indexPath);
210
+ if (!db) return null;
211
+ try {
212
+ const row = db.prepare("SELECT gitignore_present, gitignore_rules, ignored_entries, indexed_at FROM index_meta WHERE workspace = ?").get(workspacePath);
213
+ if (!row) return null;
214
+ return {
215
+ gitignorePresent: row.gitignore_present === 1,
216
+ gitignoreRules: row.gitignore_rules,
217
+ ignoredEntries: row.ignored_entries,
218
+ indexedAt: row.indexed_at
219
+ };
220
+ } catch (e) {
221
+ log.warn("native index coverage read failed", { error: String(e) });
222
+ return null;
223
+ }
224
+ }
225
+ /**
226
+ * 定向更新(cycle-129 · T3):把改动文件的旧行删除、新行写入——watcher 增量
227
+ * 路径的索引侧。与 writeNativeIndex 的「全量 DELETE+INSERT」相对,这里只触碰
228
+ * 改动文件的 nodes 行与**端点涉及这些节点**的 edges 行(增量读侧 readFilesFromDb
229
+ * 的对称操作)。
230
+ *
231
+ * @param changedFiles repo 相对路径(与 watcher 的 changedFiles 同域)。
232
+ * @returns 是否真的更新(false = 未索引过 / 无变化 / 失败)。
233
+ *
234
+ * 匹配语义与读侧 readFilesFromDb 一致:`file_path IN (改动文件)` 或
235
+ * `file_path LIKE '改动目录/%'`(目录级变更)。注意 file_path 列存的是
236
+ * GraphNode.filePath 原样(TreeSitter 产出为 repo 相对 posix 路径)。
237
+ */
238
+ function updateFilesForNativeIndex(workspacePath, changedFiles, newNodes, newEdges, newFingerprint) {
239
+ if (changedFiles.length === 0) return false;
240
+ let indexPath;
241
+ try {
242
+ indexPath = resolveNativeIndexPath(workspacePath);
243
+ } catch (e) {
244
+ log.warn("native index path rejected", { error: String(e) });
245
+ return false;
246
+ }
247
+ if (!existsSync(indexPath)) return false;
248
+ const db = getWriteDb(indexPath);
249
+ if (!db) return false;
250
+ try {
251
+ const wanted = new Set();
252
+ for (const raw of changedFiles) {
253
+ const normalized = raw.replace(/\\/g, "/");
254
+ if (!normalized) continue;
255
+ wanted.add(normalized);
256
+ }
257
+ if (wanted.size === 0) return false;
258
+ const placeholders = [...wanted].map(() => "?").join(",");
259
+ const prefixConds = [...wanted].map(() => "file_path LIKE ? ESCAPE '\\'").join(" OR ");
260
+ const prefixArgs = [...wanted].map((p) => `${p.replace(/[%_\\]/g, "\\$&")}/%`);
261
+ const staleNodes = db.prepare(`SELECT id FROM nodes WHERE file_path IN (${placeholders}) OR ${prefixConds}`).all(...wanted, ...prefixArgs);
262
+ if (staleNodes.length === 0) return false;
263
+ db.exec("BEGIN");
264
+ try {
265
+ const staleIds = staleNodes.map((r) => r.id);
266
+ for (let i = 0; i < staleIds.length; i += 500) {
267
+ const batch = staleIds.slice(i, i + 500);
268
+ const ph = batch.map(() => "?").join(",");
269
+ db.prepare(`DELETE FROM edges WHERE source IN (${ph}) OR target IN (${ph})`).run(...batch, ...batch);
270
+ }
271
+ for (let i = 0; i < staleIds.length; i += 500) {
272
+ const batch = staleIds.slice(i, i + 500);
273
+ const ph = batch.map(() => "?").join(",");
274
+ db.prepare(`DELETE FROM nodes WHERE id IN (${ph})`).run(...batch);
275
+ }
276
+ const insertNode = db.prepare("INSERT OR REPLACE INTO nodes (id, kind, name, file_path, start_line, signature, docstring, is_exported) VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
277
+ for (const n of newNodes) {
278
+ const props = n.properties ?? {};
279
+ const exported = props.isExported === true || props.is_exported === 1 || props.is_exported === true;
280
+ insertNode.run(String(n.id), n.type, n.label, n.filePath ?? "", n.lineNumber ?? 0, typeof props.signature === "string" ? props.signature : null, typeof props.docstring === "string" ? props.docstring : null, exported ? 1 : 0);
281
+ }
282
+ const insertEdge = db.prepare("INSERT INTO edges (source, target, kind, metadata, line) VALUES (?, ?, ?, NULL, ?)");
283
+ for (const e of newEdges) {
284
+ const props = e.properties ?? {};
285
+ const line = typeof props.line === "number" && Number.isFinite(props.line) ? Math.round(props.line) : null;
286
+ insertEdge.run(String(e.source), String(e.target), e.type, line);
287
+ }
288
+ const prev = db.prepare("SELECT node_count, edge_count FROM index_meta WHERE workspace = ?").get(workspacePath);
289
+ const removedEdges = db.prepare("SELECT changes() as c").get();
290
+ const counts = db.prepare("SELECT (SELECT COUNT(*) FROM nodes) as n, (SELECT COUNT(*) FROM edges) as e").get();
291
+ db.prepare("INSERT OR REPLACE INTO index_meta (workspace, fingerprint, node_count, edge_count, indexed_at) VALUES (?, ?, ?, ?, ?)").run(workspacePath, newFingerprint, counts.n, counts.e, Date.now());
292
+ db.exec("COMMIT");
293
+ log.info("native index updated (targeted)", {
294
+ workspacePath,
295
+ changedFiles: changedFiles.length,
296
+ staleNodes: staleIds.length,
297
+ newNodes: newNodes.length,
298
+ newEdges: newEdges.length
299
+ });
300
+ return true;
301
+ } catch (inner) {
302
+ db.exec("ROLLBACK");
303
+ throw inner;
304
+ }
305
+ } catch (e) {
306
+ log.warn("native index targeted update failed", { error: String(e) });
307
+ return false;
308
+ }
309
+ }
310
+ /**
311
+ * 删除原生索引(cycle-141 管理面板)。
312
+ *
313
+ * 删除索引 DB 文件本身(.codegraph-visualizer/native-index.db),
314
+ * 让下次构建重新生成。幂等:DB 不存在时返回 false 而非抛错。
315
+ *
316
+ * 注意:只删原生索引,不删上游 DB(.codegraph/codegraph.db)——
317
+ * 上游 DB 是 codegraph 工具的产物,由 codegraph 自己管理。
318
+ */
319
+ function deleteNativeIndex(workspacePath) {
320
+ let indexPath;
321
+ try {
322
+ indexPath = resolveNativeIndexPath(workspacePath);
323
+ } catch (e) {
324
+ log.warn("native index path rejected", { error: String(e) });
325
+ return false;
326
+ }
327
+ if (!existsSync(indexPath)) return false;
328
+ try {
329
+ const db = writePool.get(indexPath);
330
+ if (db) {
331
+ try {
332
+ db.close();
333
+ } catch {}
334
+ writePool.delete(indexPath);
335
+ }
336
+ rmSync(indexPath);
337
+ log.info("native index deleted", { indexPath });
338
+ return true;
339
+ } catch (e) {
340
+ log.warn("native index delete failed", { error: String(e) });
341
+ return false;
342
+ }
343
+ }
344
+
345
+ //#endregion
346
+ export { closeNativeIndexConnections, collapseRepeatedBackslashes, deleteNativeIndex, readNativeIndexCoverage, readNativeIndexMeta, resolveNativeIndexPath, updateFilesForNativeIndex, writeNativeIndex };
347
+ //# sourceMappingURL=nativeIndex-CABbgERW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nativeIndex-CABbgERW.js","names":["p: string","workspacePath: string","indexPath: string","fingerprint: string","nodes: readonly GraphNode[]","edges: readonly GraphEdge[]","coverage: IndexCoverage","changedFiles: readonly string[]","newNodes: readonly GraphNode[]","newEdges: readonly GraphEdge[]","newFingerprint: string"],"sources":["../src/adapters/nativeIndex.ts"],"sourcesContent":["/**\n * 原生 SQLite 索引写侧(cycle-128)。\n *\n * ## 设计决定:复用上游 schema\n *\n * 上游 dsh-codegraph 的读侧契约(src/adapters/codeGraphRows.ts)是:\n * nodes(id TEXT, kind TEXT, name TEXT, file_path TEXT, start_line INTEGER,\n * signature TEXT, docstring TEXT, is_exported INTEGER)\n * edges(source TEXT, target TEXT, kind TEXT, metadata TEXT, line INTEGER)\n *\n * 原生索引**逐列复用**这个 schema(DDL 见 NATIVE_MIGRATION_SQL)。收益:\n * 既有读侧函数(readGraphFromDbPaged / readTopLevelNodesFromDb /\n * readNodeChildrenFromDb / readFileOutlineFromDb / readSymbolASTFromDb /\n * readEdgesFromDb / readEdgesForNodesFromDb / readFilesFromDb)在原生库上\n * **零改动可用**——「实现兼容代码图谱」不是复制上游实现,而是共享数据契约。\n *\n * ## 与 GraphRepository 的关系\n *\n * GraphRepository(同目录 viz.db)存的是可视化产物(快照/分析/偏好),\n * 本模块存的是**索引本体**(图数据)。同库不同表,一次打开两用。\n *\n * ## 指纹去重\n *\n * `index_meta` 表记录每个 workspace 的 (fingerprint, node_count, edge_count,\n * indexed_at)。同一指纹重复扫描零写入(与 graph_snapshots 的去重语义一致)。\n * fingerprint 由调用方传入(computeGraphFingerprint 的结构指纹)——本模块\n * 不感知指纹算法。\n *\n * ## 失败语义(与 codeGraphDb.ts 一致)\n *\n * 所有写函数不抛出:失败 log.warn 并返回 false。索引写失败不阻塞图返回\n * (图来自内存 batchScan;索引只是缓存层)。\n */\nimport { existsSync, mkdirSync, rmSync } from 'node:fs';\nimport { join, normalize } from 'node:path';\nimport { createRequire } from 'node:module';\nimport { scoped } from '../shared/Logger.ts';\nimport type { GraphNode, GraphEdge } from '../types/index.ts';\n\nconst log = scoped('native-index');\n\nconst require = createRequire(import.meta.url);\n\ntype SqliteDb = {\n exec(sql: string): void;\n prepare(sql: string): {\n run(...params: unknown[]): { changes: number | bigint };\n all(...params: unknown[]): unknown[];\n get(...params: unknown[]): unknown;\n };\n close(): void;\n};\n\n/**\n * 原生索引 DDL——**逐列复用上游 schema**(见模块头注)。\n * `edges.id` 刻意不建主键:上游 edges 的 id 是 INTEGER 自增,而本插件的\n * GraphEdge.id 是字符串(`tsedge:` 前缀等)。为了「同列名同语义」,原生库的\n * edges 用与上游相同的列布局,但 source+target+kind 联合去重由写侧保证,\n * 自增 id 仅作行标识(读侧 EDGE_ROW_COLUMNS 会 SELECT id,上游行是数字自增、\n * 原生行也是数字自增——同型)。\n */\nconst NATIVE_MIGRATION_SQL = [\n `CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n kind TEXT NOT NULL,\n name TEXT NOT NULL,\n file_path TEXT NOT NULL DEFAULT '',\n start_line INTEGER NOT NULL DEFAULT 0,\n signature TEXT,\n docstring TEXT,\n is_exported INTEGER NOT NULL DEFAULT 0\n )`,\n `CREATE TABLE IF NOT EXISTS edges (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n source TEXT NOT NULL,\n target TEXT NOT NULL,\n kind TEXT NOT NULL,\n metadata TEXT,\n line INTEGER\n )`,\n `CREATE INDEX IF NOT EXISTS idx_native_nodes_kind ON nodes(kind)`,\n `CREATE INDEX IF NOT EXISTS idx_native_nodes_file ON nodes(file_path)`,\n `CREATE INDEX IF NOT EXISTS idx_native_edges_source ON edges(source)`,\n `CREATE INDEX IF NOT EXISTS idx_native_edges_target ON edges(target)`,\n `CREATE TABLE IF NOT EXISTS index_meta (\n workspace TEXT PRIMARY KEY,\n fingerprint TEXT NOT NULL,\n node_count INTEGER NOT NULL,\n edge_count INTEGER NOT NULL,\n indexed_at INTEGER NOT NULL,\n gitignore_present INTEGER NOT NULL DEFAULT 0,\n gitignore_rules INTEGER NOT NULL DEFAULT 0,\n ignored_entries INTEGER NOT NULL DEFAULT 0\n )`,\n] as const;\n\n/**\n * 老库升级 ALTER(cycle-141 第七轮):CREATE IF NOT EXISTS 不会给已存在的表补列。\n * **必须容错执行**——新库建表已含这些列,ALTER 会报 duplicate column;这条失败\n * 是幂等成功而不是错误。此前把 ALTER 混进 NATIVE_MIGRATION_SQL 让 getWriteDb 的\n * try/catch 整体失败 → 每次打开连接都返回 null → 全部写入静默失败(13 个用例\n * EPERM/0 行的现场)。\n */\nconst NATIVE_UPGRADE_SQL = [\n `ALTER TABLE index_meta ADD COLUMN gitignore_present INTEGER NOT NULL DEFAULT 0`,\n `ALTER TABLE index_meta ADD COLUMN gitignore_rules INTEGER NOT NULL DEFAULT 0`,\n `ALTER TABLE index_meta ADD COLUMN ignored_entries INTEGER NOT NULL DEFAULT 0`,\n] as const;\n\n/** 原生索引写连接(每工作区一个;与 codeGraphDb 的只读池隔离)。 */\nconst writePool = new Map<string, SqliteDb>();\n\n/**\n * 折叠路径中的重复反斜杠(cycle-141 第六轮)。\n *\n * ## 为什么不能只信调用方的转义形态\n *\n * workspace/repoId 沿 LLM 工具调用 / 宿主注册表传递时,JSON 转义层数不保证恒定:\n * 真机实证(dsh-anic index_meta 同分钟两条记录)——`D:\\Projects\\...`(单反斜杠,\n * 正常扫描链)与 `D:\\\\Projects\\\\...`(双反斜杠字面量,另一条调用链)先后写入。\n * Windows 文件 API 对重复分隔符宽容(readdir 双反斜杠路径照样成功),扫描不报错,\n * 但 **id/file_path 带毒入库**:此后按单反斜杠 id 查询(children/edges join)全部落空,\n * 客户端拿到的 bootstrap id 与后续按需请求的 nodeId 永远对不上。\n *\n * 这里刻意**不用** `path.normalize`:它会把 `/` 统一成 `\\`,破坏原生索引 id 的\n * 分隔符约定(FileSystemAdapter 用 `${dirPath}/${entry}` 拼,读侧 SQL 也按 `/`\n * 做噪音过滤)。只折叠 `\\\\` → `\\`,其余逐字保留。\n */\nexport function collapseRepeatedBackslashes(p: string): string {\n return p.replace(/\\\\{2,}/g, '\\\\');\n}\n\nexport function resolveNativeIndexPath(workspacePath: string): string {\n // 入口归一化(collapseRepeatedBackslashes):双重转义的 workspace 落到不同的\n // 磁盘目录(`.codegraph-visualizer` 挂在 `D:\\\\Projects` 字面目录下),同库两套\n // meta 的直接来源。折叠后单双反斜杠形态共享同一个索引文件。\n const root = collapseRepeatedBackslashes(workspacePath && workspacePath !== '.' ? workspacePath : process.cwd());\n // cycle-146 CI 修复:`..` 穿越检查必须在 **原始串** 上做,而不是 normalize 之后——\n // normalize 会消解 `..`(`D:/evil/../..` → `D:\\`),让 `normalized.includes('..')`\n // 永远落空,穿越检查退化成「依赖目标目录恰好不可写」的平台偶然性\n //(Windows 盘符根不可写 ⇒ false;Linux cwd 下可写 `D:` 目录 ⇒ 写穿)。语义不变:\n // 含 `..` 的 workspace 一律拒绝,无论它消解后指向哪里。\n if (root.includes('..') || normalize(root).includes('..')) {\n throw new Error(`Invalid workspace path: ${workspacePath}`);\n }\n const normalized = normalize(root);\n return join(normalized, '.codegraph-visualizer', 'native-index.db');\n}\n\nfunction getWriteDb(indexPath: string): SqliteDb | null {\n const existing = writePool.get(indexPath);\n if (existing) return existing;\n try {\n const { DatabaseSync } = require('node:sqlite') as typeof import('node:sqlite');\n mkdirSync(join(indexPath, '..'), { recursive: true });\n const db = new DatabaseSync(indexPath) as unknown as SqliteDb;\n for (const ddl of NATIVE_MIGRATION_SQL) db.exec(ddl);\n // 升级 ALTER 容错执行(duplicate column = 幂等成功,见 NATIVE_UPGRADE_SQL 头注)。\n for (const ddl of NATIVE_UPGRADE_SQL) {\n try { db.exec(ddl); } catch { /* 列已存在 */ }\n }\n writePool.set(indexPath, db);\n return db;\n } catch (e) {\n log.warn('native index open failed', { indexPath, error: String(e) });\n return null;\n }\n}\n\n/** 关闭全部写连接(dispose/测试清池;与 closeAllDbConnections 同型)。 */\nexport function closeNativeIndexConnections(): void {\n for (const db of writePool.values()) {\n try { db.close(); } catch { /* 已关闭 */ }\n }\n writePool.clear();\n}\n\n/**\n * 把原生批扫描的图数据写入索引(事务批量写 + 指纹去重)。\n *\n * @returns 是否真的写入(false = 同指纹已索引 / 打库失败 / 写失败)。\n * 上游行契约映射:\n * GraphNode → nodes 行:kind=node.type('function'|'class'|…,与上游 kind 词表\n * 同域——TreeSitter 的 SymbolKind 映射(TreeSitterAdapter.ts:119-186)产出的\n * 就是这四个值),is_exported 取 properties.isExported/is_exported 的布尔投影。\n * GraphEdge → edges 行:kind=edge.type('contains'|'extend'|…),line 取\n * properties.line(AST 行号),metadata 恒 null(原生通道无 confidence 数据,\n * 不编造——parseEdgeConfidence 的保守降级哲学)。\n */\n/** 索引覆盖范围统计(写侧随扫描沉淀,读侧供管理面板白盒区)。 */\nexport interface IndexCoverage {\n /** .gitignore 是否在场(false = 纯硬编码兜底)。 */\n gitignorePresent: boolean;\n /** .gitignore 规则数(0 = 缺席或空文件)。 */\n gitignoreRules: number;\n /** 本次扫描被排除的目录/文件总数。 */\n ignoredEntries: number;\n /** 索引时间(读侧填充;写侧参数不需要)。 */\n indexedAt?: number;\n}\n\nexport function writeNativeIndex(\n workspacePath: string,\n fingerprint: string,\n nodes: readonly GraphNode[],\n edges: readonly GraphEdge[],\n coverage: IndexCoverage = { gitignorePresent: false, gitignoreRules: 0, ignoredEntries: 0 },\n): boolean {\n let indexPath: string;\n try {\n // workspace 归一化(见 collapseRepeatedBackslashes 头注):写侧 id/file_path\n // 的毒源是 scanDir 的 repoId 起点带双反斜杠,这里在 meta 键与目录解析两处\n // 同时折叠——双形态工作区写进同一份 meta、同一个索引文件。\n workspacePath = collapseRepeatedBackslashes(workspacePath);\n indexPath = resolveNativeIndexPath(workspacePath);\n } catch (e) {\n log.warn('native index path rejected', { error: String(e) });\n return false;\n }\n const db = getWriteDb(indexPath);\n if (!db) return false;\n\n try {\n const meta = db.prepare('SELECT fingerprint, node_count, edge_count FROM index_meta WHERE workspace = ?').get(workspacePath) as\n | { fingerprint: string; node_count: number; edge_count: number }\n | undefined;\n if (meta && meta.fingerprint === fingerprint && meta.node_count === nodes.length && meta.edge_count === edges.length) {\n return false; // 同指纹同规模:零写入\n }\n\n db.exec('BEGIN');\n try {\n db.exec('DELETE FROM nodes');\n db.exec('DELETE FROM edges');\n const insertNode = db.prepare(\n 'INSERT OR REPLACE INTO nodes (id, kind, name, file_path, start_line, signature, docstring, is_exported) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',\n );\n for (const n of nodes) {\n const props = (n.properties ?? {}) as Record<string, unknown>;\n const exported = props.isExported === true || props.is_exported === 1 || props.is_exported === true;\n // id 与 filePath 同步折叠:scanDir 从带毒 repoId 起遍历时,每个 dir:/file:\n // id 与 file_path 都继承了双重转义——写库前统一消毒,读侧单反斜杠查询才能命中。\n insertNode.run(\n collapseRepeatedBackslashes(String(n.id)),\n n.type,\n n.label,\n collapseRepeatedBackslashes(n.filePath ?? ''),\n n.lineNumber ?? 0,\n typeof props.signature === 'string' ? props.signature : null,\n typeof props.docstring === 'string' ? props.docstring : null,\n exported ? 1 : 0,\n );\n }\n const insertEdge = db.prepare(\n 'INSERT INTO edges (source, target, kind, metadata, line) VALUES (?, ?, ?, NULL, ?)',\n );\n for (const e of edges) {\n const props = (e.properties ?? {}) as Record<string, unknown>;\n const line = typeof props.line === 'number' && Number.isFinite(props.line) ? Math.round(props.line) : null;\n // contains/import/call 边的两端同样继承带毒 id——不消毒则 dir: 分支的\n // contains-join 与 edges join 全部落空。\n insertEdge.run(collapseRepeatedBackslashes(String(e.source)), collapseRepeatedBackslashes(String(e.target)), e.type, line);\n }\n db.prepare(\n 'INSERT OR REPLACE INTO index_meta (workspace, fingerprint, node_count, edge_count, indexed_at, gitignore_present, gitignore_rules, ignored_entries) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',\n ).run(\n workspacePath,\n fingerprint,\n nodes.length,\n edges.length,\n Date.now(),\n coverage.gitignorePresent ? 1 : 0,\n coverage.gitignoreRules,\n coverage.ignoredEntries,\n );\n db.exec('COMMIT');\n log.info('native index written', { workspacePath, nodes: nodes.length, edges: edges.length, fingerprint: fingerprint.slice(0, 12) });\n return true;\n } catch (inner) {\n db.exec('ROLLBACK');\n throw inner;\n }\n } catch (e) {\n log.warn('native index write failed', { error: String(e) });\n return false;\n }\n}\n\n/** 读取某工作区的索引元数据(null = 未索引 / 读失败)。 */\nexport function readNativeIndexMeta(workspacePath: string): { fingerprint: string; nodeCount: number; edgeCount: number; indexedAt: number } | null {\n let indexPath: string;\n try {\n indexPath = resolveNativeIndexPath(workspacePath);\n } catch {\n return null;\n }\n if (!existsSync(indexPath)) return null;\n const db = getWriteDb(indexPath);\n if (!db) return null;\n try {\n const row = db.prepare('SELECT fingerprint, node_count, edge_count, indexed_at FROM index_meta WHERE workspace = ?').get(workspacePath) as\n | { fingerprint: string; node_count: number; edge_count: number; indexed_at: number }\n | undefined;\n if (!row) return null;\n return { fingerprint: row.fingerprint, nodeCount: row.node_count, edgeCount: row.edge_count, indexedAt: row.indexed_at };\n } catch (e) {\n log.warn('native index meta read failed', { error: String(e) });\n return null;\n }\n}\n\n/**\n * 读取某工作区的索引覆盖范围(null = 未索引 / 老库无列 / 读失败)。\n *\n * 老库的列是 `ALTER TABLE ... DEFAULT 0` 补出来的——读到 0/0/0 是「升级前索引」\n * 的诚实值,不编造。管理面板据此渲染「索引覆盖范围」行。\n */\nexport function readNativeIndexCoverage(workspacePath: string): IndexCoverage | null {\n let indexPath: string;\n try {\n indexPath = resolveNativeIndexPath(workspacePath);\n } catch {\n return null;\n }\n if (!existsSync(indexPath)) return null;\n const db = getWriteDb(indexPath);\n if (!db) return null;\n try {\n const row = db.prepare('SELECT gitignore_present, gitignore_rules, ignored_entries, indexed_at FROM index_meta WHERE workspace = ?').get(workspacePath) as\n | { gitignore_present: number; gitignore_rules: number; ignored_entries: number; indexed_at: number }\n | undefined;\n if (!row) return null;\n return {\n gitignorePresent: row.gitignore_present === 1,\n gitignoreRules: row.gitignore_rules,\n ignoredEntries: row.ignored_entries,\n indexedAt: row.indexed_at,\n };\n } catch (e) {\n log.warn('native index coverage read failed', { error: String(e) });\n return null;\n }\n}\n\n/**\n * 定向更新(cycle-129 · T3):把改动文件的旧行删除、新行写入——watcher 增量\n * 路径的索引侧。与 writeNativeIndex 的「全量 DELETE+INSERT」相对,这里只触碰\n * 改动文件的 nodes 行与**端点涉及这些节点**的 edges 行(增量读侧 readFilesFromDb\n * 的对称操作)。\n *\n * @param changedFiles repo 相对路径(与 watcher 的 changedFiles 同域)。\n * @returns 是否真的更新(false = 未索引过 / 无变化 / 失败)。\n *\n * 匹配语义与读侧 readFilesFromDb 一致:`file_path IN (改动文件)` 或\n * `file_path LIKE '改动目录/%'`(目录级变更)。注意 file_path 列存的是\n * GraphNode.filePath 原样(TreeSitter 产出为 repo 相对 posix 路径)。\n */\nexport function updateFilesForNativeIndex(\n workspacePath: string,\n changedFiles: readonly string[],\n newNodes: readonly GraphNode[],\n newEdges: readonly GraphEdge[],\n newFingerprint: string,\n): boolean {\n if (changedFiles.length === 0) return false;\n let indexPath: string;\n try {\n indexPath = resolveNativeIndexPath(workspacePath);\n } catch (e) {\n log.warn('native index path rejected', { error: String(e) });\n return false;\n }\n if (!existsSync(indexPath)) return false; // 未索引过:让调用方走全量回写\n const db = getWriteDb(indexPath);\n if (!db) return false;\n\n try {\n // 改动文件的规整集合(与 readFilesFromDb 同域:posix 保留 + 反斜杠变体)。\n const wanted = new Set<string>();\n for (const raw of changedFiles) {\n const normalized = raw.replace(/\\\\/g, '/');\n if (!normalized) continue;\n wanted.add(normalized);\n }\n if (wanted.size === 0) return false;\n\n // ① 找出改动文件涉及的**旧节点 id**(含目录前缀命中——目录变更时其下文件\n // 的符号节点 file_path 以目录为前缀,但节点自身的 file_path 是文件路径;\n // 这里按节点 file_path 精确匹配 + 目录前缀两层都要删)。\n const placeholders = [...wanted].map(() => '?').join(',');\n const prefixConds = [...wanted].map(() => \"file_path LIKE ? ESCAPE '\\\\'\").join(' OR ');\n const prefixArgs = [...wanted].map((p) => `${p.replace(/[%_\\\\]/g, '\\\\$&')}/%`);\n const staleNodes = db.prepare(\n `SELECT id FROM nodes WHERE file_path IN (${placeholders}) OR ${prefixConds}`,\n ).all(...wanted, ...prefixArgs) as Array<{ id: string }>;\n if (staleNodes.length === 0) return false;\n\n db.exec('BEGIN');\n try {\n // ② 删除旧边(端点涉及任一旧节点 id)。\n const staleIds = staleNodes.map((r) => r.id);\n for (let i = 0; i < staleIds.length; i += 500) {\n const batch = staleIds.slice(i, i + 500);\n const ph = batch.map(() => '?').join(',');\n db.prepare(`DELETE FROM edges WHERE source IN (${ph}) OR target IN (${ph})`).run(...batch, ...batch);\n }\n // ③ 删除旧节点。\n for (let i = 0; i < staleIds.length; i += 500) {\n const batch = staleIds.slice(i, i + 500);\n const ph = batch.map(() => '?').join(',');\n db.prepare(`DELETE FROM nodes WHERE id IN (${ph})`).run(...batch);\n }\n // ④ 写入新节点/新边(与 writeNativeIndex 同映射)。\n const insertNode = db.prepare(\n 'INSERT OR REPLACE INTO nodes (id, kind, name, file_path, start_line, signature, docstring, is_exported) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',\n );\n for (const n of newNodes) {\n const props = (n.properties ?? {}) as Record<string, unknown>;\n const exported = props.isExported === true || props.is_exported === 1 || props.is_exported === true;\n insertNode.run(\n String(n.id), n.type, n.label, n.filePath ?? '', n.lineNumber ?? 0,\n typeof props.signature === 'string' ? props.signature : null,\n typeof props.docstring === 'string' ? props.docstring : null,\n exported ? 1 : 0,\n );\n }\n const insertEdge = db.prepare(\n 'INSERT INTO edges (source, target, kind, metadata, line) VALUES (?, ?, ?, NULL, ?)',\n );\n for (const e of newEdges) {\n const props = (e.properties ?? {}) as Record<string, unknown>;\n const line = typeof props.line === 'number' && Number.isFinite(props.line) ? Math.round(props.line) : null;\n insertEdge.run(String(e.source), String(e.target), e.type, line);\n }\n // ⑤ meta 前移(规模重算:旧规模 − 旧节点数 + 新节点数;指纹由调用方给)。\n const prev = db.prepare('SELECT node_count, edge_count FROM index_meta WHERE workspace = ?').get(workspacePath) as\n | { node_count: number; edge_count: number } | undefined;\n const removedEdges = db.prepare(\n 'SELECT changes() as c',\n ).get() as { c: number } | undefined;\n void removedEdges;\n const counts = db.prepare('SELECT (SELECT COUNT(*) FROM nodes) as n, (SELECT COUNT(*) FROM edges) as e').get() as { n: number; e: number };\n db.prepare(\n 'INSERT OR REPLACE INTO index_meta (workspace, fingerprint, node_count, edge_count, indexed_at) VALUES (?, ?, ?, ?, ?)',\n ).run(workspacePath, newFingerprint, counts.n, counts.e, Date.now());\n void prev;\n db.exec('COMMIT');\n log.info('native index updated (targeted)', { workspacePath, changedFiles: changedFiles.length, staleNodes: staleIds.length, newNodes: newNodes.length, newEdges: newEdges.length });\n return true;\n } catch (inner) {\n db.exec('ROLLBACK');\n throw inner;\n }\n } catch (e) {\n log.warn('native index targeted update failed', { error: String(e) });\n return false;\n }\n}\n\n/**\n * 删除原生索引(cycle-141 管理面板)。\n *\n * 删除索引 DB 文件本身(.codegraph-visualizer/native-index.db),\n * 让下次构建重新生成。幂等:DB 不存在时返回 false 而非抛错。\n *\n * 注意:只删原生索引,不删上游 DB(.codegraph/codegraph.db)——\n * 上游 DB 是 codegraph 工具的产物,由 codegraph 自己管理。\n */\nexport function deleteNativeIndex(workspacePath: string): boolean {\n let indexPath: string;\n try {\n indexPath = resolveNativeIndexPath(workspacePath);\n } catch (e) {\n log.warn('native index path rejected', { error: String(e) });\n return false;\n }\n if (!existsSync(indexPath)) return false;\n try {\n // 先关闭写连接(如果池里有),再删文件。\n const db = writePool.get(indexPath);\n if (db) {\n try { db.close(); } catch { /* 已关闭 */ }\n writePool.delete(indexPath);\n }\n rmSync(indexPath);\n log.info('native index deleted', { indexPath });\n return true;\n } catch (e) {\n log.warn('native index delete failed', { error: String(e) });\n return false;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import "./constants-CQq93l3e.js";
2
+ import "./Logger-DUIJSeNu.js";
3
+ import { closeNativeIndexConnections, collapseRepeatedBackslashes, deleteNativeIndex, readNativeIndexCoverage, readNativeIndexMeta, resolveNativeIndexPath, updateFilesForNativeIndex, writeNativeIndex } from "./nativeIndex-CABbgERW.js";
4
+
5
+ export { closeNativeIndexConnections, collapseRepeatedBackslashes, deleteNativeIndex, readNativeIndexCoverage, readNativeIndexMeta, resolveNativeIndexPath, updateFilesForNativeIndex, writeNativeIndex };