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.
@@ -6,14 +6,14 @@
6
6
  },
7
7
  "metadata": {
8
8
  "description": "Claude Code plugins by Mert Koseoğlu",
9
- "version": "1.0.141"
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.141",
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.141",
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.141",
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.141",
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.141",
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
- // Read package.json version once at module load (not on every hook call).
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: shape,
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
- return new NodeSQLiteAdapter(raw);
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});return new el(o)}:$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(`
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 o=0;o<t.length;o++){let a=t[o];if(s)e+=a,a===s&&(s=null);else if(a==="'"||a==='"')e+=a,s=a;else if(a===";"){let c=e.trim();c&&this.#t.prepare(c).run(),e=""}else e+=a}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,o]=(s.node??"0.0.0").split("."),a=Number(r),c=Number(o);return!Number.isFinite(a)||!Number.isFinite(c)?!1:a>22||a===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 o=new t(s,{readonly:r?.readonly,create:!0}),a=new N(o);return r?.timeout&&a.pragma(`busy_timeout = ${r.timeout}`),a}}else if(Q()){let t=null;try{({DatabaseSync:t}=n(["node","sqlite"].join(":")))}catch{t=null}t&&V(t)?l=function(s,r){let o=new t(s,{readOnly:r?.readonly??!1});return new D(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 o=r instanceof Error?r.message:String(r);if(!o.includes("SQLITE_BUSY")&&!o.includes("database is locked"))throw r;if(e=r instanceof Error?r:new Error(o),s<t.length){let a=t[s],c=Date.now();for(;Date.now()-c<a;);}}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 o=r instanceof Error?r.message:String(r);if(et(o)){st(t),I(t);try{s=new e(t,{timeout:3e4}),U(s)}catch(a){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${a instanceof Error?a.message:String(a)}`)}}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 o=F(s),a=F(r);o!==a&&(e=`__${p("sha256").update(o).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 o=X(t);if(o===s)return r;let a=b(e,`${o}.db`);if(f(a))try{C(a,r);for(let c of["-wal","-shm"])try{C(a+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),o=W(t),a=b(e,`${o}${r}${s}`);if(f(a))return a;let c=X(t);if(c===o)return a;let d=b(e,`${c}${r}${s}`);if(f(d))try{C(d,a)}catch{}return a}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(`
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,o){let a=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(o?.bytesAvoided),S=h(o?.bytesReturned),L=this.db.transaction(()=>{if(this.stmt(i.checkDuplicate).get(t,P,e.type,a))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,a),this.stmt(i.updateMetaLastEvent).run(t)});this.withRetry(()=>L())}bulkInsertEvents(t,e,s="PostToolUse",r,o){if(!e||e.length===0)return;if(e.length===1){this.insertEvent(t,e[0],s,r?.[0],o?.[0]);return}let a=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=o?.[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 a)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,o=e?.minPriority;return r&&o!==void 0?this.stmt(i.getEventsByTypeAndPriority).all(t,r,o,s):r?this.stmt(i.getEventsByType).all(t,r,s):o!==void 0?this.stmt(i.getEventsByPriority).all(t,o,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 o=t.replace(/[%_]/g,c=>"\\"+c),a=r??null;return this.stmt(i.searchEvents).all(s,o,o,a,a,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 o of s)r[o.tool]={calls:o.calls,bytesReturned:o.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};
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};
@@ -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.141",
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.141",
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});return new Gf(s)}: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(`
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
- // Also install pure-JS deps used by server
368
- for (const pkg of ["turndown", "turndown-plugin-gfm", "@mixmark-io/domino"]) {
369
- if (!existsSync(resolve(__dirname, "node_modules", pkg))) {
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
- execSync(`npm install ${pkg} --no-package-lock --no-save --silent`, {
372
- cwd: __dirname,
373
- stdio: "pipe",
374
- timeout: 120000,
375
- });
376
- } catch { /* best effort */ }
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