context-mode 1.0.79 → 1.0.80
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/build/store.js +28 -10
- package/cli.bundle.mjs +78 -78
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +56 -56
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
8
|
"description": "Claude Code plugins by Mert Koseoğlu",
|
|
9
|
-
"version": "1.0.
|
|
9
|
+
"version": "1.0.80"
|
|
10
10
|
},
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "context-mode",
|
|
14
14
|
"source": "./",
|
|
15
15
|
"description": "Claude Code MCP plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
16
|
-
"version": "1.0.
|
|
16
|
+
"version": "1.0.80",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Mert Koseoğlu"
|
|
19
19
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.80",
|
|
4
4
|
"description": "MCP server that saves 98% of your context window with session continuity. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and automatic state restore across compactions.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "Context Mode",
|
|
4
4
|
"kind": "tool",
|
|
5
5
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.80",
|
|
7
7
|
"sandbox": {
|
|
8
8
|
"mode": "permissive",
|
|
9
9
|
"filesystem_access": "full",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.80",
|
|
4
4
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
package/build/store.js
CHANGED
|
@@ -41,7 +41,12 @@ function sanitizeQuery(query, mode = "AND") {
|
|
|
41
41
|
!["AND", "OR", "NOT", "NEAR"].includes(w.toUpperCase()));
|
|
42
42
|
if (words.length === 0)
|
|
43
43
|
return '""';
|
|
44
|
-
|
|
44
|
+
// Filter stopwords to improve BM25 ranking — common terms like "update",
|
|
45
|
+
// "test", "fix" appear everywhere and dilute relevance scoring.
|
|
46
|
+
// Fall back to unfiltered words if ALL terms are stopwords.
|
|
47
|
+
const meaningful = words.filter((w) => !STOPWORDS.has(w.toLowerCase()));
|
|
48
|
+
const final = meaningful.length > 0 ? meaningful : words;
|
|
49
|
+
return final.map((w) => `"${w}"`).join(mode === "OR" ? " OR " : " ");
|
|
45
50
|
}
|
|
46
51
|
function sanitizeTrigramQuery(query, mode = "AND") {
|
|
47
52
|
const cleaned = query.replace(/["'(){}[\]*:^~]/g, "").trim();
|
|
@@ -50,7 +55,9 @@ function sanitizeTrigramQuery(query, mode = "AND") {
|
|
|
50
55
|
const words = cleaned.split(/\s+/).filter((w) => w.length >= 3);
|
|
51
56
|
if (words.length === 0)
|
|
52
57
|
return "";
|
|
53
|
-
|
|
58
|
+
const meaningful = words.filter((w) => !STOPWORDS.has(w.toLowerCase()));
|
|
59
|
+
const final = meaningful.length > 0 ? meaningful : words;
|
|
60
|
+
return final.map((w) => `"${w}"`).join(mode === "OR" ? " OR " : " ");
|
|
54
61
|
}
|
|
55
62
|
function levenshtein(a, b) {
|
|
56
63
|
if (a.length === 0)
|
|
@@ -264,6 +271,10 @@ export class ContentStore {
|
|
|
264
271
|
#stmtChunkContent;
|
|
265
272
|
#stmtStats;
|
|
266
273
|
#stmtSourceMeta;
|
|
274
|
+
// Cleanup path
|
|
275
|
+
#stmtCleanupChunks;
|
|
276
|
+
#stmtCleanupChunksTrigram;
|
|
277
|
+
#stmtCleanupSources;
|
|
267
278
|
// FTS5 optimization: track inserts and optimize periodically to defragment
|
|
268
279
|
// the index. FTS5 b-trees fragment over many insert/delete cycles, degrading
|
|
269
280
|
// search performance. SQLite's built-in 'optimize' merges b-tree segments.
|
|
@@ -547,6 +558,10 @@ export class ContentStore {
|
|
|
547
558
|
(SELECT COUNT(*) FROM chunks) AS chunks,
|
|
548
559
|
(SELECT COUNT(*) FROM chunks WHERE content_type = 'code') AS codeChunks
|
|
549
560
|
`);
|
|
561
|
+
// Cleanup path — cached to avoid recompiling SQL on each periodic call
|
|
562
|
+
this.#stmtCleanupChunks = this.#db.prepare("DELETE FROM chunks WHERE source_id IN (SELECT id FROM sources WHERE datetime(indexed_at) < datetime('now', '-' || ? || ' days'))");
|
|
563
|
+
this.#stmtCleanupChunksTrigram = this.#db.prepare("DELETE FROM chunks_trigram WHERE source_id IN (SELECT id FROM sources WHERE datetime(indexed_at) < datetime('now', '-' || ? || ' days'))");
|
|
564
|
+
this.#stmtCleanupSources = this.#db.prepare("DELETE FROM sources WHERE datetime(indexed_at) < datetime('now', '-' || ? || ' days')");
|
|
550
565
|
}
|
|
551
566
|
// ── Index ──
|
|
552
567
|
index(options) {
|
|
@@ -768,10 +783,14 @@ export class ContentStore {
|
|
|
768
783
|
}
|
|
769
784
|
// ── Proximity Reranking ──
|
|
770
785
|
#applyProximityReranking(results, query) {
|
|
771
|
-
const
|
|
786
|
+
const allTerms = query
|
|
772
787
|
.toLowerCase()
|
|
773
788
|
.split(/\s+/)
|
|
774
789
|
.filter((w) => w.length >= 2);
|
|
790
|
+
// Exclude stopwords from proximity/title scoring — they match everywhere
|
|
791
|
+
// and inflate boosts for irrelevant chunks. Keep all terms as fallback.
|
|
792
|
+
const filtered = allTerms.filter((w) => !STOPWORDS.has(w));
|
|
793
|
+
const terms = filtered.length > 0 ? filtered : allTerms;
|
|
775
794
|
return results
|
|
776
795
|
.map((r) => {
|
|
777
796
|
// Title-match boost: query terms found in the chunk title get a boost.
|
|
@@ -806,11 +825,13 @@ export class ContentStore {
|
|
|
806
825
|
return reranked.map((r) => ({ ...r, matchLayer: "rrf" }));
|
|
807
826
|
}
|
|
808
827
|
// Step 2: Fuzzy correction → RRF re-run
|
|
828
|
+
// Skip stopwords — they'll be filtered by sanitizeQuery anyway, and each
|
|
829
|
+
// fuzzyCorrect call hits the vocab DB + runs levenshtein comparisons.
|
|
809
830
|
const words = query
|
|
810
831
|
.toLowerCase()
|
|
811
832
|
.trim()
|
|
812
833
|
.split(/\s+/)
|
|
813
|
-
.filter((w) => w.length >= 3);
|
|
834
|
+
.filter((w) => w.length >= 3 && !STOPWORDS.has(w));
|
|
814
835
|
const original = words.join(" ");
|
|
815
836
|
const correctedWords = words.map((w) => this.fuzzyCorrect(w) ?? w);
|
|
816
837
|
const correctedQuery = correctedWords.join(" ");
|
|
@@ -898,13 +919,10 @@ export class ContentStore {
|
|
|
898
919
|
* Returns count of deleted sources.
|
|
899
920
|
*/
|
|
900
921
|
cleanupStaleSources(maxAgeDays) {
|
|
901
|
-
const deleteChunks = this.#db.prepare("DELETE FROM chunks WHERE source_id IN (SELECT id FROM sources WHERE datetime(indexed_at) < datetime('now', '-' || ? || ' days'))");
|
|
902
|
-
const deleteChunksTrigram = this.#db.prepare("DELETE FROM chunks_trigram WHERE source_id IN (SELECT id FROM sources WHERE datetime(indexed_at) < datetime('now', '-' || ? || ' days'))");
|
|
903
|
-
const deleteSources = this.#db.prepare("DELETE FROM sources WHERE datetime(indexed_at) < datetime('now', '-' || ? || ' days')");
|
|
904
922
|
const cleanup = this.#db.transaction((days) => {
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
return
|
|
923
|
+
this.#stmtCleanupChunks.run(days);
|
|
924
|
+
this.#stmtCleanupChunksTrigram.run(days);
|
|
925
|
+
return this.#stmtCleanupSources.run(days);
|
|
908
926
|
});
|
|
909
927
|
const info = cleanup(maxAgeDays);
|
|
910
928
|
return info.changes;
|