context-mode 1.0.141 → 1.0.143
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/build/adapters/opencode/plugin.js +5 -20
- package/build/adapters/opencode/zod3tov4.d.ts +1 -0
- package/build/adapters/opencode/zod3tov4.js +111 -0
- package/build/db-base.js +12 -1
- package/cli.bundle.mjs +1 -1
- package/hooks/session-db.bundle.mjs +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +1 -1
- package/start.mjs +40 -9
|
@@ -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.143"
|
|
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.143",
|
|
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.143",
|
|
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",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.143",
|
|
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.143",
|
|
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.143",
|
|
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",
|
|
@@ -28,25 +28,7 @@ import { extractEvents, extractUserEvents } from "../../session/extract.js";
|
|
|
28
28
|
import { buildResumeSnapshot } from "../../session/snapshot.js";
|
|
29
29
|
import { OpenCodeAdapter } from "./index.js";
|
|
30
30
|
import { PLATFORM_ENV_VARS } from "../detect.js";
|
|
31
|
-
|
|
32
|
-
// Used in the resume-injection visible signal so users can confirm in
|
|
33
|
-
// OPENCODE_DEBUG logs which plugin version actually injected.
|
|
34
|
-
const VERSION = (() => {
|
|
35
|
-
try {
|
|
36
|
-
const pkgRoot = dirname(fileURLToPath(import.meta.url));
|
|
37
|
-
// Search both the legacy depths (when bundled flat under build/) and
|
|
38
|
-
// the post-refactor depths (when compiled to build/adapters/opencode/).
|
|
39
|
-
// `../../../package.json` is the canonical location after the
|
|
40
|
-
// `src/opencode-plugin.ts → src/adapters/opencode/plugin.ts` move.
|
|
41
|
-
for (const rel of ["../../../package.json", "../package.json", "./package.json"]) {
|
|
42
|
-
const p = resolve(pkgRoot, rel);
|
|
43
|
-
if (existsSync(p))
|
|
44
|
-
return JSON.parse(readFileSync(p, "utf8")).version ?? "unknown";
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
catch { /* fall through */ }
|
|
48
|
-
return "unknown";
|
|
49
|
-
})();
|
|
31
|
+
import { zod3ShapeToV4 } from "./zod3tov4.js";
|
|
50
32
|
// Synthetic message tags emitted by harnesses (CCv2 inline filter). When the
|
|
51
33
|
// user "message" is actually a system-generated nudge (e.g. tool-result, system
|
|
52
34
|
// reminder), capturing it as user_prompt would flood the DB with noise.
|
|
@@ -264,9 +246,12 @@ async function createContextModePlugin(ctx) {
|
|
|
264
246
|
: typeof inputSchema?._def?.shape === "function"
|
|
265
247
|
? inputSchema._def.shape()
|
|
266
248
|
: {};
|
|
249
|
+
const argsForHost = platform === "kilo"
|
|
250
|
+
? zod3ShapeToV4(shape)
|
|
251
|
+
: shape;
|
|
267
252
|
tools[registered.name] = {
|
|
268
253
|
description: String(config.description ?? ""),
|
|
269
|
-
args:
|
|
254
|
+
args: argsForHost,
|
|
270
255
|
async execute(args, toolCtx) {
|
|
271
256
|
toolCtx.metadata?.({ title: String(config.title ?? registered.name) });
|
|
272
257
|
const project = toolCtx.directory || projectDir;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function zod3ShapeToV4(shape: Record<string, unknown>, depth?: number): Record<string, unknown>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod 3 → Zod 4 shape conversion (KiloCode only).
|
|
3
|
+
*
|
|
4
|
+
* KiloCode's runtime bundles Zod v4 internally. When it receives plugin tool
|
|
5
|
+
* definitions whose `args` contain Zod v3 schemas (with `_def` but no `_zod`),
|
|
6
|
+
* it crashes with `undefined is not an object (evaluating 'n._zod.def')`.
|
|
7
|
+
*
|
|
8
|
+
* This module converts Zod 3 schema shapes into Zod 4 equivalents so KiloCode
|
|
9
|
+
* can process them natively. Only called when `platform === "kilo"`.
|
|
10
|
+
* OpenCode uses Zod 3 natively and receives the original shapes unchanged.
|
|
11
|
+
*/
|
|
12
|
+
import z from 'zod/v4';
|
|
13
|
+
export function zod3ShapeToV4(shape, depth = 0) {
|
|
14
|
+
const result = {};
|
|
15
|
+
for (const [key, value] of Object.entries(shape)) {
|
|
16
|
+
result[key] = zod3ToV4(value, depth);
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
function zod3ToV4(v, depth = 0) {
|
|
21
|
+
if (depth > 10)
|
|
22
|
+
return z.unknown();
|
|
23
|
+
if (v == null || typeof v !== "object")
|
|
24
|
+
return z.unknown();
|
|
25
|
+
const obj = v;
|
|
26
|
+
if (!obj._def || typeof obj._def !== "object")
|
|
27
|
+
return z.unknown();
|
|
28
|
+
const def = obj._def;
|
|
29
|
+
let result;
|
|
30
|
+
switch (def.typeName) {
|
|
31
|
+
case "ZodString":
|
|
32
|
+
result = z.string();
|
|
33
|
+
break;
|
|
34
|
+
case "ZodNumber":
|
|
35
|
+
result = z.number();
|
|
36
|
+
break;
|
|
37
|
+
case "ZodBoolean":
|
|
38
|
+
result = z.boolean();
|
|
39
|
+
break;
|
|
40
|
+
case "ZodAny":
|
|
41
|
+
result = z.any();
|
|
42
|
+
break;
|
|
43
|
+
case "ZodUnknown":
|
|
44
|
+
result = z.unknown();
|
|
45
|
+
break;
|
|
46
|
+
case "ZodNever":
|
|
47
|
+
result = z.never();
|
|
48
|
+
break;
|
|
49
|
+
case "ZodNull":
|
|
50
|
+
result = z.null();
|
|
51
|
+
break;
|
|
52
|
+
case "ZodUndefined":
|
|
53
|
+
result = z.undefined();
|
|
54
|
+
break;
|
|
55
|
+
case "ZodLiteral":
|
|
56
|
+
result = z.literal(def.value);
|
|
57
|
+
break;
|
|
58
|
+
case "ZodArray":
|
|
59
|
+
result = z.array(zod3ToV4(def.type ?? def.elementType, depth + 1));
|
|
60
|
+
break;
|
|
61
|
+
case "ZodEnum": {
|
|
62
|
+
const values = def.values;
|
|
63
|
+
result = Array.isArray(values) && values.length > 0
|
|
64
|
+
? z.enum(values)
|
|
65
|
+
: z.never();
|
|
66
|
+
break;
|
|
67
|
+
}
|
|
68
|
+
case "ZodObject": {
|
|
69
|
+
const raw = def.shape;
|
|
70
|
+
const inner = typeof raw === "function" ? raw() : raw;
|
|
71
|
+
result = z.object(inner ? zod3ShapeToV4(inner, depth + 1) : {});
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
case "ZodOptional":
|
|
75
|
+
result = z.optional(zod3ToV4(def.innerType ?? def.type, depth + 1));
|
|
76
|
+
break;
|
|
77
|
+
case "ZodNullable":
|
|
78
|
+
result = z.nullable(zod3ToV4(def.innerType ?? def.type, depth + 1));
|
|
79
|
+
break;
|
|
80
|
+
case "ZodDefault": {
|
|
81
|
+
const val = typeof def.defaultValue === "function"
|
|
82
|
+
? def.defaultValue()
|
|
83
|
+
: def.defaultValue;
|
|
84
|
+
result = zod3ToV4(def.innerType ?? def.type, depth + 1).default(val);
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case "ZodRecord":
|
|
88
|
+
result = z.record(z.string(), zod3ToV4(def.valueType, depth + 1));
|
|
89
|
+
break;
|
|
90
|
+
case "ZodUnion": {
|
|
91
|
+
const opts = def.options;
|
|
92
|
+
if (!opts || opts.length === 0)
|
|
93
|
+
return z.never();
|
|
94
|
+
if (opts.length === 1)
|
|
95
|
+
return zod3ToV4(opts[0], depth + 1);
|
|
96
|
+
result = z.union(opts.map(o => zod3ToV4(o, depth + 1)));
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
case "ZodEffects":
|
|
100
|
+
// Host schema only. Original Zod 3 schema still parses in execute().
|
|
101
|
+
result = zod3ToV4(def.schema, depth + 1);
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
// Never leak raw Zod 3 schemas back to KiloCode.
|
|
105
|
+
result = z.unknown();
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
return def.description && typeof result.describe === "function"
|
|
109
|
+
? result.describe(String(def.description))
|
|
110
|
+
: result;
|
|
111
|
+
}
|
package/build/db-base.js
CHANGED
|
@@ -266,7 +266,18 @@ export function loadDatabase() {
|
|
|
266
266
|
const raw = new DatabaseSync(path, {
|
|
267
267
|
readOnly: opts?.readonly ?? false,
|
|
268
268
|
});
|
|
269
|
-
|
|
269
|
+
const adapter = new NodeSQLiteAdapter(raw);
|
|
270
|
+
// Propagate busy_timeout — node:sqlite's DatabaseSync constructor
|
|
271
|
+
// silently ignores `{ timeout }` (unlike better-sqlite3's native
|
|
272
|
+
// C++ constructor), so we set it via PRAGMA, mirroring the Bun
|
|
273
|
+
// branch above. Without this, the default is 0 and the first
|
|
274
|
+
// write contention surfaces as immediate `SQLITE_BUSY`/`database
|
|
275
|
+
// is locked` — defeating the 30s grace `withRetry()` is built
|
|
276
|
+
// around. See issue #642 and ADR-0001 (multi-writer contract).
|
|
277
|
+
if (opts?.timeout) {
|
|
278
|
+
adapter.pragma(`busy_timeout = ${opts.timeout}`);
|
|
279
|
+
}
|
|
280
|
+
return adapter;
|
|
270
281
|
};
|
|
271
282
|
}
|
|
272
283
|
else {
|
package/cli.bundle.mjs
CHANGED
|
@@ -146,7 +146,7 @@ file_content = File.read!(file_content_path)
|
|
|
146
146
|
${n}`;case"csharp":return`var FILE_CONTENT_PATH = ${s};
|
|
147
147
|
var file_path = FILE_CONTENT_PATH;
|
|
148
148
|
var FILE_CONTENT = System.IO.File.ReadAllText(FILE_CONTENT_PATH);
|
|
149
|
-
${n}`}}}});import{cpus as MF}from"node:os";async function xy(t,e){let{concurrency:r,capByCpuCount:n=!1,onSettled:s}=e;if(t.length===0)return{settled:[],effectiveConcurrency:0,capped:!1};let o=Math.max(1,r),i=n?Math.max(1,MF().length):o,a=Math.min(o,i,t.length),c=a<o,u=new Array(t.length),d=0;async function l(){for(;;){let f=d++;if(f>=t.length)return;try{let p=await t[f].run();u[f]={status:"fulfilled",value:p}}catch(p){u[f]={status:"rejected",reason:p}}s?.(f,u[f])}}let m=[];for(let f=0;f<a;f++)m.push(l());return await Promise.allSettled(m),{settled:u,effectiveConcurrency:a,capped:c}}var BE=x(()=>{"use strict"});var wy={};ze(wy,{BunSQLiteAdapter:()=>Qu,NodeSQLiteAdapter:()=>el,SQLiteBase:()=>aa,applyWALPragmas:()=>To,cleanOrphanedWALFiles:()=>Po,closeDB:()=>Ro,defaultDBPath:()=>ky,deleteDBFiles:()=>tl,hasModernSqlite:()=>WE,isSQLiteCorruptionError:()=>rl,loadDatabase:()=>st,nodeSqliteHasFts5:()=>VE,renameCorruptDB:()=>GE,withRetry:()=>Pn});import{createRequire as jF}from"node:module";import{existsSync as zF,unlinkSync as qE,renameSync as LF}from"node:fs";import{tmpdir as FF}from"node:os";import{join as UF}from"node:path";function VE(t){let e=null;try{return e=new t(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function WE(t,e){let r=e!==void 0?e:globalThis.Bun;if(typeof r<"u"&&r!==null)return!0;let n=t??process.versions,[s,o]=(n.node??"0.0.0").split("."),i=Number(s),a=Number(o);return!Number.isFinite(i)||!Number.isFinite(a)?!1:i>22||i===22&&a>=5}function st(){if(!$o){let t=jF(import.meta.url);if(globalThis.Bun){let e=t(["bun","sqlite"].join(":")).Database;$o=function(n,s){let o=new e(n,{readonly:s?.readonly,create:!0}),i=new Qu(o);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}}else if(WE()){let e=null;try{({DatabaseSync:e}=t(["node","sqlite"].join(":")))}catch{e=null}e&&VE(e)?$o=function(n,s){let o=new e(n,{readOnly:s?.readonly??!1})
|
|
149
|
+
${n}`}}}});import{cpus as MF}from"node:os";async function xy(t,e){let{concurrency:r,capByCpuCount:n=!1,onSettled:s}=e;if(t.length===0)return{settled:[],effectiveConcurrency:0,capped:!1};let o=Math.max(1,r),i=n?Math.max(1,MF().length):o,a=Math.min(o,i,t.length),c=a<o,u=new Array(t.length),d=0;async function l(){for(;;){let f=d++;if(f>=t.length)return;try{let p=await t[f].run();u[f]={status:"fulfilled",value:p}}catch(p){u[f]={status:"rejected",reason:p}}s?.(f,u[f])}}let m=[];for(let f=0;f<a;f++)m.push(l());return await Promise.allSettled(m),{settled:u,effectiveConcurrency:a,capped:c}}var BE=x(()=>{"use strict"});var wy={};ze(wy,{BunSQLiteAdapter:()=>Qu,NodeSQLiteAdapter:()=>el,SQLiteBase:()=>aa,applyWALPragmas:()=>To,cleanOrphanedWALFiles:()=>Po,closeDB:()=>Ro,defaultDBPath:()=>ky,deleteDBFiles:()=>tl,hasModernSqlite:()=>WE,isSQLiteCorruptionError:()=>rl,loadDatabase:()=>st,nodeSqliteHasFts5:()=>VE,renameCorruptDB:()=>GE,withRetry:()=>Pn});import{createRequire as jF}from"node:module";import{existsSync as zF,unlinkSync as qE,renameSync as LF}from"node:fs";import{tmpdir as FF}from"node:os";import{join as UF}from"node:path";function VE(t){let e=null;try{return e=new t(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function WE(t,e){let r=e!==void 0?e:globalThis.Bun;if(typeof r<"u"&&r!==null)return!0;let n=t??process.versions,[s,o]=(n.node??"0.0.0").split("."),i=Number(s),a=Number(o);return!Number.isFinite(i)||!Number.isFinite(a)?!1:i>22||i===22&&a>=5}function st(){if(!$o){let t=jF(import.meta.url);if(globalThis.Bun){let e=t(["bun","sqlite"].join(":")).Database;$o=function(n,s){let o=new e(n,{readonly:s?.readonly,create:!0}),i=new Qu(o);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}}else if(WE()){let e=null;try{({DatabaseSync:e}=t(["node","sqlite"].join(":")))}catch{e=null}e&&VE(e)?$o=function(n,s){let o=new e(n,{readOnly:s?.readonly??!1}),i=new el(o);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}:$o=t("better-sqlite3")}else $o=t("better-sqlite3")}return $o}function To(t){t.pragma("journal_mode = WAL"),t.pragma("synchronous = NORMAL");try{t.pragma("mmap_size = 268435456")}catch{}}function Po(t){if(!zF(t))for(let e of["-wal","-shm"])try{qE(t+e)}catch{}}function tl(t){for(let e of["","-wal","-shm"])try{qE(t+e)}catch{}}function Ro(t){try{t.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{t.close()}catch{}}function ky(t="context-mode"){return UF(FF(),`${t}-${process.pid}.db`)}function Pn(t,e=[100,500,2e3]){let r;for(let n=0;n<=e.length;n++)try{return t()}catch(s){let o=s instanceof Error?s.message:String(s);if(!o.includes("SQLITE_BUSY")&&!o.includes("database is locked"))throw s;if(r=s instanceof Error?s:new Error(o),n<e.length){let i=e[n],a=Date.now();for(;Date.now()-a<i;);}}throw new Error(`SQLITE_BUSY: database is locked after ${e.length} retries. Original error: ${r?.message}`)}function rl(t){return t.includes("SQLITE_CORRUPT")||t.includes("SQLITE_NOTADB")||t.includes("database disk image is malformed")||t.includes("file is not a database")}function GE(t){let e=Date.now();for(let r of["","-wal","-shm"])try{LF(t+r,`${t}${r}.corrupt-${e}`)}catch{}}var Qu,el,$o,ia,Sy,aa,Rn=x(()=>{"use strict";Qu=class{#e;constructor(e){this.#e=e}pragma(e){let n=this.#e.prepare(`PRAGMA ${e}`).all();if(!n||n.length===0)return;if(n.length>1)return n;let s=Object.values(n[0]);return s.length===1?s[0]:n[0]}exec(e){let r="",n=null;for(let o=0;o<e.length;o++){let i=e[o];if(n)r+=i,i===n&&(n=null);else if(i==="'"||i==='"')r+=i,n=i;else if(i===";"){let a=r.trim();a&&this.#e.prepare(a).run(),r=""}else r+=i}let s=r.trim();return s&&this.#e.prepare(s).run(),this}prepare(e){let r=this.#e.prepare(e);return{run:(...n)=>r.run(...n),get:(...n)=>{let s=r.get(...n);return s===null?void 0:s},all:(...n)=>r.all(...n),iterate:(...n)=>r.iterate(...n)}}transaction(e){return this.#e.transaction(e)}close(){this.#e.close()}},el=class{#e;constructor(e){this.#e=e}pragma(e){let n=this.#e.prepare(`PRAGMA ${e}`).all();if(!n||n.length===0)return;if(n.length>1)return n;let s=Object.values(n[0]);return s.length===1?s[0]:n[0]}exec(e){return this.#e.exec(e),this}prepare(e){let r=this.#e.prepare(e);return{run:(...n)=>r.run(...n),get:(...n)=>r.get(...n),all:(...n)=>r.all(...n),iterate:(...n)=>typeof r.iterate=="function"?r.iterate(...n):r.all(...n)[Symbol.iterator]()}}transaction(e){return(...r)=>{this.#e.exec("BEGIN");try{let n=e(...r);return this.#e.exec("COMMIT"),n}catch(n){throw this.#e.exec("ROLLBACK"),n}}}close(){this.#e.close()}},$o=null;ia=Symbol.for("__context_mode_live_dbs_v3__"),Sy=(()=>{let t=globalThis;return t[ia]||(t[ia]=new Set,process.on("exit",()=>{for(let e of t[ia])Ro(e);t[ia].clear()})),t[ia]})(),aa=class{#e;#t;constructor(e){let r=st();this.#e=e,Po(e);let n;try{n=new r(e,{timeout:3e4}),To(n)}catch(s){let o=s instanceof Error?s.message:String(s);if(rl(o)){GE(e),Po(e);try{n=new r(e,{timeout:3e4}),To(n)}catch(i){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw s}this.#t=n,Sy.add(this.#t),this.initSchema(),this.prepareStatements()}get db(){return this.#t}get dbPath(){return this.#e}close(){Sy.delete(this.#t),Ro(this.#t)}withRetry(e){return Pn(e)}cleanup(){Sy.delete(this.#t),Ro(this.#t),tl(this.#e)}}});import{readFileSync as KE,readdirSync as t$,unlinkSync as $y,existsSync as Ey,statSync as nl,openSync as JE,fstatSync as YE,closeSync as XE}from"node:fs";import{createHash as QE}from"node:crypto";import{tmpdir as r$}from"node:os";import{join as Ty}from"node:path";function n$(t){let e=new Set,r=[];for(let n of t){let s=n.toLowerCase();e.has(s)||(e.add(s),r.push(n))}return r}function HF(t,e="AND"){let r=n$(t.replace(/['"(){}[\]*:^~]/g," ").split(/\s+/).filter(o=>o.length>0&&!["AND","OR","NOT","NEAR"].includes(o.toUpperCase())));if(r.length===0)return'""';let n=r.filter(o=>!Co.has(o.toLowerCase()));return(n.length>0?n:r).map(o=>`"${o}"`).join(e==="OR"?" OR ":" ")}function ZF(t,e="AND"){let r=t.replace(/["'(){}[\]*:^~]/g,"").trim();if(r.length<3)return"";let n=n$(r.split(/\s+/).filter(i=>i.length>=3));if(n.length===0)return"";let s=n.filter(i=>!Co.has(i.toLowerCase()));return(s.length>0?s:n).map(i=>`"${i}"`).join(e==="OR"?" OR ":" ")}function BF(t,e){if(t.length===0)return e.length;if(e.length===0)return t.length;let r=Array.from({length:e.length+1},(n,s)=>s);for(let n=1;n<=t.length;n++){let s=[n];for(let o=1;o<=e.length;o++)s[o]=t[n-1]===e[o-1]?r[o-1]:1+Math.min(r[o],s[o-1],r[o-1]);r=s}return r[e.length]}function qF(t){return t<=4?1:t<=12?2:3}function Py(){let t=r$(),e=0;try{let r=t$(t);for(let n of r){let s=n.match(/^context-mode-(\d+)\.db$/);if(!s)continue;let o=parseInt(s[1],10);if(o!==process.pid)try{process.kill(o,0)}catch{let i=Ty(t,n);for(let a of["","-wal","-shm"])try{$y(i+a)}catch{}e++}}}catch{}return e}function Ry(t,e){let r=0;try{if(!Ey(t))return 0;let n=Date.now()-e*24*60*60*1e3,s=t$(t).filter(o=>o.endsWith(".db"));for(let o of s)try{let i=Ty(t,o),c=nl(i).mtimeMs<n;if(!c){let u=i+"-wal";if(Ey(u))try{let d=nl(u);d.size>0&&Date.now()-d.mtimeMs>36e5&&(c=!0)}catch{}}if(c){for(let u of["","-wal","-shm"])try{$y(i+u)}catch{}r++}}catch{}}catch{}return r}function VF(t,e){let r=[],n=t.indexOf(e);for(;n!==-1;)r.push(n),n=t.indexOf(e,n+1);return r}function WF(t,e,r=30){if(t.length<2||e.length<2)return 0;let n=0,s=Math.min(t.length,e.length)-1;for(let o=0;o<s;o++){let i=t[o],a=t[o+1],c=e[o].length,u=0;for(let d of i){let l=d+c,m=l+r;for(;u<a.length&&a[u]<l;)u++;u<a.length&&a[u]<=m&&(n++,u++)}}return n}function GF(t){if(t.length===0)return 1/0;if(t.length===1)return 0;let e=t.map(s=>[...s].sort((o,i)=>o-i)),r=new Array(e.length).fill(0),n=1/0;for(;;){let s=1/0,o=-1/0,i=0;for(let c=0;c<e.length;c++){let u=e[c][r[c]];u<s&&(s=u,i=c),u>o&&(o=u)}let a=o-s;if(a<n&&(n=a),r[i]++,r[i]>=e[i].length)break}return n}var Co,e$,sl,s$=x(()=>{"use strict";Rn();Co=new Set(["the","and","for","are","but","not","you","all","can","had","her","was","one","our","out","has","his","how","its","may","new","now","old","see","way","who","did","get","got","let","say","she","too","use","will","with","this","that","from","they","been","have","many","some","them","than","each","make","like","just","over","such","take","into","year","your","good","could","would","about","which","their","there","other","after","should","through","also","more","most","only","very","when","what","then","these","those","being","does","done","both","same","still","while","where","here","were","much","update","updates","updated","deps","dev","tests","test","add","added","fix","fixed","run","running","using"]);e$=4096;sl=class t{#e;#t;#n;#o;#s;#a;#c;#i;#u;#l;#m;#f;#h;#g;#y;#_;#v;#b;#x;#S;#k;#w;#E;#$;#T;#P;#R;#C;#O;#I;#A;#N;#D;#M=0;static OPTIMIZE_EVERY=50;#r=new Map;static FUZZY_CACHE_SIZE=256;constructor(e){let r=st();this.#t=e??Ty(r$(),`context-mode-${process.pid}.db`),Po(this.#t);let n;try{n=new r(this.#t,{timeout:3e4}),To(n)}catch(s){let o=s instanceof Error?s.message:String(s);if(rl(o)){tl(this.#t),Po(this.#t);try{n=new r(this.#t,{timeout:3e4}),To(n)}catch(i){throw new Error(`Failed to create fresh DB after deleting corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw s}this.#e=n,this.#H(),this.#Z()}cleanup(){try{this.#e.close()}catch{}for(let e of["","-wal","-shm"])try{$y(this.#t+e)}catch{}}#H(){this.#e.exec(`
|
|
150
150
|
CREATE TABLE IF NOT EXISTS sources (
|
|
151
151
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
152
152
|
label TEXT NOT NULL,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{createRequire as Y}from"node:module";import{existsSync as G,unlinkSync as x,renameSync as q}from"node:fs";import{tmpdir as z}from"node:os";import{join as K}from"node:path";var N=class{#t;constructor(t){this.#t=t}pragma(t){let s=this.#t.prepare(`PRAGMA ${t}`).all();if(!s||s.length===0)return;if(s.length>1)return s;let r=Object.values(s[0]);return r.length===1?r[0]:s[0]}exec(t){let e="",s=null;for(let
|
|
1
|
+
import{createRequire as Y}from"node:module";import{existsSync as G,unlinkSync as x,renameSync as q}from"node:fs";import{tmpdir as z}from"node:os";import{join as K}from"node:path";var N=class{#t;constructor(t){this.#t=t}pragma(t){let s=this.#t.prepare(`PRAGMA ${t}`).all();if(!s||s.length===0)return;if(s.length>1)return s;let r=Object.values(s[0]);return r.length===1?r[0]:s[0]}exec(t){let e="",s=null;for(let a=0;a<t.length;a++){let o=t[a];if(s)e+=o,o===s&&(s=null);else if(o==="'"||o==='"')e+=o,s=o;else if(o===";"){let c=e.trim();c&&this.#t.prepare(c).run(),e=""}else e+=o}let r=e.trim();return r&&this.#t.prepare(r).run(),this}prepare(t){let e=this.#t.prepare(t);return{run:(...s)=>e.run(...s),get:(...s)=>{let r=e.get(...s);return r===null?void 0:r},all:(...s)=>e.all(...s),iterate:(...s)=>e.iterate(...s)}}transaction(t){return this.#t.transaction(t)}close(){this.#t.close()}},D=class{#t;constructor(t){this.#t=t}pragma(t){let s=this.#t.prepare(`PRAGMA ${t}`).all();if(!s||s.length===0)return;if(s.length>1)return s;let r=Object.values(s[0]);return r.length===1?r[0]:s[0]}exec(t){return this.#t.exec(t),this}prepare(t){let e=this.#t.prepare(t);return{run:(...s)=>e.run(...s),get:(...s)=>e.get(...s),all:(...s)=>e.all(...s),iterate:(...s)=>typeof e.iterate=="function"?e.iterate(...s):e.all(...s)[Symbol.iterator]()}}transaction(t){return(...e)=>{this.#t.exec("BEGIN");try{let s=t(...e);return this.#t.exec("COMMIT"),s}catch(s){throw this.#t.exec("ROLLBACK"),s}}}close(){this.#t.close()}},l=null;function V(n){let t=null;try{return t=new n(":memory:"),t.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{t?.close()}catch{}}}function Q(n,t){let e=t!==void 0?t:globalThis.Bun;if(typeof e<"u"&&e!==null)return!0;let s=n??process.versions,[r,a]=(s.node??"0.0.0").split("."),o=Number(r),c=Number(a);return!Number.isFinite(o)||!Number.isFinite(c)?!1:o>22||o===22&&c>=5}function J(){if(!l){let n=Y(import.meta.url);if(globalThis.Bun){let t=n(["bun","sqlite"].join(":")).Database;l=function(s,r){let a=new t(s,{readonly:r?.readonly,create:!0}),o=new N(a);return r?.timeout&&o.pragma(`busy_timeout = ${r.timeout}`),o}}else if(Q()){let t=null;try{({DatabaseSync:t}=n(["node","sqlite"].join(":")))}catch{t=null}t&&V(t)?l=function(s,r){let a=new t(s,{readOnly:r?.readonly??!1}),o=new D(a);return r?.timeout&&o.pragma(`busy_timeout = ${r.timeout}`),o}:l=n("better-sqlite3")}else l=n("better-sqlite3")}return l}function U(n){n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL");try{n.pragma("mmap_size = 268435456")}catch{}}function I(n){if(!G(n))for(let t of["-wal","-shm"])try{x(n+t)}catch{}}function Z(n){for(let t of["","-wal","-shm"])try{x(n+t)}catch{}}function A(n){try{n.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{n.close()}catch{}}function M(n="context-mode"){return K(z(),`${n}-${process.pid}.db`)}function tt(n,t=[100,500,2e3]){let e;for(let s=0;s<=t.length;s++)try{return n()}catch(r){let a=r instanceof Error?r.message:String(r);if(!a.includes("SQLITE_BUSY")&&!a.includes("database is locked"))throw r;if(e=r instanceof Error?r:new Error(a),s<t.length){let o=t[s],c=Date.now();for(;Date.now()-c<o;);}}throw new Error(`SQLITE_BUSY: database is locked after ${t.length} retries. Original error: ${e?.message}`)}function et(n){return n.includes("SQLITE_CORRUPT")||n.includes("SQLITE_NOTADB")||n.includes("database disk image is malformed")||n.includes("file is not a database")}function st(n){let t=Date.now();for(let e of["","-wal","-shm"])try{q(n+e,`${n}${e}.corrupt-${t}`)}catch{}}var _=Symbol.for("__context_mode_live_dbs_v3__"),v=(()=>{let n=globalThis;return n[_]||(n[_]=new Set,process.on("exit",()=>{for(let t of n[_])A(t);n[_].clear()})),n[_]})(),y=class{#t;#e;constructor(t){let e=J();this.#t=t,I(t);let s;try{s=new e(t,{timeout:3e4}),U(s)}catch(r){let a=r instanceof Error?r.message:String(r);if(et(a)){st(t),I(t);try{s=new e(t,{timeout:3e4}),U(s)}catch(o){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${o instanceof Error?o.message:String(o)}`)}}else throw r}this.#e=s,v.add(this.#e),this.initSchema(),this.prepareStatements()}get db(){return this.#e}get dbPath(){return this.#t}close(){v.delete(this.#e),A(this.#e)}withRetry(t){return tt(t)}cleanup(){v.delete(this.#e),A(this.#e),Z(this.#t)}};import{createHash as p}from"node:crypto";import{execFileSync as nt}from"node:child_process";import{existsSync as f,realpathSync as rt,renameSync as C}from"node:fs";import{join as b}from"node:path";var E;function g(n){let t=n.replace(/\\/g,"/");return/^\/+$/.test(t)?"/":/^[A-Za-z]:\/+$/.test(t)?`${t.slice(0,2)}/`:t.replace(/\/+$/,"")}function F(n){let t=n;try{t=rt.native(n)}catch{}let e=g(t);return process.platform==="win32"||process.platform==="darwin"?e.toLowerCase():e}function k(n,t){return nt("git",["-C",n,...t],{encoding:"utf-8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}function it(n){let t=k(n,["rev-parse","--show-toplevel"]);return t.length>0?g(t):null}function ot(n){let t=k(n,["worktree","list","--porcelain"]).split(/\r?\n/).find(e=>e.startsWith("worktree "))?.replace("worktree ","")?.trim();return t?g(t):null}function at(n=process.cwd()){let t=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(E&&E.projectDir===n&&E.envSuffix===t)return E.suffix;let e="";if(t!==void 0)e=t?`__${t}`:"";else try{let s=it(n),r=ot(n);if(s&&r){let a=F(s),o=F(r);a!==o&&(e=`__${p("sha256").update(a).digest("hex").slice(0,8)}`)}}catch{}return E={projectDir:n,envSuffix:t,suffix:e},e}function ht(){E=void 0}function X(n){return p("sha256").update(g(n)).digest("hex").slice(0,16)}function W(n){let t=g(n),e=process.platform==="darwin"||process.platform==="win32"?t.toLowerCase():t;return p("sha256").update(e).digest("hex").slice(0,16)}function ft(n){let{projectDir:t,contentDir:e}=n,s=W(t),r=b(e,`${s}.db`);if(f(r))return r;let a=X(t);if(a===s)return r;let o=b(e,`${a}.db`);if(f(o))try{C(o,r);for(let c of["-wal","-shm"])try{C(o+c,r+c)}catch{}}catch{}return r}function bt(n){return ct({...n,ext:".db"})}function ct(n){let{projectDir:t,sessionsDir:e,ext:s}=n,r=n.suffix??at(t),a=W(t),o=b(e,`${a}${r}${s}`);if(f(o))return o;let c=X(t);if(c===a)return o;let d=b(e,`${c}${r}${s}`);if(f(d))try{C(d,o)}catch{}return o}var B=1e3,P=5;function h(n){let t=Number(n);return!Number.isFinite(t)||t<=0?0:Math.floor(t)}var i={insertEvent:"insertEvent",getEvents:"getEvents",getEventsByType:"getEventsByType",getEventsByPriority:"getEventsByPriority",getEventsByTypeAndPriority:"getEventsByTypeAndPriority",getEventCount:"getEventCount",getLatestAttributedProject:"getLatestAttributedProject",checkDuplicate:"checkDuplicate",evictLowestPriority:"evictLowestPriority",updateMetaLastEvent:"updateMetaLastEvent",ensureSession:"ensureSession",getSessionStats:"getSessionStats",incrementCompactCount:"incrementCompactCount",upsertResume:"upsertResume",getResume:"getResume",markResumeConsumed:"markResumeConsumed",claimLatestUnconsumedResume:"claimLatestUnconsumedResume",deleteEvents:"deleteEvents",deleteMeta:"deleteMeta",deleteResume:"deleteResume",getOldSessions:"getOldSessions",searchEvents:"searchEvents",incrementToolCall:"incrementToolCall",getToolCallTotals:"getToolCallTotals",getToolCallByTool:"getToolCallByTool",getEventBytesSummary:"getEventBytesSummary"},j=class extends y{constructor(t){super(t?.dbPath??M("session"))}stmt(t){return this.stmts.get(t)}initSchema(){try{let e=this.db.pragma("table_xinfo(session_events)").find(s=>s.name==="data_hash");e&&e.hidden!==0&&this.db.exec("DROP TABLE session_events")}catch{}this.db.exec(`
|
|
2
2
|
CREATE TABLE IF NOT EXISTS session_events (
|
|
3
3
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
4
|
session_id TEXT NOT NULL,
|
|
@@ -116,4 +116,4 @@ import{createRequire as Y}from"node:module";import{existsSync as G,unlinkSync as
|
|
|
116
116
|
FROM tool_calls WHERE session_id = ?`),t(i.getToolCallByTool,`SELECT tool, calls, bytes_returned
|
|
117
117
|
FROM tool_calls WHERE session_id = ? ORDER BY calls DESC`),t(i.getEventBytesSummary,`SELECT COALESCE(SUM(bytes_avoided), 0) AS bytes_avoided,
|
|
118
118
|
COALESCE(SUM(bytes_returned), 0) AS bytes_returned
|
|
119
|
-
FROM session_events WHERE session_id = ?`)}insertEvent(t,e,s="PostToolUse",r,
|
|
119
|
+
FROM session_events WHERE session_id = ?`)}insertEvent(t,e,s="PostToolUse",r,a){let o=p("sha256").update(e.data).digest("hex").slice(0,16).toUpperCase(),c=String(r?.projectDir??e.project_dir??this._getSessionProjectDir(t)).trim(),d=String(r?.source??e.attribution_source??"unknown"),u=Number(r?.confidence??e.attribution_confidence??0),T=Number.isFinite(u)?Math.max(0,Math.min(1,u)):0,m=h(a?.bytesAvoided),S=h(a?.bytesReturned),L=this.db.transaction(()=>{if(this.stmt(i.checkDuplicate).get(t,P,e.type,o))return;this.stmt(i.getEventCount).get(t).cnt>=B&&this.stmt(i.evictLowestPriority).run(t),this.stmt(i.insertEvent).run(t,e.type,e.category,e.priority,e.data,c,d,T,m,S,s,o),this.stmt(i.updateMetaLastEvent).run(t)});this.withRetry(()=>L())}bulkInsertEvents(t,e,s="PostToolUse",r,a){if(!e||e.length===0)return;if(e.length===1){this.insertEvent(t,e[0],s,r?.[0],a?.[0]);return}let o=e.map((d,u)=>{let T=p("sha256").update(d.data).digest("hex").slice(0,16).toUpperCase(),m=r?.[u],S=String(m?.projectDir??d.project_dir??this._getSessionProjectDir(t)??"").trim(),L=String(m?.source??d.attribution_source??"unknown"),R=Number(m?.confidence??d.attribution_confidence??0),O=Number.isFinite(R)?Math.max(0,Math.min(1,R)):0,w=a?.[u],H=h(w?.bytesAvoided),$=h(w?.bytesReturned);return{event:d,dataHash:T,projectDir:S,attributionSource:L,attributionConfidence:O,bytesAvoided:H,bytesReturned:$}}),c=this.db.transaction(()=>{let d=this.stmt(i.getEventCount).get(t).cnt;for(let u of o)this.stmt(i.checkDuplicate).get(t,P,u.event.type,u.dataHash)||(d>=B?this.stmt(i.evictLowestPriority).run(t):d++,this.stmt(i.insertEvent).run(t,u.event.type,u.event.category,u.event.priority,u.event.data,u.projectDir,u.attributionSource,u.attributionConfidence,u.bytesAvoided,u.bytesReturned,s,u.dataHash));this.stmt(i.updateMetaLastEvent).run(t)});this.withRetry(()=>c())}getEvents(t,e){let s=e?.limit??1e3,r=e?.type,a=e?.minPriority;return r&&a!==void 0?this.stmt(i.getEventsByTypeAndPriority).all(t,r,a,s):r?this.stmt(i.getEventsByType).all(t,r,s):a!==void 0?this.stmt(i.getEventsByPriority).all(t,a,s):this.stmt(i.getEvents).all(t,s)}getEventCount(t){return this.stmt(i.getEventCount).get(t).cnt}getEventBytesSummary(t){let e=this.stmt(i.getEventBytesSummary).get(t);return{bytesAvoided:Number(e?.bytes_avoided??0),bytesReturned:Number(e?.bytes_returned??0)}}getLatestAttributedProjectDir(t){return this.stmt(i.getLatestAttributedProject).get(t)?.project_dir||null}_getSessionProjectDir(t){try{return this.db.prepare("SELECT project_dir FROM session_meta WHERE session_id = ?").get(t)?.project_dir||""}catch{return""}}searchEvents(t,e,s,r){try{let a=t.replace(/[%_]/g,c=>"\\"+c),o=r??null;return this.stmt(i.searchEvents).all(s,a,a,o,o,e)}catch{return[]}}ensureSession(t,e){this.stmt(i.ensureSession).run(t,e)}getSessionStats(t){return this.stmt(i.getSessionStats).get(t)??null}incrementCompactCount(t){this.stmt(i.incrementCompactCount).run(t)}upsertResume(t,e,s){this.stmt(i.upsertResume).run(t,e,s??0)}getResume(t){return this.stmt(i.getResume).get(t)??null}markResumeConsumed(t){this.stmt(i.markResumeConsumed).run(t)}claimLatestUnconsumedResume(t){let e=this.stmt(i.claimLatestUnconsumedResume).get(t);return e?{sessionId:e.session_id,snapshot:e.snapshot}:null}getLatestSessionId(){try{return this.db.prepare("SELECT session_id FROM session_meta ORDER BY started_at DESC LIMIT 1").get()?.session_id??null}catch{return null}}incrementToolCall(t,e,s=0){let r=Number.isFinite(s)&&s>0?Math.round(s):0;try{this.stmt(i.incrementToolCall).run(t,e,r)}catch{}}getToolCallStats(t){try{let e=this.stmt(i.getToolCallTotals).get(t),s=this.stmt(i.getToolCallByTool).all(t),r={};for(let a of s)r[a.tool]={calls:a.calls,bytesReturned:a.bytes_returned};return{totalCalls:e?.calls??0,totalBytesReturned:e?.bytes_returned??0,byTool:r}}catch{return{totalCalls:0,totalBytesReturned:0,byTool:{}}}}deleteSession(t){this.db.transaction(()=>{this.stmt(i.deleteEvents).run(t),this.stmt(i.deleteResume).run(t),this.stmt(i.deleteMeta).run(t)})()}cleanupOldSessions(t=7){let e=`-${t}`,s=this.stmt(i.getOldSessions).all(e);for(let{session_id:r}of s)this.deleteSession(r);return s.length}};export{j as SessionDB,ht as _resetWorktreeSuffixCacheForTests,at as getWorktreeSuffix,W as hashProjectDirCanonical,X as hashProjectDirLegacy,g as normalizeWorktreePath,ft as resolveContentStorePath,bt as resolveSessionDbPath,ct as resolveSessionPath};
|
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.143",
|
|
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.143",
|
|
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",
|
package/server.bundle.mjs
CHANGED
|
@@ -142,7 +142,7 @@ file_content = File.read!(file_content_path)
|
|
|
142
142
|
${n}`;case"csharp":return`var FILE_CONTENT_PATH = ${o};
|
|
143
143
|
var file_path = FILE_CONTENT_PATH;
|
|
144
144
|
var FILE_CONTENT = System.IO.File.ReadAllText(FILE_CONTENT_PATH);
|
|
145
|
-
${n}`}}};import{cpus as IN}from"node:os";async function Vf(t,e){let{concurrency:r,capByCpuCount:n=!1,onSettled:o}=e;if(t.length===0)return{settled:[],effectiveConcurrency:0,capped:!1};let s=Math.max(1,r),i=n?Math.max(1,IN().length):s,a=Math.min(s,i,t.length),c=a<s,u=new Array(t.length),d=0;async function l(){for(;;){let m=d++;if(m>=t.length)return;try{let p=await t[m].run();u[m]={status:"fulfilled",value:p}}catch(p){u[m]={status:"rejected",reason:p}}o?.(m,u[m])}}let f=[];for(let m=0;m<a;m++)f.push(l());return await Promise.allSettled(f),{settled:u,effectiveConcurrency:a,capped:c}}import{createRequire as AN}from"node:module";import{existsSync as NN,unlinkSync as jb,renameSync as DN}from"node:fs";import{tmpdir as MN}from"node:os";import{join as jN}from"node:path";var Kf=class{#e;constructor(e){this.#e=e}pragma(e){let n=this.#e.prepare(`PRAGMA ${e}`).all();if(!n||n.length===0)return;if(n.length>1)return n;let o=Object.values(n[0]);return o.length===1?o[0]:n[0]}exec(e){let r="",n=null;for(let s=0;s<e.length;s++){let i=e[s];if(n)r+=i,i===n&&(n=null);else if(i==="'"||i==='"')r+=i,n=i;else if(i===";"){let a=r.trim();a&&this.#e.prepare(a).run(),r=""}else r+=i}let o=r.trim();return o&&this.#e.prepare(o).run(),this}prepare(e){let r=this.#e.prepare(e);return{run:(...n)=>r.run(...n),get:(...n)=>{let o=r.get(...n);return o===null?void 0:o},all:(...n)=>r.all(...n),iterate:(...n)=>r.iterate(...n)}}transaction(e){return this.#e.transaction(e)}close(){this.#e.close()}},Gf=class{#e;constructor(e){this.#e=e}pragma(e){let n=this.#e.prepare(`PRAGMA ${e}`).all();if(!n||n.length===0)return;if(n.length>1)return n;let o=Object.values(n[0]);return o.length===1?o[0]:n[0]}exec(e){return this.#e.exec(e),this}prepare(e){let r=this.#e.prepare(e);return{run:(...n)=>r.run(...n),get:(...n)=>r.get(...n),all:(...n)=>r.all(...n),iterate:(...n)=>typeof r.iterate=="function"?r.iterate(...n):r.all(...n)[Symbol.iterator]()}}transaction(e){return(...r)=>{this.#e.exec("BEGIN");try{let n=e(...r);return this.#e.exec("COMMIT"),n}catch(n){throw this.#e.exec("ROLLBACK"),n}}}close(){this.#e.close()}},Mo=null;function zN(t){let e=null;try{return e=new t(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function LN(t,e){let r=e!==void 0?e:globalThis.Bun;if(typeof r<"u"&&r!==null)return!0;let n=t??process.versions,[o,s]=(n.node??"0.0.0").split("."),i=Number(o),a=Number(s);return!Number.isFinite(i)||!Number.isFinite(a)?!1:i>22||i===22&&a>=5}function tt(){if(!Mo){let t=AN(import.meta.url);if(globalThis.Bun){let e=t(["bun","sqlite"].join(":")).Database;Mo=function(n,o){let s=new e(n,{readonly:o?.readonly,create:!0}),i=new Kf(s);return o?.timeout&&i.pragma(`busy_timeout = ${o.timeout}`),i}}else if(LN()){let e=null;try{({DatabaseSync:e}=t(["node","sqlite"].join(":")))}catch{e=null}e&&zN(e)?Mo=function(n,o){let s=new e(n,{readOnly:o?.readonly??!1})
|
|
145
|
+
${n}`}}};import{cpus as IN}from"node:os";async function Vf(t,e){let{concurrency:r,capByCpuCount:n=!1,onSettled:o}=e;if(t.length===0)return{settled:[],effectiveConcurrency:0,capped:!1};let s=Math.max(1,r),i=n?Math.max(1,IN().length):s,a=Math.min(s,i,t.length),c=a<s,u=new Array(t.length),d=0;async function l(){for(;;){let m=d++;if(m>=t.length)return;try{let p=await t[m].run();u[m]={status:"fulfilled",value:p}}catch(p){u[m]={status:"rejected",reason:p}}o?.(m,u[m])}}let f=[];for(let m=0;m<a;m++)f.push(l());return await Promise.allSettled(f),{settled:u,effectiveConcurrency:a,capped:c}}import{createRequire as AN}from"node:module";import{existsSync as NN,unlinkSync as jb,renameSync as DN}from"node:fs";import{tmpdir as MN}from"node:os";import{join as jN}from"node:path";var Kf=class{#e;constructor(e){this.#e=e}pragma(e){let n=this.#e.prepare(`PRAGMA ${e}`).all();if(!n||n.length===0)return;if(n.length>1)return n;let o=Object.values(n[0]);return o.length===1?o[0]:n[0]}exec(e){let r="",n=null;for(let s=0;s<e.length;s++){let i=e[s];if(n)r+=i,i===n&&(n=null);else if(i==="'"||i==='"')r+=i,n=i;else if(i===";"){let a=r.trim();a&&this.#e.prepare(a).run(),r=""}else r+=i}let o=r.trim();return o&&this.#e.prepare(o).run(),this}prepare(e){let r=this.#e.prepare(e);return{run:(...n)=>r.run(...n),get:(...n)=>{let o=r.get(...n);return o===null?void 0:o},all:(...n)=>r.all(...n),iterate:(...n)=>r.iterate(...n)}}transaction(e){return this.#e.transaction(e)}close(){this.#e.close()}},Gf=class{#e;constructor(e){this.#e=e}pragma(e){let n=this.#e.prepare(`PRAGMA ${e}`).all();if(!n||n.length===0)return;if(n.length>1)return n;let o=Object.values(n[0]);return o.length===1?o[0]:n[0]}exec(e){return this.#e.exec(e),this}prepare(e){let r=this.#e.prepare(e);return{run:(...n)=>r.run(...n),get:(...n)=>r.get(...n),all:(...n)=>r.all(...n),iterate:(...n)=>typeof r.iterate=="function"?r.iterate(...n):r.all(...n)[Symbol.iterator]()}}transaction(e){return(...r)=>{this.#e.exec("BEGIN");try{let n=e(...r);return this.#e.exec("COMMIT"),n}catch(n){throw this.#e.exec("ROLLBACK"),n}}}close(){this.#e.close()}},Mo=null;function zN(t){let e=null;try{return e=new t(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function LN(t,e){let r=e!==void 0?e:globalThis.Bun;if(typeof r<"u"&&r!==null)return!0;let n=t??process.versions,[o,s]=(n.node??"0.0.0").split("."),i=Number(o),a=Number(s);return!Number.isFinite(i)||!Number.isFinite(a)?!1:i>22||i===22&&a>=5}function tt(){if(!Mo){let t=AN(import.meta.url);if(globalThis.Bun){let e=t(["bun","sqlite"].join(":")).Database;Mo=function(n,o){let s=new e(n,{readonly:o?.readonly,create:!0}),i=new Kf(s);return o?.timeout&&i.pragma(`busy_timeout = ${o.timeout}`),i}}else if(LN()){let e=null;try{({DatabaseSync:e}=t(["node","sqlite"].join(":")))}catch{e=null}e&&zN(e)?Mo=function(n,o){let s=new e(n,{readOnly:o?.readonly??!1}),i=new Gf(s);return o?.timeout&&i.pragma(`busy_timeout = ${o.timeout}`),i}:Mo=t("better-sqlite3")}else Mo=t("better-sqlite3")}return Mo}function ai(t){t.pragma("journal_mode = WAL"),t.pragma("synchronous = NORMAL");try{t.pragma("mmap_size = 268435456")}catch{}}function ci(t){if(!NN(t))for(let e of["-wal","-shm"])try{jb(t+e)}catch{}}function Jf(t){for(let e of["","-wal","-shm"])try{jb(t+e)}catch{}}function ui(t){try{t.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{t.close()}catch{}}function zb(t="context-mode"){return jN(MN(),`${t}-${process.pid}.db`)}function jn(t,e=[100,500,2e3]){let r;for(let n=0;n<=e.length;n++)try{return t()}catch(o){let s=o instanceof Error?o.message:String(o);if(!s.includes("SQLITE_BUSY")&&!s.includes("database is locked"))throw o;if(r=o instanceof Error?o:new Error(s),n<e.length){let i=e[n],a=Date.now();for(;Date.now()-a<i;);}}throw new Error(`SQLITE_BUSY: database is locked after ${e.length} retries. Original error: ${r?.message}`)}function Yf(t){return t.includes("SQLITE_CORRUPT")||t.includes("SQLITE_NOTADB")||t.includes("database disk image is malformed")||t.includes("file is not a database")}function UN(t){let e=Date.now();for(let r of["","-wal","-shm"])try{DN(t+r,`${t}${r}.corrupt-${e}`)}catch{}}var ii=Symbol.for("__context_mode_live_dbs_v3__"),Wf=(()=>{let t=globalThis;return t[ii]||(t[ii]=new Set,process.on("exit",()=>{for(let e of t[ii])ui(e);t[ii].clear()})),t[ii]})(),_c=class{#e;#t;constructor(e){let r=tt();this.#e=e,ci(e);let n;try{n=new r(e,{timeout:3e4}),ai(n)}catch(o){let s=o instanceof Error?o.message:String(o);if(Yf(s)){UN(e),ci(e);try{n=new r(e,{timeout:3e4}),ai(n)}catch(i){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw o}this.#t=n,Wf.add(this.#t),this.initSchema(),this.prepareStatements()}get db(){return this.#t}get dbPath(){return this.#e}close(){Wf.delete(this.#t),ui(this.#t)}withRetry(e){return jn(e)}cleanup(){Wf.delete(this.#t),ui(this.#t),Jf(this.#e)}};import{readFileSync as Lb,readdirSync as qb,unlinkSync as Qf,existsSync as Xf,statSync as xc,openSync as Ub,fstatSync as Hb,closeSync as Fb}from"node:fs";import{createHash as Zb}from"node:crypto";import{tmpdir as Vb}from"node:os";import{join as em}from"node:path";var jo=new Set(["the","and","for","are","but","not","you","all","can","had","her","was","one","our","out","has","his","how","its","may","new","now","old","see","way","who","did","get","got","let","say","she","too","use","will","with","this","that","from","they","been","have","many","some","them","than","each","make","like","just","over","such","take","into","year","your","good","could","would","about","which","their","there","other","after","should","through","also","more","most","only","very","when","what","then","these","those","being","does","done","both","same","still","while","where","here","were","much","update","updates","updated","deps","dev","tests","test","add","added","fix","fixed","run","running","using"]);function Wb(t){let e=new Set,r=[];for(let n of t){let o=n.toLowerCase();e.has(o)||(e.add(o),r.push(n))}return r}function HN(t,e="AND"){let r=Wb(t.replace(/['"(){}[\]*:^~]/g," ").split(/\s+/).filter(s=>s.length>0&&!["AND","OR","NOT","NEAR"].includes(s.toUpperCase())));if(r.length===0)return'""';let n=r.filter(s=>!jo.has(s.toLowerCase()));return(n.length>0?n:r).map(s=>`"${s}"`).join(e==="OR"?" OR ":" ")}function FN(t,e="AND"){let r=t.replace(/["'(){}[\]*:^~]/g,"").trim();if(r.length<3)return"";let n=Wb(r.split(/\s+/).filter(i=>i.length>=3));if(n.length===0)return"";let o=n.filter(i=>!jo.has(i.toLowerCase()));return(o.length>0?o:n).map(i=>`"${i}"`).join(e==="OR"?" OR ":" ")}function ZN(t,e){if(t.length===0)return e.length;if(e.length===0)return t.length;let r=Array.from({length:e.length+1},(n,o)=>o);for(let n=1;n<=t.length;n++){let o=[n];for(let s=1;s<=e.length;s++)o[s]=t[n-1]===e[s-1]?r[s-1]:1+Math.min(r[s],o[s-1],r[s-1]);r=o}return r[e.length]}function BN(t){return t<=4?1:t<=12?2:3}var Bb=4096;function tm(){let t=Vb(),e=0;try{let r=qb(t);for(let n of r){let o=n.match(/^context-mode-(\d+)\.db$/);if(!o)continue;let s=parseInt(o[1],10);if(s!==process.pid)try{process.kill(s,0)}catch{let i=em(t,n);for(let a of["","-wal","-shm"])try{Qf(i+a)}catch{}e++}}}catch{}return e}function rm(t,e){let r=0;try{if(!Xf(t))return 0;let n=Date.now()-e*24*60*60*1e3,o=qb(t).filter(s=>s.endsWith(".db"));for(let s of o)try{let i=em(t,s),c=xc(i).mtimeMs<n;if(!c){let u=i+"-wal";if(Xf(u))try{let d=xc(u);d.size>0&&Date.now()-d.mtimeMs>36e5&&(c=!0)}catch{}}if(c){for(let u of["","-wal","-shm"])try{Qf(i+u)}catch{}r++}}catch{}}catch{}return r}function qN(t,e){let r=[],n=t.indexOf(e);for(;n!==-1;)r.push(n),n=t.indexOf(e,n+1);return r}function VN(t,e,r=30){if(t.length<2||e.length<2)return 0;let n=0,o=Math.min(t.length,e.length)-1;for(let s=0;s<o;s++){let i=t[s],a=t[s+1],c=e[s].length,u=0;for(let d of i){let l=d+c,f=l+r;for(;u<a.length&&a[u]<l;)u++;u<a.length&&a[u]<=f&&(n++,u++)}}return n}function WN(t){if(t.length===0)return 1/0;if(t.length===1)return 0;let e=t.map(o=>[...o].sort((s,i)=>s-i)),r=new Array(e.length).fill(0),n=1/0;for(;;){let o=1/0,s=-1/0,i=0;for(let c=0;c<e.length;c++){let u=e[c][r[c]];u<o&&(o=u,i=c),u>s&&(s=u)}let a=s-o;if(a<n&&(n=a),r[i]++,r[i]>=e[i].length)break}return n}var vc=class t{#e;#t;#n;#s;#o;#a;#c;#i;#u;#l;#f;#m;#h;#g;#y;#_;#x;#v;#b;#S;#k;#E;#w;#T;#P;#R;#$;#C;#O;#I;#A;#N;#D;#M=0;static OPTIMIZE_EVERY=50;#r=new Map;static FUZZY_CACHE_SIZE=256;constructor(e){let r=tt();this.#t=e??em(Vb(),`context-mode-${process.pid}.db`),ci(this.#t);let n;try{n=new r(this.#t,{timeout:3e4}),ai(n)}catch(o){let s=o instanceof Error?o.message:String(o);if(Yf(s)){Jf(this.#t),ci(this.#t);try{n=new r(this.#t,{timeout:3e4}),ai(n)}catch(i){throw new Error(`Failed to create fresh DB after deleting corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw o}this.#e=n,this.#F(),this.#Z()}cleanup(){try{this.#e.close()}catch{}for(let e of["","-wal","-shm"])try{Qf(this.#t+e)}catch{}}#F(){this.#e.exec(`
|
|
146
146
|
CREATE TABLE IF NOT EXISTS sources (
|
|
147
147
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
148
148
|
label TEXT NOT NULL,
|
package/start.mjs
CHANGED
|
@@ -364,16 +364,47 @@ if (!process.env.VITEST) {
|
|
|
364
364
|
// Ensure native dependencies + ABI compatibility (shared with hooks via ensure-deps.mjs)
|
|
365
365
|
// ensure-deps handles better-sqlite3 install + ABI cache/rebuild automatically (#148, #203)
|
|
366
366
|
import "./hooks/ensure-deps.mjs";
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
367
|
+
// Pure-JS runtime deps used only by `ctx_fetch_and_index` (HTML → Markdown
|
|
368
|
+
// pipeline runs in a sandboxed subprocess that `require.resolve()`s these at
|
|
369
|
+
// call time). Plugin distributions that bypass `npm install` — most notably
|
|
370
|
+
// codex's marketplace, which git-clones into `~/.codex/plugins/cache/<pkg>/`
|
|
371
|
+
// without installing dependencies — land here with no `node_modules/`.
|
|
372
|
+
//
|
|
373
|
+
// Before #634: synchronous `execSync("npm install …")` per package
|
|
374
|
+
// (turndown + turndown-plugin-gfm + @mixmark-io/domino) blocked MCP boot
|
|
375
|
+
// for ~15–25s cold. Codex's per-MCP `startup_timeout_sec` is 30s, so on
|
|
376
|
+
// any host where its prewarm + DNS already eats a few seconds the timer
|
|
377
|
+
// fires before context-mode replies to `initialize` and the MCP child is
|
|
378
|
+
// dropped with "MCP client for `context-mode` timed out after 30 seconds".
|
|
379
|
+
//
|
|
380
|
+
// Fix: spawn each `npm install` detached + unref'd so it runs in the
|
|
381
|
+
// background while the MCP server proceeds with its handshake. The deps
|
|
382
|
+
// land asynchronously, well before any LLM-driven `ctx_fetch_and_index`
|
|
383
|
+
// call can plausibly fire. If a user invokes that tool faster than the
|
|
384
|
+
// install completes, the subprocess's own `require.resolve("turndown")`
|
|
385
|
+
// failure surfaces a typed error to the caller — same posture as any
|
|
386
|
+
// other missing-runtime-dep situation in that code path.
|
|
387
|
+
{
|
|
388
|
+
const NPM_INSTALL_BG_PKGS = ["turndown", "turndown-plugin-gfm", "@mixmark-io/domino"];
|
|
389
|
+
const IS_WIN32 = process.platform === "win32";
|
|
390
|
+
const NPM_BIN = IS_WIN32 ? "npm.cmd" : "npm";
|
|
391
|
+
for (const pkg of NPM_INSTALL_BG_PKGS) {
|
|
392
|
+
if (existsSync(resolve(__dirname, "node_modules", pkg))) continue;
|
|
370
393
|
try {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
394
|
+
const child = spawn(
|
|
395
|
+
NPM_BIN,
|
|
396
|
+
["install", pkg, "--no-package-lock", "--no-save", "--silent", "--no-audit", "--no-fund"],
|
|
397
|
+
{
|
|
398
|
+
cwd: __dirname,
|
|
399
|
+
stdio: "ignore",
|
|
400
|
+
detached: true,
|
|
401
|
+
// npm on Windows ships as a `.cmd` shim — must go through cmd.exe.
|
|
402
|
+
shell: IS_WIN32,
|
|
403
|
+
},
|
|
404
|
+
);
|
|
405
|
+
child.on("error", () => { /* best effort — npm missing, broken cache, etc. */ });
|
|
406
|
+
child.unref();
|
|
407
|
+
} catch { /* best effort — never block MCP boot */ }
|
|
377
408
|
}
|
|
378
409
|
}
|
|
379
410
|
|