context-mode 0.9.12 → 0.9.13

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.12",
16
+ "version": "0.9.13",
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.12",
3
+ "version": "0.9.13",
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",
@@ -11,82 +11,86 @@ 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: copy new code to registry's installPath + nuke stale cache ───
14
+ // ─── Self-heal: rename dir to correct version, fix registry + hooks ───
15
15
  try {
16
16
  const hookDir = dirname(fileURLToPath(import.meta.url));
17
17
  const myRoot = resolve(hookDir, "..");
18
18
  const myPkg = JSON.parse(readFileSync(resolve(myRoot, "package.json"), "utf-8"));
19
19
  const myVersion = myPkg.version ?? "unknown";
20
+ const myDirName = basename(myRoot);
21
+ const cacheParent = dirname(myRoot);
20
22
  const marker = resolve(tmpdir(), `context-mode-healed-${myVersion}`);
21
23
 
22
24
  if (myVersion !== "unknown" && !existsSync(marker)) {
25
+ // 1. If dir name doesn't match version (e.g. "0.7.0" but code is "0.9.12"),
26
+ // create correct dir, copy files, update registry + hooks
27
+ const correctDir = resolve(cacheParent, myVersion);
28
+ if (myDirName !== myVersion && !existsSync(correctDir)) {
29
+ cpSync(myRoot, correctDir, { recursive: true });
30
+
31
+ // Create start.mjs in new dir if missing
32
+ const startMjs = resolve(correctDir, "start.mjs");
33
+ if (!existsSync(startMjs)) {
34
+ writeFileSync(startMjs, [
35
+ '#!/usr/bin/env node',
36
+ 'import { existsSync } from "node:fs";',
37
+ 'import { dirname, resolve } from "node:path";',
38
+ 'import { fileURLToPath } from "node:url";',
39
+ 'const __dirname = dirname(fileURLToPath(import.meta.url));',
40
+ 'process.chdir(__dirname);',
41
+ 'if (!process.env.CLAUDE_PROJECT_DIR) process.env.CLAUDE_PROJECT_DIR = process.cwd();',
42
+ 'if (existsSync(resolve(__dirname, "server.bundle.mjs"))) {',
43
+ ' await import("./server.bundle.mjs");',
44
+ '} else if (existsSync(resolve(__dirname, "build", "server.js"))) {',
45
+ ' await import("./build/server.js");',
46
+ '}',
47
+ ].join("\n"), "utf-8");
48
+ }
49
+ }
50
+
51
+ const targetDir = existsSync(correctDir) ? correctDir : myRoot;
52
+
53
+ // 2. Update installed_plugins.json → point to correct version dir
23
54
  const ipPath = resolve(homedir(), ".claude", "plugins", "installed_plugins.json");
24
55
  const ip = JSON.parse(readFileSync(ipPath, "utf-8"));
25
-
26
56
  for (const [key, entries] of Object.entries(ip.plugins || {})) {
27
57
  if (!key.toLowerCase().includes("context-mode")) continue;
28
58
  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 */ }
59
+ entry.installPath = targetDir;
60
+ entry.version = myVersion;
61
+ entry.lastUpdated = new Date().toISOString();
62
+ }
63
+ }
64
+ writeFileSync(ipPath, JSON.stringify(ip, null, 2) + "\n", "utf-8");
65
+
66
+ // 3. Update hook path in settings.json
67
+ const settingsPath = resolve(homedir(), ".claude", "settings.json");
68
+ try {
69
+ const settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
70
+ const hooks = settings.hooks?.PreToolUse;
71
+ if (Array.isArray(hooks)) {
72
+ let changed = false;
73
+ for (const entry of hooks) {
74
+ for (const h of (entry.hooks || [])) {
75
+ if (h.command?.includes("pretooluse.mjs") && !h.command.includes(targetDir)) {
76
+ h.command = "node " + resolve(targetDir, "hooks", "pretooluse.mjs");
77
+ changed = true;
44
78
  }
45
79
  }
46
80
  }
47
-
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 */ }
81
+ if (changed) writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
82
+ }
83
+ } catch { /* skip settings update */ }
84
+
85
+ // 4. Nuke stale version dirs (keep only targetDir and current running dir)
86
+ try {
87
+ const keepDirs = new Set([basename(targetDir), myDirName]);
88
+ for (const d of readdirSync(cacheParent)) {
89
+ if (!keepDirs.has(d)) {
90
+ try { rmSync(resolve(cacheParent, d), { recursive: true, force: true }); } catch { /* skip */ }
65
91
  }
66
92
  }
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
- }
93
+ } catch { /* skip */ }
90
94
 
91
95
  writeFileSync(marker, Date.now().toString(), "utf-8");
92
96
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "context-mode",
3
- "version": "0.9.12",
3
+ "version": "0.9.13",
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",