@openez-graph/cli 1.3.0 → 1.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.
- package/dist/CHANGELOG.md +9 -0
- package/dist/cli.cjs +38 -15
- package/package.json +1 -1
package/dist/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to OpenEZ Graph are documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.1] - 2026-08-16
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **Reindex and DB open performance on large workspaces** — `openez status` and `openez reindex` on a 92K-chunk workspace (e.g. Zed) went from >8 minutes (100% CPU, never completing) to ~0.15s (status) and ~25s (reindex). Two root causes fixed:
|
|
13
|
+
- **FTS repair scan on every DB open** — `initializeWorkspaceSchema` ran an O(n²) `LEFT JOIN chunks_fts` (chunk_id is UNINDEXED in FTS5) plus an orphan-cleanup `DELETE ... NOT IN` on every open, even when FTS was fully in sync. Now skips the expensive repair when a count + shape check confirms FTS is in sync, and only runs the full repair when counts diverge or orphaned rows are detected.
|
|
14
|
+
- **FTS trigger storm during full reindex** — `resetIndexArtifacts` deleted 92K chunks with FTS triggers active, firing 92K triggered `DELETE FROM chunks_fts WHERE chunk_id = old.id` (each a full FTS shadow-table scan). Now drops FTS triggers and the FTS table before deleting chunks, then recreates an empty FTS table for the reindex to populate via `bulkInsertFts`.
|
|
15
|
+
|
|
8
16
|
## [1.3.0] - 2026-08-15
|
|
9
17
|
|
|
10
18
|
### Added
|
|
@@ -299,6 +307,7 @@ Remediation release — index/graph correctness, data protection, and web flow f
|
|
|
299
307
|
- Error handling and validation for import path extraction
|
|
300
308
|
- CLI npm packaging
|
|
301
309
|
|
|
310
|
+
[1.3.1]: https://github.com/asta-nguyen/openez-graph/compare/v1.3.0...v1.3.1
|
|
302
311
|
[1.2.0]: https://github.com/asta-nguyen/openez-graph/compare/v1.1.0...v1.2.0
|
|
303
312
|
[1.3.0]: https://github.com/asta-nguyen/openez-graph/compare/v1.2.0...v1.3.0
|
|
304
313
|
[1.1.0]: https://github.com/asta-nguyen/openez-graph/compare/v1.0.3...v1.1.0
|
package/dist/cli.cjs
CHANGED
|
@@ -11910,6 +11910,13 @@ function createFtsOps(native, stmts, deps) {
|
|
|
11910
11910
|
},
|
|
11911
11911
|
// ── Reset ──
|
|
11912
11912
|
resetIndexArtifacts() {
|
|
11913
|
+
native.exec("DROP TRIGGER IF EXISTS chunks_fts_insert");
|
|
11914
|
+
native.exec("DROP TRIGGER IF EXISTS chunks_fts_delete");
|
|
11915
|
+
native.exec("DROP TRIGGER IF EXISTS chunks_fts_update");
|
|
11916
|
+
native.exec("DROP TABLE IF EXISTS chunks_fts");
|
|
11917
|
+
native.exec(
|
|
11918
|
+
"CREATE VIRTUAL TABLE chunks_fts USING fts5(chunk_id UNINDEXED, path, heading, language, search_text, tokenize = 'unicode61')"
|
|
11919
|
+
);
|
|
11913
11920
|
native.exec("DELETE FROM graph_edges");
|
|
11914
11921
|
native.exec("DELETE FROM graph_nodes");
|
|
11915
11922
|
native.exec("DELETE FROM chunks");
|
|
@@ -12114,20 +12121,36 @@ function initializeWorkspaceSchema(sqlite) {
|
|
|
12114
12121
|
INNER JOIN documents d ON d.id = c.document_id;
|
|
12115
12122
|
`);
|
|
12116
12123
|
} else {
|
|
12117
|
-
sqlite.
|
|
12118
|
-
|
|
12119
|
-
|
|
12120
|
-
|
|
12121
|
-
|
|
12122
|
-
|
|
12123
|
-
|
|
12124
|
-
|
|
12125
|
-
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12124
|
+
const chunkCount = sqlite.prepare("SELECT count(*) as c FROM chunks").get().c;
|
|
12125
|
+
const ftsCount = sqlite.prepare("SELECT count(*) as c FROM chunks_fts").get().c;
|
|
12126
|
+
let ftsInSync = chunkCount === ftsCount;
|
|
12127
|
+
if (ftsInSync) {
|
|
12128
|
+
const ftsShape = sqlite.prepare(
|
|
12129
|
+
`
|
|
12130
|
+
SELECT count(DISTINCT f.chunk_id) AS distinct_count,
|
|
12131
|
+
count(*) - count(c.id) AS orphan_count
|
|
12132
|
+
FROM chunks_fts f
|
|
12133
|
+
LEFT JOIN chunks c ON c.id = f.chunk_id
|
|
12134
|
+
`
|
|
12135
|
+
).get();
|
|
12136
|
+
ftsInSync = ftsShape.distinct_count === chunkCount && ftsShape.orphan_count === 0;
|
|
12137
|
+
}
|
|
12138
|
+
if (!ftsInSync) {
|
|
12139
|
+
sqlite.exec(`
|
|
12140
|
+
INSERT INTO chunks_fts (chunk_id, path, heading, language, search_text)
|
|
12141
|
+
SELECT c.id, d.path, coalesce(c.heading, ''),
|
|
12142
|
+
coalesce(d.language, ''),
|
|
12143
|
+
${composeFtsSearchTextSql("c.metadata", "c.content")}
|
|
12144
|
+
FROM chunks c
|
|
12145
|
+
INNER JOIN documents d ON d.id = c.document_id
|
|
12146
|
+
LEFT JOIN chunks_fts f ON f.chunk_id = c.id
|
|
12147
|
+
WHERE f.chunk_id IS NULL;
|
|
12148
|
+
`);
|
|
12149
|
+
sqlite.exec(`
|
|
12150
|
+
DELETE FROM chunks_fts
|
|
12151
|
+
WHERE chunk_id NOT IN (SELECT id FROM chunks);
|
|
12152
|
+
`);
|
|
12153
|
+
}
|
|
12131
12154
|
}
|
|
12132
12155
|
const hasTypeLabelIdx = sqlite.prepare(
|
|
12133
12156
|
"SELECT count(*) as c FROM sqlite_master WHERE type='index' AND name='idx_graph_nodes_type_label'"
|
|
@@ -60267,7 +60290,7 @@ __export(mcp_bridge_exports, {
|
|
|
60267
60290
|
startMcpServer: () => startMcpServer
|
|
60268
60291
|
});
|
|
60269
60292
|
async function startMcpServer(defaultPath, version4) {
|
|
60270
|
-
await createAndStartMcpServer({ defaultPath, version: version4, build: "
|
|
60293
|
+
await createAndStartMcpServer({ defaultPath, version: version4, build: "5060798-dirty" });
|
|
60271
60294
|
}
|
|
60272
60295
|
var init_mcp_bridge = __esm({
|
|
60273
60296
|
"src/mcp-bridge.ts"() {
|
package/package.json
CHANGED