context-mode 1.0.96 → 1.0.98

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.96"
9
+ "version": "1.0.98"
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.96",
16
+ "version": "1.0.98",
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.96",
3
+ "version": "1.0.98",
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.96",
6
+ "version": "1.0.98",
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.96",
3
+ "version": "1.0.98",
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
@@ -3,9 +3,9 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { createRequire } from "node:module";
5
5
  import { createHash } from "node:crypto";
6
- import { existsSync, unlinkSync, readdirSync, readFileSync, writeFileSync, rmSync, mkdirSync, cpSync, statSync, symlinkSync } from "node:fs";
6
+ import { existsSync, unlinkSync, readdirSync, readFileSync, writeFileSync, rmSync, mkdirSync, cpSync, statSync, symlinkSync, lstatSync } from "node:fs";
7
7
  import { execSync } from "node:child_process";
8
- import { join, dirname, resolve } from "node:path";
8
+ import { join, dirname, resolve, sep } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
  import { homedir, tmpdir } from "node:os";
11
11
  import { request as httpsRequest } from "node:https";
@@ -276,19 +276,30 @@ function healCacheMidSession() {
276
276
  if (!existsSync(ipPath))
277
277
  return;
278
278
  const ip = JSON.parse(readFileSync(ipPath, "utf-8"));
279
+ const cacheRoot = resolve(homedir(), ".claude", "plugins", "cache");
280
+ // Plugin root: build/ for tsc, plugin root for bundle
281
+ const pluginRoot = existsSync(resolve(__pkg_dir, "package.json")) ? __pkg_dir : dirname(__pkg_dir);
279
282
  for (const [key, entries] of Object.entries((ip.plugins ?? {}))) {
280
- if (!key.toLowerCase().includes("context-mode"))
283
+ if (key !== "context-mode@context-mode")
281
284
  continue;
282
285
  for (const entry of entries) {
283
286
  const rp = entry.installPath;
284
287
  if (!rp || existsSync(rp))
285
288
  continue;
289
+ // Path traversal guard
290
+ if (!resolve(rp).startsWith(cacheRoot + sep))
291
+ continue;
292
+ // Remove dangling symlink
293
+ try {
294
+ if (lstatSync(rp).isSymbolicLink())
295
+ unlinkSync(rp);
296
+ }
297
+ catch { }
286
298
  const parent = dirname(rp);
287
299
  if (!existsSync(parent))
288
300
  mkdirSync(parent, { recursive: true });
289
- const target = resolve(__pkg_dir, "..");
290
- if (existsSync(target)) {
291
- symlinkSync(target, rp, process.platform === "win32" ? "junction" : undefined);
301
+ if (existsSync(pluginRoot)) {
302
+ symlinkSync(pluginRoot, rp, process.platform === "win32" ? "junction" : undefined);
292
303
  }
293
304
  }
294
305
  }
@@ -2143,8 +2154,11 @@ async function main() {
2143
2154
  if (cleaned > 0) {
2144
2155
  console.error(`Cleaned up ${cleaned} stale DB file(s) from previous sessions`);
2145
2156
  }
2146
- // MCP readiness sentinel path (#230)
2147
- const mcpSentinel = join(tmpdir(), `context-mode-mcp-ready-${process.ppid}`);
2157
+ // MCP readiness sentinel path (#230, #347)
2158
+ // Uses process.pid (not ppid) — hooks use directory-scan to find any live sentinel.
2159
+ // Hardcoded /tmp on Unix to avoid TMPDIR mismatch (#347).
2160
+ const mcpSentinelDir = process.platform === "win32" ? tmpdir() : "/tmp";
2161
+ const mcpSentinel = join(mcpSentinelDir, `context-mode-mcp-ready-${process.pid}`);
2148
2162
  // Clean up own DB + backgrounded processes + preload script on shutdown
2149
2163
  const shutdown = () => {
2150
2164
  executor.cleanupBackgrounded();