context-mode 0.9.10 → 0.9.12

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.
@@ -13,7 +13,7 @@
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": "0.9.10",
16
+ "version": "0.9.12",
17
17
  "author": {
18
18
  "name": "Mert Koseoğlu"
19
19
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mode",
3
- "version": "0.9.10",
3
+ "version": "0.9.12",
4
4
  "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.",
5
5
  "author": {
6
6
  "name": "Mert Koseoğlu",
@@ -6,41 +6,89 @@
6
6
  * Cross-platform (Windows/macOS/Linux) — no bash/jq dependency.
7
7
  */
8
8
 
9
- import { readFileSync, writeFileSync, existsSync } from "node:fs";
9
+ import { readFileSync, writeFileSync, existsSync, rmSync, cpSync, readdirSync } from "node:fs";
10
10
  import { resolve, dirname, basename } from "node:path";
11
11
  import { fileURLToPath } from "node:url";
12
12
  import { homedir, tmpdir } from "node:os";
13
13
 
14
- // ─── Self-heal registry (runs once per session via marker file) ───
14
+ // ─── Self-heal: copy new code to registry's installPath + nuke stale cache ───
15
15
  try {
16
- const marker = resolve(tmpdir(), "context-mode-registry-healed");
17
- if (!existsSync(marker)) {
18
- const hookDir = dirname(fileURLToPath(import.meta.url));
19
- const myRoot = resolve(hookDir, "..");
20
- const myVersion = basename(myRoot);
21
-
22
- if (/^\d+\.\d+\.\d+/.test(myVersion)) {
23
- const ipPath = resolve(homedir(), ".claude", "plugins", "installed_plugins.json");
24
- const ip = JSON.parse(readFileSync(ipPath, "utf-8"));
25
- let fixed = false;
26
-
27
- for (const [key, entries] of Object.entries(ip.plugins || {})) {
28
- if (!key.toLowerCase().includes("context-mode")) continue;
29
- for (const entry of entries) {
30
- if (entry.installPath !== myRoot) {
31
- entry.installPath = myRoot;
32
- entry.version = myVersion;
33
- entry.lastUpdated = new Date().toISOString();
34
- fixed = true;
16
+ const hookDir = dirname(fileURLToPath(import.meta.url));
17
+ const myRoot = resolve(hookDir, "..");
18
+ const myPkg = JSON.parse(readFileSync(resolve(myRoot, "package.json"), "utf-8"));
19
+ const myVersion = myPkg.version ?? "unknown";
20
+ const marker = resolve(tmpdir(), `context-mode-healed-${myVersion}`);
21
+
22
+ if (myVersion !== "unknown" && !existsSync(marker)) {
23
+ const ipPath = resolve(homedir(), ".claude", "plugins", "installed_plugins.json");
24
+ const ip = JSON.parse(readFileSync(ipPath, "utf-8"));
25
+
26
+ for (const [key, entries] of Object.entries(ip.plugins || {})) {
27
+ if (!key.toLowerCase().includes("context-mode")) continue;
28
+ for (const entry of entries) {
29
+ const regPath = entry.installPath;
30
+
31
+ // Copy new code to registry's installPath if it's a different dir
32
+ if (regPath && regPath !== myRoot && existsSync(regPath)) {
33
+ const items = [
34
+ "build", "hooks", "skills", ".claude-plugin",
35
+ "start.mjs", "server.bundle.mjs", "package.json", ".mcp.json",
36
+ ];
37
+ for (const item of items) {
38
+ const src = resolve(myRoot, item);
39
+ if (existsSync(src)) {
40
+ try {
41
+ rmSync(resolve(regPath, item), { recursive: true, force: true });
42
+ cpSync(src, resolve(regPath, item), { recursive: true });
43
+ } catch { /* skip */ }
44
+ }
35
45
  }
36
46
  }
37
- }
38
47
 
39
- if (fixed) {
40
- writeFileSync(ipPath, JSON.stringify(ip, null, 2) + "\n", "utf-8");
48
+ // Update version in registry
49
+ if (entry.version !== myVersion) {
50
+ entry.version = myVersion;
51
+ entry.lastUpdated = new Date().toISOString();
52
+ }
53
+
54
+ // Nuke all stale version dirs (keep only registry's installPath)
55
+ if (regPath) {
56
+ const cacheParent = dirname(regPath);
57
+ const keepDir = basename(regPath);
58
+ try {
59
+ for (const d of readdirSync(cacheParent)) {
60
+ if (d !== keepDir) {
61
+ try { rmSync(resolve(cacheParent, d), { recursive: true, force: true }); } catch { /* skip */ }
62
+ }
63
+ }
64
+ } catch { /* skip */ }
65
+ }
41
66
  }
42
- writeFileSync(marker, Date.now().toString(), "utf-8");
43
67
  }
68
+
69
+ writeFileSync(ipPath, JSON.stringify(ip, null, 2) + "\n", "utf-8");
70
+
71
+ // Create start.mjs if missing (old versions used start.sh)
72
+ const startMjs = resolve(myRoot, "start.mjs");
73
+ if (!existsSync(startMjs)) {
74
+ const shim = [
75
+ '#!/usr/bin/env node',
76
+ 'import { existsSync } from "node:fs";',
77
+ 'import { dirname, resolve } from "node:path";',
78
+ 'import { fileURLToPath } from "node:url";',
79
+ 'const __dirname = dirname(fileURLToPath(import.meta.url));',
80
+ 'process.chdir(__dirname);',
81
+ 'if (!process.env.CLAUDE_PROJECT_DIR) process.env.CLAUDE_PROJECT_DIR = process.cwd();',
82
+ 'if (existsSync(resolve(__dirname, "server.bundle.mjs"))) {',
83
+ ' await import("./server.bundle.mjs");',
84
+ '} else if (existsSync(resolve(__dirname, "build", "server.js"))) {',
85
+ ' await import("./build/server.js");',
86
+ '}',
87
+ ].join("\n");
88
+ writeFileSync(startMjs, shim, "utf-8");
89
+ }
90
+
91
+ writeFileSync(marker, Date.now().toString(), "utf-8");
44
92
  }
45
93
  } catch { /* best effort — don't block hook */ }
46
94
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mode",
3
- "version": "0.9.10",
3
+ "version": "0.9.12",
4
4
  "type": "module",
5
5
  "description": "Claude Code MCP plugin that saves 98% of your context window. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
6
6
  "author": "Mert Koseoğlu",