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.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code plugins by Mert Koseoğlu",
9
- "version": "1.0.30"
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.30",
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.30",
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.30",
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.30",
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 {