context-mode 1.0.54 → 1.0.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +20 -6
- package/build/adapters/antigravity/index.d.ts +1 -3
- package/build/adapters/antigravity/index.js +0 -30
- package/build/adapters/claude-code/index.d.ts +1 -3
- package/build/adapters/claude-code/index.js +15 -34
- package/build/adapters/codex/index.d.ts +1 -3
- package/build/adapters/codex/index.js +1 -31
- package/build/adapters/cursor/index.d.ts +1 -3
- package/build/adapters/cursor/index.js +0 -11
- package/build/adapters/gemini-cli/index.d.ts +1 -3
- package/build/adapters/gemini-cli/index.js +0 -30
- package/build/adapters/kiro/index.d.ts +1 -3
- package/build/adapters/kiro/index.js +0 -30
- package/build/adapters/openclaw/index.d.ts +1 -3
- package/build/adapters/openclaw/index.js +0 -38
- package/build/adapters/opencode/index.d.ts +1 -3
- package/build/adapters/opencode/index.js +15 -34
- package/build/adapters/types.d.ts +0 -13
- package/build/adapters/vscode-copilot/index.d.ts +1 -3
- package/build/adapters/vscode-copilot/index.js +0 -32
- package/build/adapters/zed/index.d.ts +1 -3
- package/build/adapters/zed/index.js +0 -30
- package/build/executor.d.ts +0 -1
- package/build/executor.js +26 -14
- package/build/openclaw-plugin.js +0 -30
- package/build/opencode-plugin.d.ts +1 -0
- package/build/opencode-plugin.js +1 -8
- package/build/server.js +34 -17
- package/build/truncate.d.ts +4 -17
- package/build/truncate.js +4 -52
- package/cli.bundle.mjs +109 -136
- package/hooks/ensure-deps.mjs +80 -2
- package/hooks/routing-block.mjs +10 -1
- package/hooks/session-snapshot.bundle.mjs +13 -13
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +82 -106
- package/skills/context-mode-ops/SKILL.md +111 -0
- package/skills/context-mode-ops/agent-teams.md +198 -0
- package/skills/context-mode-ops/communication.md +224 -0
- package/skills/context-mode-ops/release.md +199 -0
- package/skills/context-mode-ops/review-pr.md +269 -0
- package/skills/context-mode-ops/tdd.md +329 -0
- package/skills/context-mode-ops/triage-issue.md +218 -0
- package/skills/context-mode-ops/validation.md +238 -0
- package/start.mjs +5 -52
package/hooks/ensure-deps.mjs
CHANGED
|
@@ -8,13 +8,22 @@
|
|
|
8
8
|
* hook that needs native modules. Fast path: existsSync check (~0.1ms).
|
|
9
9
|
* Slow path: npm install (first run only, ~5-30s).
|
|
10
10
|
*
|
|
11
|
+
* Also handles ABI compatibility (#148, #203): when the current Node.js
|
|
12
|
+
* version differs from the one better-sqlite3 was compiled against,
|
|
13
|
+
* automatically swaps in a cached binary or rebuilds. This protects
|
|
14
|
+
* both the MCP server AND hooks from ABI mismatch crashes when users
|
|
15
|
+
* have multiple Node versions via mise/volta/fnm/nvm.
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/mksglu/context-mode/issues/148
|
|
11
18
|
* @see https://github.com/mksglu/context-mode/issues/172
|
|
19
|
+
* @see https://github.com/mksglu/context-mode/issues/203
|
|
12
20
|
*/
|
|
13
21
|
|
|
14
|
-
import { existsSync } from "node:fs";
|
|
22
|
+
import { existsSync, copyFileSync } from "node:fs";
|
|
15
23
|
import { execSync } from "node:child_process";
|
|
16
24
|
import { resolve, dirname } from "node:path";
|
|
17
25
|
import { fileURLToPath } from "node:url";
|
|
26
|
+
import { createRequire } from "node:module";
|
|
18
27
|
|
|
19
28
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
20
29
|
const root = resolve(__dirname, "..");
|
|
@@ -23,7 +32,9 @@ const NATIVE_DEPS = ["better-sqlite3"];
|
|
|
23
32
|
|
|
24
33
|
export function ensureDeps() {
|
|
25
34
|
for (const pkg of NATIVE_DEPS) {
|
|
26
|
-
|
|
35
|
+
const pkgDir = resolve(root, "node_modules", pkg);
|
|
36
|
+
if (!existsSync(pkgDir)) {
|
|
37
|
+
// Package not installed at all
|
|
27
38
|
try {
|
|
28
39
|
execSync(`npm install ${pkg} --no-package-lock --no-save --silent`, {
|
|
29
40
|
cwd: root,
|
|
@@ -31,9 +42,76 @@ export function ensureDeps() {
|
|
|
31
42
|
timeout: 120000,
|
|
32
43
|
});
|
|
33
44
|
} catch { /* best effort — hook degrades gracefully without DB */ }
|
|
45
|
+
} else if (
|
|
46
|
+
!existsSync(resolve(pkgDir, "build", "Release")) &&
|
|
47
|
+
!existsSync(resolve(pkgDir, "prebuilds"))
|
|
48
|
+
) {
|
|
49
|
+
// Package installed but native binary missing (e.g., npm ignore-scripts=true)
|
|
50
|
+
try {
|
|
51
|
+
execSync(`npm rebuild ${pkg} --ignore-scripts=false`, {
|
|
52
|
+
cwd: root,
|
|
53
|
+
stdio: "pipe",
|
|
54
|
+
timeout: 120000,
|
|
55
|
+
});
|
|
56
|
+
} catch { /* best effort — hook degrades gracefully without DB */ }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* ABI-aware native binary caching for better-sqlite3 (#148, #203).
|
|
63
|
+
*
|
|
64
|
+
* Users with mise/asdf/volta/fnm may run sessions with different Node
|
|
65
|
+
* versions. Each ABI needs its own compiled binary — cache them
|
|
66
|
+
* side-by-side so switching Node versions doesn't require a rebuild
|
|
67
|
+
* every time.
|
|
68
|
+
*
|
|
69
|
+
* Flow:
|
|
70
|
+
* 1. Check if ABI-specific cache exists → swap in
|
|
71
|
+
* 2. Probe-load better-sqlite3 → if OK, cache current binary
|
|
72
|
+
* 3. If ABI mismatch → npm rebuild, then cache the new binary
|
|
73
|
+
*/
|
|
74
|
+
export function ensureNativeCompat(pluginRoot) {
|
|
75
|
+
try {
|
|
76
|
+
const abi = process.versions.modules;
|
|
77
|
+
const nativeDir = resolve(pluginRoot, "node_modules", "better-sqlite3", "build", "Release");
|
|
78
|
+
const binaryPath = resolve(nativeDir, "better_sqlite3.node");
|
|
79
|
+
const abiCachePath = resolve(nativeDir, `better_sqlite3.abi${abi}.node`);
|
|
80
|
+
|
|
81
|
+
if (!existsSync(nativeDir)) return;
|
|
82
|
+
|
|
83
|
+
// Fast path: cached binary for this ABI already exists
|
|
84
|
+
if (existsSync(abiCachePath)) {
|
|
85
|
+
copyFileSync(abiCachePath, binaryPath);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (!existsSync(binaryPath)) return;
|
|
90
|
+
|
|
91
|
+
// Probe: try loading better-sqlite3 with current Node
|
|
92
|
+
try {
|
|
93
|
+
const req = createRequire(resolve(pluginRoot, "package.json"));
|
|
94
|
+
req("better-sqlite3");
|
|
95
|
+
// Load succeeded — cache the working binary for this ABI
|
|
96
|
+
copyFileSync(binaryPath, abiCachePath);
|
|
97
|
+
} catch (probeErr) {
|
|
98
|
+
if (probeErr?.message?.includes("NODE_MODULE_VERSION")) {
|
|
99
|
+
// ABI mismatch — rebuild for current Node version
|
|
100
|
+
execSync("npm rebuild better-sqlite3", {
|
|
101
|
+
cwd: pluginRoot,
|
|
102
|
+
stdio: "pipe",
|
|
103
|
+
timeout: 60000,
|
|
104
|
+
});
|
|
105
|
+
if (existsSync(binaryPath)) {
|
|
106
|
+
copyFileSync(binaryPath, abiCachePath);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
34
109
|
}
|
|
110
|
+
} catch {
|
|
111
|
+
/* best effort — caller will report the error on first DB access */
|
|
35
112
|
}
|
|
36
113
|
}
|
|
37
114
|
|
|
38
115
|
// Auto-run on import (like suppress-stderr.mjs)
|
|
39
116
|
ensureDeps();
|
|
117
|
+
ensureNativeCompat(root);
|
package/hooks/routing-block.mjs
CHANGED
|
@@ -35,12 +35,21 @@ export function createRoutingBlock(t) {
|
|
|
35
35
|
- DO NOT use Read for analysis (use execute_file). Read IS correct for files you intend to Edit.
|
|
36
36
|
- DO NOT use WebFetch (use ${t("ctx_fetch_and_index")} instead).
|
|
37
37
|
- Bash is ONLY for git/mkdir/rm/mv/navigation.
|
|
38
|
+
- DO NOT use ${t("ctx_execute")} or ${t("ctx_execute_file")} to create, modify, or overwrite files.
|
|
39
|
+
ctx_execute is for data analysis, log processing, and computation only.
|
|
38
40
|
</forbidden_actions>
|
|
39
41
|
|
|
42
|
+
<file_writing_policy>
|
|
43
|
+
ALWAYS use the native Write tool to create files and Edit tool to modify files.
|
|
44
|
+
NEVER use ${t("ctx_execute")}, ${t("ctx_execute_file")}, or Bash to write file content.
|
|
45
|
+
This applies to all file types: code, configs, plans, specs, YAML, JSON, markdown.
|
|
46
|
+
</file_writing_policy>
|
|
47
|
+
|
|
40
48
|
<output_constraints>
|
|
41
49
|
<word_limit>Keep your final response under 500 words.</word_limit>
|
|
42
50
|
<artifact_policy>
|
|
43
|
-
Write artifacts (code, configs, PRDs) to FILES. NEVER return them as inline text.
|
|
51
|
+
Write artifacts (code, configs, PRDs) to FILES using the native Write tool. NEVER return them as inline text.
|
|
52
|
+
Use Edit tool for modifications to existing files.
|
|
44
53
|
Return only: file path + 1-line description.
|
|
45
54
|
</artifact_policy>
|
|
46
55
|
<response_format>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
function
|
|
2
|
-
`)}function z(t){if(t.length===0)return"";let e=[],n={};for(let i of t)try{let r=JSON.parse(i.data);typeof r.subject=="string"?e.push(r.subject):typeof r.taskId=="string"&&typeof r.status=="string"&&(n[r.taskId]=r.status)}catch{}if(e.length===0)return"";let s=new Set(["completed","deleted","failed"]),c=Object.keys(n).sort((i,r)=>Number(i)-Number(r)),u=[];for(let i=0;i<e.length;i++){let r=c[i],f=r?n[r]??"pending":"pending";s.has(f)||u.push(e[i])}if(u.length===0)return"";let
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function
|
|
6
|
-
`)}function
|
|
7
|
-
`)}function
|
|
1
|
+
function l(t,e){return t.length<=e?t:t.slice(0,Math.max(0,e-3))+"..."}function a(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var G=2048,J=10;function q(t){if(t.length===0)return"";let e=new Map;for(let u of t){let p=u.data,i=e.get(p);i||(i={ops:new Map,last:""},e.set(p,i));let r;u.type==="file_write"?r="write":u.type==="file_read"?r="read":u.type==="file_edit"?r="edit":r=u.type,i.ops.set(r,(i.ops.get(r)??0)+1),i.last=r}let s=Array.from(e.entries()).slice(-J),c=[" <active_files>"];for(let[u,{ops:p,last:i}]of s){let r=Array.from(p.entries()).map(([f,g])=>`${f}:${g}`).join(",");c.push(` <file path="${a(u)}" ops="${a(r)}" last="${a(i)}" />`)}return c.push(" </active_files>"),c.join(`
|
|
2
|
+
`)}function z(t){if(t.length===0)return"";let e=[],n={};for(let i of t)try{let r=JSON.parse(i.data);typeof r.subject=="string"?e.push(r.subject):typeof r.taskId=="string"&&typeof r.status=="string"&&(n[r.taskId]=r.status)}catch{}if(e.length===0)return"";let s=new Set(["completed","deleted","failed"]),c=Object.keys(n).sort((i,r)=>Number(i)-Number(r)),u=[];for(let i=0;i<e.length;i++){let r=c[i],f=r?n[r]??"pending":"pending";s.has(f)||u.push(e[i])}if(u.length===0)return"";let p=[" <task_state>"];for(let i of u)p.push(` - ${a(l(i,100))}`);return p.push(" </task_state>"),p.join(`
|
|
3
|
+
`)}function U(t){if(t.length===0)return"";let e=new Set,n=[" <rules>"];for(let s of t){let c=s.data;e.has(c)||(e.add(c),s.type==="rule_content"?n.push(` <rule_content>${a(l(s.data,400))}</rule_content>`):n.push(` - ${a(l(s.data,200))}`))}return n.push(" </rules>"),n.join(`
|
|
4
|
+
`)}function V(t){if(t.length===0)return"";let e=new Set,n=[" <decisions>"];for(let s of t){let c=s.data;e.has(c)||(e.add(c),n.push(` - ${a(l(s.data,200))}`))}return n.push(" </decisions>"),n.join(`
|
|
5
|
+
`)}function Y(t,e,n){let s=[];if(!t&&e.length===0&&!n)return"";s.push(" <environment>"),t&&s.push(` <cwd>${a(t.data)}</cwd>`),n&&s.push(` <git op="${a(n.data)}" />`);for(let c of e)s.push(` <env>${a(l(c.data,150))}</env>`);return s.push(" </environment>"),s.join(`
|
|
6
|
+
`)}function H(t){if(t.length===0)return"";let e=[" <errors_encountered>"];for(let n of t)e.push(` - ${a(l(n.data,150))}`);return e.push(" </errors_encountered>"),e.join(`
|
|
7
|
+
`)}function K(t){return` <intent mode="${a(t.data)}">${a(l(t.data,100))}</intent>`}function P(t){if(t.length===0)return"";let e=[" <subagents>"];for(let n of t){let s=n.type==="subagent_completed"?"completed":n.type==="subagent_launched"?"launched":"unknown";e.push(` <agent status="${s}">${a(l(n.data,200))}</agent>`)}return e.push(" </subagents>"),e.join(`
|
|
8
8
|
`)}function Q(t){if(t.length===0)return"";let e=new Map;for(let s of t){let c=s.data.split(":")[0].trim();e.set(c,(e.get(c)??0)+1)}let n=[" <mcp_tools>"];for(let[s,c]of e)n.push(` <tool name="${a(s)}" calls="${c}" />`);return n.push(" </mcp_tools>"),n.join(`
|
|
9
|
-
`)}function et(t,e){let n=e?.maxBytes??G,s=e?.compactCount??1,c=new Date().toISOString(),u=[],
|
|
10
|
-
`),y;if(
|
|
11
|
-
${
|
|
12
|
-
${
|
|
13
|
-
${
|
|
14
|
-
${
|
|
9
|
+
`)}function et(t,e){let n=e?.maxBytes??G,s=e?.compactCount??1,c=new Date().toISOString(),u=[],p=[],i=[],r=[],f=[],g=[],$=[],h=[],E=[],S=[],w=[],m=[];for(let o of t)switch(o.category){case"file":u.push(o);break;case"task":p.push(o);break;case"rule":i.push(o);break;case"decision":r.push(o);break;case"cwd":f.push(o);break;case"error":g.push(o);break;case"env":$.push(o);break;case"git":h.push(o);break;case"subagent":E.push(o);break;case"intent":S.push(o);break;case"mcp":w.push(o);break;case"plan":m.push(o);break}let b=[],x=q(u);x&&b.push(x);let B=z(p);B&&b.push(B);let j=U(i);j&&b.push(j);let d=[],I=V(r);I&&d.push(I);let R=f.length>0?f[f.length-1]:void 0,F=h.length>0?h[h.length-1]:void 0,L=Y(R,$,F);L&&d.push(L);let M=H(g);M&&d.push(M);let D=E.filter(o=>o.type==="subagent_completed"),O=P(D);O&&d.push(O),m.length>0&&m[m.length-1].type==="plan_enter"&&d.push(' <plan_mode status="active" />');let v=[];if(S.length>0){let o=S[S.length-1];v.push(K(o))}let T=Q(w);T&&v.push(T);let X=E.filter(o=>o.type==="subagent_launched"),A=P(X);A&&v.push(A);let _=`<session_resume compact_count="${s}" events_captured="${t.length}" generated_at="${c}">`,k="</session_resume>",C=[b,d,v];for(let o=C.length;o>=0;o--){let N=C.slice(0,o).flat().join(`
|
|
10
|
+
`),y;if(N?y=`${_}
|
|
11
|
+
${N}
|
|
12
|
+
${k}`:y=`${_}
|
|
13
|
+
${k}`,Buffer.byteLength(y)<=n)return y}return`${_}
|
|
14
|
+
${k}`}export{et as buildResumeSnapshot,q as renderActiveFiles,V as renderDecisions,Y as renderEnvironment,H as renderErrors,K as renderIntent,Q as renderMcpTools,U as renderRules,P as renderSubagents,z as renderTaskState};
|
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.56",
|
|
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.56",
|
|
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",
|