context-mode 1.0.92 → 1.0.94
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/cli.d.ts +2 -0
- package/build/cli.js +26 -6
- package/build/server.js +51 -12
- package/cli.bundle.mjs +95 -95
- package/hooks/ensure-deps.mjs +5 -3
- package/insight/server.mjs +21 -0
- package/insight/src/routes/index.tsx +5 -11
- package/insight/src/routes/sessions.tsx +3 -3
- package/openclaw.plugin.json +1 -1
- package/package.json +9 -2
- package/server.bundle.mjs +61 -61
- package/insight/components.json +0 -25
|
@@ -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.94"
|
|
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.94",
|
|
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.94",
|
|
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.94",
|
|
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.94",
|
|
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/cli.d.ts
CHANGED
|
@@ -13,3 +13,5 @@
|
|
|
13
13
|
*/
|
|
14
14
|
/** Normalize Windows backslash paths to forward slashes for Bash (MSYS2) compatibility. */
|
|
15
15
|
export declare function toUnixPath(p: string): string;
|
|
16
|
+
export declare function npmExecFile(args: string[], opts?: Record<string, unknown>): void;
|
|
17
|
+
export declare function npmExec(command: string, opts?: Record<string, unknown>): void;
|
package/build/cli.js
CHANGED
|
@@ -120,6 +120,26 @@ else {
|
|
|
120
120
|
export function toUnixPath(p) {
|
|
121
121
|
return p.replace(/\\/g, "/");
|
|
122
122
|
}
|
|
123
|
+
/**
|
|
124
|
+
* Windows-safe npm execution. On Windows:
|
|
125
|
+
* - "npm" → "npm.cmd" (Node won't resolve via PATHEXT in execFile)
|
|
126
|
+
* - shell: true required (Node v20+ CVE-2024-27980 mitigation)
|
|
127
|
+
* See: https://github.com/mksglu/context-mode/issues/344
|
|
128
|
+
*/
|
|
129
|
+
const isWin = process.platform === "win32";
|
|
130
|
+
export function npmExecFile(args, opts = {}) {
|
|
131
|
+
execFileSync(isWin ? "npm.cmd" : "npm", args, {
|
|
132
|
+
...opts,
|
|
133
|
+
...(isWin ? { shell: true } : {}),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
export function npmExec(command, opts = {}) {
|
|
137
|
+
const { execSync: es } = require("node:child_process");
|
|
138
|
+
es(isWin ? command.replace(/^npm /, "npm.cmd ") : command, {
|
|
139
|
+
...opts,
|
|
140
|
+
...(isWin ? { shell: true } : {}),
|
|
141
|
+
});
|
|
142
|
+
}
|
|
123
143
|
function defaultPluginRoot() {
|
|
124
144
|
const __filename = fileURLToPath(import.meta.url);
|
|
125
145
|
const __dirname = dirname(__filename);
|
|
@@ -400,7 +420,7 @@ async function insight(port) {
|
|
|
400
420
|
if (!existsSync(join(cacheDir, "node_modules"))) {
|
|
401
421
|
console.log("Installing dependencies (first run)...");
|
|
402
422
|
try {
|
|
403
|
-
|
|
423
|
+
npmExec("npm install --production=false", { cwd: cacheDir, stdio: "inherit", timeout: 300000 });
|
|
404
424
|
}
|
|
405
425
|
catch {
|
|
406
426
|
// Clean up partial install so next run retries fresh
|
|
@@ -512,12 +532,12 @@ async function upgrade() {
|
|
|
512
532
|
}
|
|
513
533
|
// Step 2: Install dependencies + build
|
|
514
534
|
s.start("Installing dependencies & building");
|
|
515
|
-
|
|
535
|
+
npmExecFile(["install", "--no-audit", "--no-fund"], {
|
|
516
536
|
cwd: srcDir,
|
|
517
537
|
stdio: "pipe",
|
|
518
538
|
timeout: 120000,
|
|
519
539
|
});
|
|
520
|
-
|
|
540
|
+
npmExecFile(["run", "build"], {
|
|
521
541
|
cwd: srcDir,
|
|
522
542
|
stdio: "pipe",
|
|
523
543
|
timeout: 60000,
|
|
@@ -558,7 +578,7 @@ async function upgrade() {
|
|
|
558
578
|
p.log.info(color.dim(" Registry synced to " + pluginRoot));
|
|
559
579
|
// Install production deps
|
|
560
580
|
s.start("Installing production dependencies");
|
|
561
|
-
|
|
581
|
+
npmExecFile(["install", "--production", "--no-audit", "--no-fund"], {
|
|
562
582
|
cwd: pluginRoot,
|
|
563
583
|
stdio: "pipe",
|
|
564
584
|
timeout: 60000,
|
|
@@ -568,7 +588,7 @@ async function upgrade() {
|
|
|
568
588
|
// Rebuild native addons for current Node.js ABI (fixes #131)
|
|
569
589
|
s.start("Rebuilding native addons");
|
|
570
590
|
try {
|
|
571
|
-
|
|
591
|
+
npmExecFile(["rebuild", "better-sqlite3"], {
|
|
572
592
|
cwd: pluginRoot,
|
|
573
593
|
stdio: "pipe",
|
|
574
594
|
timeout: 60000,
|
|
@@ -587,7 +607,7 @@ async function upgrade() {
|
|
|
587
607
|
// Update global npm
|
|
588
608
|
s.start("Updating npm global package");
|
|
589
609
|
try {
|
|
590
|
-
|
|
610
|
+
npmExecFile(["install", "-g", pluginRoot, "--no-audit", "--no-fund"], {
|
|
591
611
|
stdio: "pipe",
|
|
592
612
|
timeout: 30000,
|
|
593
613
|
});
|
package/build/server.js
CHANGED
|
@@ -1700,6 +1700,25 @@ server.registerTool("ctx_upgrade", {
|
|
|
1700
1700
|
const pluginRoot = existsSync(resolve(__pkg_dir, "package.json")) ? __pkg_dir : dirname(__pkg_dir);
|
|
1701
1701
|
const bundlePath = resolve(pluginRoot, "cli.bundle.mjs");
|
|
1702
1702
|
const fallbackPath = resolve(pluginRoot, "build", "cli.js");
|
|
1703
|
+
// Clean up insight-cache on upgrade so next ctx_insight does fresh build
|
|
1704
|
+
try {
|
|
1705
|
+
const sessDir = getSessionDir();
|
|
1706
|
+
const insightCacheDir = join(dirname(sessDir), "insight-cache");
|
|
1707
|
+
if (existsSync(insightCacheDir)) {
|
|
1708
|
+
// Kill any running insight server first
|
|
1709
|
+
try {
|
|
1710
|
+
if (process.platform === "win32") {
|
|
1711
|
+
execSync('for /f "tokens=5" %a in (\'netstat -ano ^| findstr :4747\') do taskkill /F /PID %a', { stdio: "pipe" });
|
|
1712
|
+
}
|
|
1713
|
+
else {
|
|
1714
|
+
execSync("lsof -ti:4747 | xargs kill 2>/dev/null", { stdio: "pipe" });
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
catch { /* no process to kill */ }
|
|
1718
|
+
rmSync(insightCacheDir, { recursive: true, force: true });
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
catch { /* best effort — don't block upgrade */ }
|
|
1703
1722
|
let cmd;
|
|
1704
1723
|
if (existsSync(bundlePath)) {
|
|
1705
1724
|
cmd = `node "${bundlePath}" upgrade`;
|
|
@@ -1726,13 +1745,13 @@ server.registerTool("ctx_upgrade", {
|
|
|
1726
1745
|
`console.log("- [x] Starting inline upgrade (no CLI found)");`,
|
|
1727
1746
|
`execFileSync("git",["clone","--depth","1","${repoUrl}",T],{stdio:"inherit"});`,
|
|
1728
1747
|
`console.log("- [x] Cloned latest source");`,
|
|
1729
|
-
`execFileSync("npm",["install"],{cwd:T,stdio:"inherit"});`,
|
|
1730
|
-
`execFileSync("npm",["run","build"],{cwd:T,stdio:"inherit"});`,
|
|
1748
|
+
`execFileSync(process.platform==="win32"?"npm.cmd":"npm",["install"],{cwd:T,stdio:"inherit",shell:process.platform==="win32"});`,
|
|
1749
|
+
`execFileSync(process.platform==="win32"?"npm.cmd":"npm",["run","build"],{cwd:T,stdio:"inherit",shell:process.platform==="win32"});`,
|
|
1731
1750
|
`console.log("- [x] Built from source");`,
|
|
1732
1751
|
...copyDirs.map((d) => `if(existsSync(join(T,${JSON.stringify(d)})))cpSync(join(T,${JSON.stringify(d)}),join(P,${JSON.stringify(d)}),{recursive:true,force:true});`),
|
|
1733
1752
|
...copyFiles.map((f) => `if(existsSync(join(T,${JSON.stringify(f)})))cpSync(join(T,${JSON.stringify(f)}),join(P,${JSON.stringify(f)}),{force:true});`),
|
|
1734
1753
|
`console.log("- [x] Copied build artifacts");`,
|
|
1735
|
-
`execFileSync("npm",["install","--production"],{cwd:P,stdio:"inherit"});`,
|
|
1754
|
+
`execFileSync(process.platform==="win32"?"npm.cmd":"npm",["install","--production"],{cwd:P,stdio:"inherit",shell:process.platform==="win32"});`,
|
|
1736
1755
|
`console.log("- [x] Installed production dependencies");`,
|
|
1737
1756
|
`console.log("## context-mode upgrade complete");`,
|
|
1738
1757
|
`}catch(e){`,
|
|
@@ -1904,6 +1923,7 @@ server.registerTool("ctx_insight", {
|
|
|
1904
1923
|
}
|
|
1905
1924
|
try {
|
|
1906
1925
|
const steps = [];
|
|
1926
|
+
let sourceUpdated = false;
|
|
1907
1927
|
// Ensure cache dir
|
|
1908
1928
|
mkdirSync(cacheDir, { recursive: true });
|
|
1909
1929
|
// Copy source files if needed (check by comparing server.mjs mtime)
|
|
@@ -1914,13 +1934,14 @@ server.registerTool("ctx_insight", {
|
|
|
1914
1934
|
steps.push("Copying source files...");
|
|
1915
1935
|
cpSync(insightSource, cacheDir, { recursive: true, force: true });
|
|
1916
1936
|
steps.push("Source files copied.");
|
|
1937
|
+
sourceUpdated = true;
|
|
1917
1938
|
}
|
|
1918
|
-
// Install deps if needed
|
|
1939
|
+
// Install deps if needed (also reinstall when source updated and package.json may have changed)
|
|
1919
1940
|
const hasNodeModules = existsSync(join(cacheDir, "node_modules"));
|
|
1920
|
-
if (!hasNodeModules) {
|
|
1941
|
+
if (!hasNodeModules || sourceUpdated) {
|
|
1921
1942
|
steps.push("Installing dependencies (first run, ~30s)...");
|
|
1922
1943
|
try {
|
|
1923
|
-
execSync("npm install --production=false", {
|
|
1944
|
+
execSync(process.platform === "win32" ? "npm.cmd install --production=false" : "npm install --production=false", {
|
|
1924
1945
|
cwd: cacheDir,
|
|
1925
1946
|
stdio: "pipe",
|
|
1926
1947
|
timeout: 300000,
|
|
@@ -1949,7 +1970,8 @@ server.registerTool("ctx_insight", {
|
|
|
1949
1970
|
timeout: 60000,
|
|
1950
1971
|
});
|
|
1951
1972
|
steps.push("Build complete.");
|
|
1952
|
-
// Pre-check: is port already in use?
|
|
1973
|
+
// Pre-check: is port already in use?
|
|
1974
|
+
let portOccupied = false;
|
|
1953
1975
|
try {
|
|
1954
1976
|
const { request } = await import("node:http");
|
|
1955
1977
|
await new Promise((resolve, reject) => {
|
|
@@ -1961,9 +1983,29 @@ server.registerTool("ctx_insight", {
|
|
|
1961
1983
|
req.on("timeout", () => { req.destroy(); reject(); });
|
|
1962
1984
|
req.end();
|
|
1963
1985
|
});
|
|
1964
|
-
|
|
1986
|
+
portOccupied = true;
|
|
1987
|
+
}
|
|
1988
|
+
catch {
|
|
1989
|
+
// Port is free, proceed with spawn
|
|
1990
|
+
}
|
|
1991
|
+
if (portOccupied && sourceUpdated) {
|
|
1992
|
+
// Source was updated but stale server is running on port — kill it so fresh code runs
|
|
1993
|
+
steps.push("Killing stale dashboard server (source updated)...");
|
|
1994
|
+
try {
|
|
1995
|
+
if (process.platform === "win32") {
|
|
1996
|
+
execSync(`for /f "tokens=5" %a in ('netstat -ano ^| findstr :${port}') do taskkill /F /PID %a`, { stdio: "pipe" });
|
|
1997
|
+
}
|
|
1998
|
+
else {
|
|
1999
|
+
execSync(`lsof -ti:${port} | xargs kill 2>/dev/null`, { stdio: "pipe" });
|
|
2000
|
+
}
|
|
2001
|
+
await new Promise(r => setTimeout(r, 500)); // Wait for port to free
|
|
2002
|
+
}
|
|
2003
|
+
catch { /* no process to kill — proceed anyway */ }
|
|
2004
|
+
steps.push("Stale server killed.");
|
|
2005
|
+
}
|
|
2006
|
+
else if (portOccupied) {
|
|
2007
|
+
// Source unchanged, server is running fine — just open browser
|
|
1965
2008
|
steps.push("Dashboard already running.");
|
|
1966
|
-
// Open browser anyway
|
|
1967
2009
|
const url = `http://localhost:${port}`;
|
|
1968
2010
|
const platform = process.platform;
|
|
1969
2011
|
try {
|
|
@@ -1979,9 +2021,6 @@ server.registerTool("ctx_insight", {
|
|
|
1979
2021
|
content: [{ type: "text", text: `Dashboard already running at http://localhost:${port}` }],
|
|
1980
2022
|
});
|
|
1981
2023
|
}
|
|
1982
|
-
catch {
|
|
1983
|
-
// Port is free, proceed with spawn
|
|
1984
|
-
}
|
|
1985
2024
|
// Kill any previous insight child this MCP spawned (e.g. re-invocation).
|
|
1986
2025
|
if (_insightChild && _insightChild.pid && !_insightChild.killed) {
|
|
1987
2026
|
try {
|