context-mode 1.0.137 → 1.0.139
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/.codex-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +5 -1
- package/build/adapters/jetbrains-copilot/hooks.d.ts +11 -3
- package/build/adapters/jetbrains-copilot/hooks.js +11 -7
- package/build/adapters/opencode/plugin.js +30 -6
- package/build/adapters/vscode-copilot/hooks.d.ts +27 -3
- package/build/adapters/vscode-copilot/hooks.js +27 -12
- package/build/cli.js +199 -32
- package/build/openclaw-plugin.d.ts +130 -0
- package/build/openclaw-plugin.js +626 -0
- package/build/opencode-plugin.d.ts +122 -0
- package/build/opencode-plugin.js +372 -0
- package/build/pi-extension.d.ts +14 -0
- package/build/pi-extension.js +451 -0
- package/build/server.js +4 -1
- package/build/util/db-lock.d.ts +65 -0
- package/build/util/db-lock.js +166 -0
- package/cli.bundle.mjs +173 -160
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/scripts/heal-installed-plugins.mjs +115 -1
- package/scripts/postinstall.mjs +16 -18
- package/server.bundle.mjs +43 -43
- package/start.mjs +11 -14
package/openclaw.plugin.json
CHANGED
|
@@ -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.139",
|
|
7
7
|
"sandbox": {
|
|
8
8
|
"mode": "permissive",
|
|
9
9
|
"filesystem_access": "full",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.139",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP plugin that saves 98% of your context window. Works with Claude Code, Gemini CLI, VS Code Copilot, OpenCode, and Codex CLI. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
|
|
6
6
|
"author": "Mert Koseoğlu",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* @see https://github.com/anthropics/claude-code/issues/46915
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
20
|
+
import { existsSync, readFileSync, writeFileSync, readdirSync, unlinkSync, statSync } from "node:fs";
|
|
21
21
|
import { resolve, sep } from "node:path";
|
|
22
22
|
|
|
23
23
|
/**
|
|
@@ -461,3 +461,117 @@ export function healClaudeJsonMcpArgs({ dotClaudeJsonPath, pluginCacheParent, ne
|
|
|
461
461
|
|
|
462
462
|
return { healed: ["claude-json-mcp-args"] };
|
|
463
463
|
}
|
|
464
|
+
|
|
465
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
466
|
+
// Issue #609 — sweepStaleMcpJson: remove cache-baked `.mcp.json` files.
|
|
467
|
+
//
|
|
468
|
+
// Background (per ISSUE-609-VERDICT, ISSUE-604-VERDICT):
|
|
469
|
+
// cli.ts upgrade() wrote `.mcp.json` into every per-version plugin-cache
|
|
470
|
+
// dir starting with #411. PR #531 (commit 9261377) removed `.mcp.json`
|
|
471
|
+
// from `package.json files[]` so the npm tarball no longer ships it,
|
|
472
|
+
// but the cli-side write persisted. Every `/ctx-upgrade` re-baked a
|
|
473
|
+
// per-version copy. When Claude Code's native plugin manager auto-update
|
|
474
|
+
// later copies a previous version's `.mcp.json` forward into a fresh
|
|
475
|
+
// version dir, the stale start.mjs absolute path goes with it →
|
|
476
|
+
// MODULE_NOT_FOUND on every MCP boot, and `ctx-doctor` stays green
|
|
477
|
+
// because nothing validates that path against current pluginRoot.
|
|
478
|
+
//
|
|
479
|
+
// The architectural fix is to STOP writing `.mcp.json` from the cache layer
|
|
480
|
+
// entirely. `.claude-plugin/plugin.json.mcpServers` is the canonical source
|
|
481
|
+
// (refs/platforms/claude-code/src/utils/plugins/mcpPluginIntegration.ts:131-212
|
|
482
|
+
// — Claude Code reads it first). This sweep removes any pre-existing
|
|
483
|
+
// `.mcp.json` from every per-version cache dir so the previous-version-
|
|
484
|
+
// carry vector cannot replay across upgrades.
|
|
485
|
+
//
|
|
486
|
+
// Single source of truth shared by:
|
|
487
|
+
// - `start.mjs` HEAL 5c (every MCP boot)
|
|
488
|
+
// - `scripts/postinstall.mjs` (every `npm install -g context-mode`)
|
|
489
|
+
// - `src/cli.ts` upgrade() (post-bump)
|
|
490
|
+
//
|
|
491
|
+
// Safety contracts:
|
|
492
|
+
// - Path-traversal guard: refuses to walk outside `pluginCacheRoot`.
|
|
493
|
+
// - Best-effort: NEVER throws; missing files / unreadable dirs are
|
|
494
|
+
// skipped silently and reported in the result.
|
|
495
|
+
// - Scope: deletes ONLY files named exactly `.mcp.json`; never touches
|
|
496
|
+
// sibling files in the same dir.
|
|
497
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
498
|
+
|
|
499
|
+
/**
|
|
500
|
+
* @typedef {Object} SweepResult
|
|
501
|
+
* @property {string[]} removed - absolute paths of removed `.mcp.json` files
|
|
502
|
+
* @property {string} [skipped] - reason if no work performed (e.g. "no-cache-root")
|
|
503
|
+
*/
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Remove every `.mcp.json` from per-version directories under
|
|
507
|
+
* `<pluginCacheRoot>/<owner>/<plugin>/<X.Y.Z>/`.
|
|
508
|
+
*
|
|
509
|
+
* @param {{ pluginCacheRoot: string, pluginKey: string }} opts
|
|
510
|
+
* pluginKey is the "<owner>@<plugin>" form (e.g. "context-mode@context-mode").
|
|
511
|
+
* @returns {SweepResult}
|
|
512
|
+
*/
|
|
513
|
+
export function sweepStaleMcpJson({ pluginCacheRoot, pluginKey }) {
|
|
514
|
+
/** @type {string[]} */
|
|
515
|
+
const removed = [];
|
|
516
|
+
|
|
517
|
+
if (!pluginCacheRoot || !pluginKey) {
|
|
518
|
+
return { removed, skipped: "missing-args" };
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
const resolvedCacheRoot = resolve(pluginCacheRoot);
|
|
522
|
+
if (!existsSync(resolvedCacheRoot)) {
|
|
523
|
+
return { removed, skipped: "no-cache-root" };
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// pluginKey shape: "<owner>@<plugin>"
|
|
527
|
+
const [ownerSegment, pluginSegment] = pluginKey.split("@");
|
|
528
|
+
if (!ownerSegment || !pluginSegment) {
|
|
529
|
+
return { removed, skipped: "bad-plugin-key" };
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Path-traversal guard: refuse to walk outside the declared cache root,
|
|
533
|
+
// even if pluginKey contains `..` segments. Per Mert's standing Windows
|
|
534
|
+
// safety rule, resolve normalizes both `/` and `\` so the guard fires
|
|
535
|
+
// on either separator.
|
|
536
|
+
const ownerDir = resolve(resolvedCacheRoot, ownerSegment, pluginSegment);
|
|
537
|
+
const cacheRootWithSep = resolvedCacheRoot + sep;
|
|
538
|
+
if (!ownerDir.startsWith(cacheRootWithSep)) {
|
|
539
|
+
return { removed, skipped: "outside-cache-root" };
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
if (!existsSync(ownerDir)) {
|
|
543
|
+
return { removed, skipped: "no-plugin-dir" };
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
/** @type {string[]} */
|
|
547
|
+
let versionEntries = [];
|
|
548
|
+
try {
|
|
549
|
+
versionEntries = readdirSync(ownerDir);
|
|
550
|
+
} catch {
|
|
551
|
+
return { removed, skipped: "readdir-failed" };
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
for (const versionEntry of versionEntries) {
|
|
555
|
+
const versionDir = resolve(ownerDir, versionEntry);
|
|
556
|
+
// Per-version guard: only enter directories whose resolved path stays
|
|
557
|
+
// under the owner dir. Belt-and-braces against weird FS entries.
|
|
558
|
+
if (!versionDir.startsWith(ownerDir + sep)) continue;
|
|
559
|
+
try {
|
|
560
|
+
const stat = statSync(versionDir);
|
|
561
|
+
if (!stat.isDirectory()) continue;
|
|
562
|
+
} catch {
|
|
563
|
+
continue;
|
|
564
|
+
}
|
|
565
|
+
const mcpJsonPath = resolve(versionDir, ".mcp.json");
|
|
566
|
+
if (!existsSync(mcpJsonPath)) continue;
|
|
567
|
+
try {
|
|
568
|
+
unlinkSync(mcpJsonPath);
|
|
569
|
+
removed.push(mcpJsonPath);
|
|
570
|
+
} catch {
|
|
571
|
+
// best-effort: file may have been removed by a concurrent process
|
|
572
|
+
// between existsSync and unlinkSync. Silent skip.
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
return { removed };
|
|
577
|
+
}
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import { dirname, resolve, join, sep } from "node:path";
|
|
|
14
14
|
import { fileURLToPath } from "node:url";
|
|
15
15
|
import { homedir } from "node:os";
|
|
16
16
|
import { healBetterSqlite3Binding } from "./heal-better-sqlite3.mjs";
|
|
17
|
-
import { healInstalledPlugins, healSettingsEnabledPlugins, healPluginJsonMcpServers,
|
|
17
|
+
import { healInstalledPlugins, healSettingsEnabledPlugins, healPluginJsonMcpServers, sweepStaleMcpJson } from "./heal-installed-plugins.mjs";
|
|
18
18
|
|
|
19
19
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
20
|
const pkgRoot = resolve(__dirname, "..");
|
|
@@ -181,26 +181,24 @@ if (isGlobalInstall()) {
|
|
|
181
181
|
healedAny = true;
|
|
182
182
|
}
|
|
183
183
|
} catch { /* per-entry best effort */ }
|
|
184
|
-
// v1.0.122 — Issue #531 — Layer 6: asymmetric-heal sibling for
|
|
185
|
-
// .mcp.json. The #253/aea633c regression shipped a bare `./start.mjs`
|
|
186
|
-
// arg that Claude Code resolves against session CWD (not pluginRoot)
|
|
187
|
-
// → MODULE_NOT_FOUND on every ctx_* tool. When MCP is dead, the
|
|
188
|
-
// only escape hatch is `npm install -g context-mode` whose
|
|
189
|
-
// postinstall MUST run this heal too.
|
|
190
|
-
try {
|
|
191
|
-
const r = healMcpJsonArgs({
|
|
192
|
-
pluginRoot: installPath,
|
|
193
|
-
pluginCacheRoot: cacheRoot,
|
|
194
|
-
pluginKey: "context-mode@context-mode",
|
|
195
|
-
});
|
|
196
|
-
if (r && Array.isArray(r.healed) && r.healed.length > 0) {
|
|
197
|
-
healedAny = true;
|
|
198
|
-
}
|
|
199
|
-
} catch { /* per-entry best effort */ }
|
|
200
184
|
}
|
|
201
185
|
}
|
|
186
|
+
// Issue #609 — Layer 6: sweep stale `.mcp.json` files from every
|
|
187
|
+
// per-version cache dir. Replaces the previous per-entry healMcpJsonArgs
|
|
188
|
+
// loop (v1.0.122) — `.mcp.json` is no longer written from cli.ts so
|
|
189
|
+
// remaining files in the cache are stale carry-forwards that block
|
|
190
|
+
// future auto-updates from working cleanly. Single sweep per install.
|
|
191
|
+
try {
|
|
192
|
+
const sweepResult = sweepStaleMcpJson({
|
|
193
|
+
pluginCacheRoot: cacheRoot,
|
|
194
|
+
pluginKey: "context-mode@context-mode",
|
|
195
|
+
});
|
|
196
|
+
if (sweepResult && Array.isArray(sweepResult.removed) && sweepResult.removed.length > 0) {
|
|
197
|
+
process.stderr.write(`context-mode: swept ${sweepResult.removed.length} stale .mcp.json file(s) (Issue #609)\n`);
|
|
198
|
+
}
|
|
199
|
+
} catch { /* never block install */ }
|
|
202
200
|
if (healedAny) {
|
|
203
|
-
process.stderr.write("context-mode: healed mcpServers args (
|
|
201
|
+
process.stderr.write("context-mode: healed mcpServers args (Issue #523)\n");
|
|
204
202
|
}
|
|
205
203
|
}
|
|
206
204
|
} catch { /* never block install */ }
|