context-mode 1.0.30 → 1.0.33
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/server.js +19 -39
- package/cli.bundle.mjs +92 -92
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +67 -67
|
@@ -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.33"
|
|
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.33",
|
|
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.33",
|
|
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.33",
|
|
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.33",
|
|
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/server.js
CHANGED
|
@@ -88,48 +88,11 @@ function getStorePath() {
|
|
|
88
88
|
mkdirSync(dir, { recursive: true });
|
|
89
89
|
return join(dir, `${hash}.db`);
|
|
90
90
|
}
|
|
91
|
-
/**
|
|
92
|
-
* Detect fresh vs --continue session.
|
|
93
|
-
* SessionStart hook writes {hash}.cleanup on "startup", deletes it on "resume".
|
|
94
|
-
* Flag exists → fresh start → delete old store. Flag missing → continue → keep store.
|
|
95
|
-
* Uses same hash as getStorePath() so they stay in sync.
|
|
96
|
-
*/
|
|
97
|
-
function isFreshStart() {
|
|
98
|
-
try {
|
|
99
|
-
const projectDir = process.env.CLAUDE_PROJECT_DIR
|
|
100
|
-
|| process.env.GEMINI_PROJECT_DIR
|
|
101
|
-
|| process.env.OPENCLAW_PROJECT_DIR
|
|
102
|
-
|| process.cwd();
|
|
103
|
-
const normalized = projectDir.replace(/\\/g, "/");
|
|
104
|
-
const hash = createHash("sha256").update(normalized).digest("hex").slice(0, 16);
|
|
105
|
-
// Check all platform config dirs for cleanup flag
|
|
106
|
-
const configDirs = [".claude", ".gemini", ".cursor", ".kiro", ".config/opencode", ".openclaw"];
|
|
107
|
-
for (const configDir of configDirs) {
|
|
108
|
-
const sessionsDir = join(homedir(), configDir, "context-mode", "sessions");
|
|
109
|
-
// Check with and without worktree suffix
|
|
110
|
-
const files = existsSync(sessionsDir) ? readdirSync(sessionsDir) : [];
|
|
111
|
-
if (files.some(f => f.startsWith(hash) && f.endsWith(".cleanup"))) {
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
catch {
|
|
118
|
-
return false; // default: persist (safer than deleting)
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
91
|
function getStore() {
|
|
122
92
|
if (!_store) {
|
|
93
|
+
// Content DB cleanup on fresh start is handled by SessionStart hook.
|
|
94
|
+
// Server just opens whatever DB exists (or creates new if hook deleted it).
|
|
123
95
|
const dbPath = getStorePath();
|
|
124
|
-
// Fresh session: delete old store DB for clean slate
|
|
125
|
-
if (isFreshStart()) {
|
|
126
|
-
for (const suffix of ["", "-wal", "-shm"]) {
|
|
127
|
-
try {
|
|
128
|
-
unlinkSync(dbPath + suffix);
|
|
129
|
-
}
|
|
130
|
-
catch { /* may not exist */ }
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
96
|
_store = new ContentStore(dbPath);
|
|
134
97
|
// One-time startup cleanup: remove stale content DBs (>14 days)
|
|
135
98
|
try {
|
|
@@ -152,6 +115,8 @@ const sessionStats = {
|
|
|
152
115
|
bytesReturned: {},
|
|
153
116
|
bytesIndexed: 0,
|
|
154
117
|
bytesSandboxed: 0, // network I/O consumed inside sandbox (never enters context)
|
|
118
|
+
cacheHits: 0,
|
|
119
|
+
cacheBytesSaved: 0, // bytes avoided by TTL cache hits
|
|
155
120
|
sessionStart: Date.now(),
|
|
156
121
|
};
|
|
157
122
|
function trackResponse(toolName, response) {
|
|
@@ -1062,6 +1027,10 @@ server.registerTool("ctx_fetch_and_index", {
|
|
|
1062
1027
|
const ageHours = Math.floor(ageMs / (60 * 60 * 1000));
|
|
1063
1028
|
const ageMin = Math.floor(ageMs / (60 * 1000));
|
|
1064
1029
|
const ageStr = ageHours > 0 ? `${ageHours}h ago` : ageMin > 0 ? `${ageMin}m ago` : "just now";
|
|
1030
|
+
// Track cache savings — estimate ~1.6KB per chunk (average indexed content size)
|
|
1031
|
+
const estimatedBytes = meta.chunkCount * 1600;
|
|
1032
|
+
sessionStats.cacheHits++;
|
|
1033
|
+
sessionStats.cacheBytesSaved += estimatedBytes;
|
|
1065
1034
|
return trackResponse("ctx_fetch_and_index", {
|
|
1066
1035
|
content: [{
|
|
1067
1036
|
type: "text",
|
|
@@ -1403,6 +1372,17 @@ server.registerTool("ctx_stats", {
|
|
|
1403
1372
|
if (keptOut > 0) {
|
|
1404
1373
|
lines.push("", `Without context-mode, **${kb(totalProcessed)}** of raw output would flood your context window. Instead, **${reductionPct}%** stayed in sandbox.`);
|
|
1405
1374
|
}
|
|
1375
|
+
// Cache savings section
|
|
1376
|
+
if (sessionStats.cacheHits > 0 || sessionStats.cacheBytesSaved > 0) {
|
|
1377
|
+
const totalWithCache = totalProcessed + sessionStats.cacheBytesSaved;
|
|
1378
|
+
const totalSavingsRatio = totalWithCache / Math.max(totalBytesReturned, 1);
|
|
1379
|
+
const ttlHoursLeft = Math.max(0, 24 - Math.floor((Date.now() - sessionStats.sessionStart) / (60 * 60 * 1000)));
|
|
1380
|
+
lines.push("", `### TTL Cache`, "", `| Metric | Value |`, `|--------|------:|`, `| Cache hits | **${sessionStats.cacheHits}** |`, `| Data avoided by cache | **${kb(sessionStats.cacheBytesSaved)}** |`, `| Network requests saved | **${sessionStats.cacheHits}** |`, `| TTL remaining | **~${ttlHoursLeft}h** |`, "", `Content was already indexed in the knowledge base — ${sessionStats.cacheHits} fetch${sessionStats.cacheHits > 1 ? "es" : ""} skipped entirely. **${kb(sessionStats.cacheBytesSaved)}** of network I/O avoided. Search results served directly from local FTS5 index.`);
|
|
1381
|
+
// Update total savings to include cache
|
|
1382
|
+
if (totalSavingsRatio > savingsRatio) {
|
|
1383
|
+
lines.push("", `**Total context savings (sandbox + cache): ${totalSavingsRatio.toFixed(1)}x** — ${kb(totalWithCache)} processed, only ${kb(totalBytesReturned)} entered context.`);
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1406
1386
|
}
|
|
1407
1387
|
// ── Session Continuity ──
|
|
1408
1388
|
try {
|