context-mode 1.0.142 → 1.0.144
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/pi/mcp-bridge.js +36 -12
- package/build/db-base.js +12 -1
- package/build/openclaw-plugin.d.ts +130 -0
- package/build/openclaw-plugin.js +626 -0
- package/build/opencode-plugin.d.ts +122 -0
- package/build/opencode-plugin.js +372 -0
- package/build/pi-extension.d.ts +14 -0
- package/build/pi-extension.js +451 -0
- package/build/server.d.ts +35 -0
- package/build/server.js +49 -1
- package/build/util/db-lock.d.ts +65 -0
- package/build/util/db-lock.js +166 -0
- package/cli.bundle.mjs +104 -104
- package/hooks/pretooluse.mjs +9 -1
- package/hooks/session-db.bundle.mjs +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +80 -80
|
@@ -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.144"
|
|
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.144",
|
|
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.144",
|
|
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.144",
|
|
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.144",
|
|
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.144",
|
|
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",
|
|
@@ -92,10 +92,16 @@ export function resolveJsRuntimeForBridge(deps = {}) {
|
|
|
92
92
|
return execPath;
|
|
93
93
|
return null;
|
|
94
94
|
}
|
|
95
|
+
// Bridge-imposed timeout for protocol-handshake methods (initialize,
|
|
96
|
+
// tools/list). These MUST be bounded: a server that never replies to
|
|
97
|
+
// initialize would otherwise block Pi's bridge bootstrap indefinitely.
|
|
98
|
+
// `tools/call` deliberately has NO bridge ceiling (#643) — long-running
|
|
99
|
+
// ctx_execute (test suites, builds, cargo test) was rejected by a 120s
|
|
100
|
+
// hardcoded bound even though the executor child would have finished.
|
|
101
|
+
// Responsibility for bounding a tool call belongs to the executor
|
|
102
|
+
// layer (per-tool timeout / background mode / Pi-level cancel), not
|
|
103
|
+
// to the transport.
|
|
95
104
|
const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
|
|
96
|
-
// Tools/call may run shell commands or fetch URLs — wider window than
|
|
97
|
-
// initialize/list, but still bounded so a hung server can't block Pi.
|
|
98
|
-
const DEFAULT_CALL_TIMEOUT_MS = 120_000;
|
|
99
105
|
class PiTextComponent {
|
|
100
106
|
text;
|
|
101
107
|
constructor(text = "") {
|
|
@@ -349,19 +355,29 @@ export class MCPStdioClient {
|
|
|
349
355
|
throw new Error("MCP client not started");
|
|
350
356
|
const id = ++this.requestId;
|
|
351
357
|
return new Promise((resolve, reject) => {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
+
// Gate the timer on a finite ms value so callers can pass
|
|
359
|
+
// `Number.POSITIVE_INFINITY` to mean "no bridge ceiling" (#643).
|
|
360
|
+
// Node coerces both `undefined` and `Infinity` to a 1ms delay
|
|
361
|
+
// (TimeoutOverflowWarning), so we can't just pass them through —
|
|
362
|
+
// we must skip the setTimeout entirely. tools/call uses this path
|
|
363
|
+
// because long-running ctx_execute must not be bounded here.
|
|
364
|
+
const timer = Number.isFinite(timeoutMs)
|
|
365
|
+
? setTimeout(() => {
|
|
366
|
+
if (!this.pending.has(id))
|
|
367
|
+
return;
|
|
368
|
+
this.pending.delete(id);
|
|
369
|
+
reject(new Error(`MCP request timeout after ${timeoutMs}ms: ${method}`));
|
|
370
|
+
}, timeoutMs)
|
|
371
|
+
: null;
|
|
358
372
|
this.pending.set(id, {
|
|
359
373
|
resolve: (v) => {
|
|
360
|
-
|
|
374
|
+
if (timer)
|
|
375
|
+
clearTimeout(timer);
|
|
361
376
|
resolve(v);
|
|
362
377
|
},
|
|
363
378
|
reject: (e) => {
|
|
364
|
-
|
|
379
|
+
if (timer)
|
|
380
|
+
clearTimeout(timer);
|
|
365
381
|
reject(e);
|
|
366
382
|
},
|
|
367
383
|
});
|
|
@@ -445,7 +461,15 @@ export class MCPStdioClient {
|
|
|
445
461
|
// one layer covers `listTools` / `initialize` paths too, with a
|
|
446
462
|
// single-flight guard against orphan child processes from
|
|
447
463
|
// concurrent callers.
|
|
448
|
-
|
|
464
|
+
//
|
|
465
|
+
// No bridge-imposed timeout for tools/call (#643). The previous
|
|
466
|
+
// 120s ceiling rejected legitimate long-running ctx_execute calls
|
|
467
|
+
// (test suites, builds, large `cargo test`) even though the
|
|
468
|
+
// executor child would have finished. Bounding belongs to the
|
|
469
|
+
// executor layer (per-tool timeout / background mode / Pi cancel),
|
|
470
|
+
// not the transport. `Number.POSITIVE_INFINITY` instructs
|
|
471
|
+
// `request()` to skip the setTimeout entirely — see the gate there.
|
|
472
|
+
return this.request("tools/call", { name, arguments: args ?? {} }, Number.POSITIVE_INFINITY);
|
|
449
473
|
}
|
|
450
474
|
/**
|
|
451
475
|
* Respawn the MCP child after an exit (clean shutdown or crash).
|
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 {
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw TypeScript plugin entry point for context-mode.
|
|
3
|
+
*
|
|
4
|
+
* Exports an object with { id, name, configSchema, register(api) } for
|
|
5
|
+
* declarative metadata and config validation before code execution.
|
|
6
|
+
*
|
|
7
|
+
* register(api) registers:
|
|
8
|
+
* - before_tool_call hook — Routing enforcement (deny/modify/passthrough)
|
|
9
|
+
* - after_tool_call hook — Session event capture
|
|
10
|
+
* - command:new hook — Session initialization and cleanup
|
|
11
|
+
* - session_start hook — Re-key DB session to OpenClaw's session ID
|
|
12
|
+
* - before_compaction hook — Flush events to resume snapshot
|
|
13
|
+
* - after_compaction hook — Increment compact count
|
|
14
|
+
* - before_prompt_build (p=10) — Resume snapshot injection into system context
|
|
15
|
+
* - before_prompt_build (p=5) — Routing instruction injection into system context
|
|
16
|
+
* - context-mode engine — Context engine with compaction management
|
|
17
|
+
* - /ctx-stats command — Auto-reply command for session statistics
|
|
18
|
+
* - /ctx-doctor command — Auto-reply command for diagnostics
|
|
19
|
+
* - /ctx-upgrade command — Auto-reply command for upgrade
|
|
20
|
+
*
|
|
21
|
+
* Loaded by OpenClaw via: openclaw.extensions entry in package.json
|
|
22
|
+
*
|
|
23
|
+
* OpenClaw plugin paradigm:
|
|
24
|
+
* - Plugins export { id, name, configSchema, register(api) } for metadata
|
|
25
|
+
* - api.registerHook() for event-driven hooks
|
|
26
|
+
* - api.on() for typed lifecycle hooks
|
|
27
|
+
* - api.registerContextEngine() for compaction ownership
|
|
28
|
+
* - api.registerCommand() for auto-reply slash commands
|
|
29
|
+
* - Plugins run in-process with the Gateway (trusted code)
|
|
30
|
+
*/
|
|
31
|
+
import type { OpenClawToolDef } from "./openclaw/mcp-tools.js";
|
|
32
|
+
/** Context for auto-reply command handlers. */
|
|
33
|
+
interface CommandContext {
|
|
34
|
+
senderId?: string;
|
|
35
|
+
channel?: string;
|
|
36
|
+
isAuthorizedSender?: boolean;
|
|
37
|
+
args?: string;
|
|
38
|
+
commandBody?: string;
|
|
39
|
+
config?: Record<string, unknown>;
|
|
40
|
+
}
|
|
41
|
+
/** OpenClaw plugin API provided to the register function. */
|
|
42
|
+
interface OpenClawPluginApi {
|
|
43
|
+
registerHook(event: string, handler: (...args: unknown[]) => unknown, meta: {
|
|
44
|
+
name: string;
|
|
45
|
+
description: string;
|
|
46
|
+
}): void;
|
|
47
|
+
/**
|
|
48
|
+
* Register a typed lifecycle hook.
|
|
49
|
+
* Supported names: "session_start", "before_compaction", "after_compaction",
|
|
50
|
+
* "before_prompt_build"
|
|
51
|
+
*/
|
|
52
|
+
on(event: string, handler: (...args: unknown[]) => unknown, opts?: {
|
|
53
|
+
priority?: number;
|
|
54
|
+
}): void;
|
|
55
|
+
registerContextEngine(id: string, factory: () => ContextEngineInstance): void;
|
|
56
|
+
registerCommand?(cmd: {
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
acceptsArgs?: boolean;
|
|
60
|
+
requireAuth?: boolean;
|
|
61
|
+
handler: (ctx: CommandContext) => {
|
|
62
|
+
text: string;
|
|
63
|
+
} | Promise<{
|
|
64
|
+
text: string;
|
|
65
|
+
}>;
|
|
66
|
+
}): void;
|
|
67
|
+
registerCli?(factory: (ctx: {
|
|
68
|
+
program: unknown;
|
|
69
|
+
}) => void, meta: {
|
|
70
|
+
commands: string[];
|
|
71
|
+
}): void;
|
|
72
|
+
/**
|
|
73
|
+
* Register an agent tool (OpenClaw native registerTool) — see
|
|
74
|
+
* refs/platforms/openclaw/docs/plugins/building-plugins.md:116. Optional in
|
|
75
|
+
* the type so we degrade silently on legacy hosts that pre-date this API.
|
|
76
|
+
*/
|
|
77
|
+
registerTool?(tool: OpenClawToolDef, opts?: {
|
|
78
|
+
optional?: boolean;
|
|
79
|
+
}): void;
|
|
80
|
+
logger?: {
|
|
81
|
+
info: (...args: unknown[]) => void;
|
|
82
|
+
error: (...args: unknown[]) => void;
|
|
83
|
+
debug?: (...args: unknown[]) => void;
|
|
84
|
+
warn?: (...args: unknown[]) => void;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Context engine instance returned by the factory. */
|
|
88
|
+
interface ContextEngineInstance {
|
|
89
|
+
info: {
|
|
90
|
+
id: string;
|
|
91
|
+
name: string;
|
|
92
|
+
ownsCompaction: boolean;
|
|
93
|
+
};
|
|
94
|
+
ingest(data: unknown): Promise<{
|
|
95
|
+
ingested: boolean;
|
|
96
|
+
}>;
|
|
97
|
+
assemble(ctx: {
|
|
98
|
+
messages: unknown[];
|
|
99
|
+
}): Promise<{
|
|
100
|
+
messages: unknown[];
|
|
101
|
+
estimatedTokens: number;
|
|
102
|
+
}>;
|
|
103
|
+
compact(): Promise<{
|
|
104
|
+
ok: boolean;
|
|
105
|
+
compacted: boolean;
|
|
106
|
+
}>;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* OpenClaw plugin definition. The object form provides declarative metadata
|
|
110
|
+
* (id, name, configSchema) that OpenClaw can read without executing code.
|
|
111
|
+
* register() is called once per agent session with a fresh api object.
|
|
112
|
+
* Each call creates isolated closures (db, sessionId, hooks) — no shared state.
|
|
113
|
+
*/
|
|
114
|
+
declare const _default: {
|
|
115
|
+
id: string;
|
|
116
|
+
name: string;
|
|
117
|
+
configSchema: {
|
|
118
|
+
type: "object";
|
|
119
|
+
properties: {
|
|
120
|
+
enabled: {
|
|
121
|
+
type: "boolean";
|
|
122
|
+
default: boolean;
|
|
123
|
+
description: string;
|
|
124
|
+
};
|
|
125
|
+
};
|
|
126
|
+
additionalProperties: boolean;
|
|
127
|
+
};
|
|
128
|
+
register(api: OpenClawPluginApi): void;
|
|
129
|
+
};
|
|
130
|
+
export default _default;
|