context-mode 0.5.25 → 0.5.26
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.
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Context-mode tool routing — injects MCP tool instructions into subagent prompts",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "Task",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "bash ${CLAUDE_PLUGIN_ROOT}/hooks/task-inject.sh"
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -13,7 +13,7 @@
|
|
|
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 10 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
16
|
-
"version": "0.5.
|
|
16
|
+
"version": "0.5.26",
|
|
17
17
|
"author": {
|
|
18
18
|
"name": "Mert Koseoğlu"
|
|
19
19
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.26",
|
|
4
4
|
"description": "Claude Code MCP plugin that saves 98% of your context window. Sandboxed code execution in 10 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
|
@@ -25,27 +25,5 @@
|
|
|
25
25
|
"args": ["${CLAUDE_PLUGIN_ROOT}/start.sh"]
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
|
-
"skills": "./skills/"
|
|
29
|
-
"hooks": {
|
|
30
|
-
"PreToolUse": [
|
|
31
|
-
{
|
|
32
|
-
"matcher": "Bash",
|
|
33
|
-
"hooks": [
|
|
34
|
-
{
|
|
35
|
-
"type": "prompt",
|
|
36
|
-
"prompt": "Always allow this Bash call to proceed. This is a routing reminder, not a blocker. Default to mcp__context-mode__execute for ALL Bash commands. ONLY use Bash for these guaranteed-small-output operations: file mutations (mkdir, mv, cp, rm, touch, chmod), git writes (git add, git commit, git push, git checkout, git branch, git merge, git pull, git rebase), navigation (cd, pwd, which), process control (kill, pkill), package management (npm install/publish, pip install), and simple echo/printf. Everything else — any command that reads, queries, fetches, lists, logs, tests, builds, diffs, inspects, or calls an external service — should use mcp__context-mode__execute instead. When uncertain, prefer context-mode for future calls."
|
|
37
|
-
}
|
|
38
|
-
]
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
"matcher": "Task",
|
|
42
|
-
"hooks": [
|
|
43
|
-
{
|
|
44
|
-
"type": "prompt",
|
|
45
|
-
"prompt": "Always allow this Task call to proceed. This is a routing reminder, not a blocker. The subagent inherits MCP tools but NOT skill instructions. When the subagent prompt involves fetching URLs, running CLI commands, or processing large files, include these tool names in the prompt so the subagent uses them: mcp__context-mode__execute (language, code, intent), mcp__context-mode__fetch_and_index (url, source), mcp__context-mode__search (query, source), mcp__context-mode__execute_file (path, language, code). Also tell the subagent: do NOT use Bash, Read, or WebFetch for large outputs."
|
|
46
|
-
}
|
|
47
|
-
]
|
|
48
|
-
}
|
|
49
|
-
]
|
|
50
|
-
}
|
|
28
|
+
"skills": "./skills/"
|
|
51
29
|
}
|
package/build/server.js
CHANGED
|
@@ -5,7 +5,7 @@ import { z } from "zod";
|
|
|
5
5
|
import { PolyglotExecutor } from "./executor.js";
|
|
6
6
|
import { ContentStore } from "./store.js";
|
|
7
7
|
import { detectRuntimes, getRuntimeSummary, getAvailableLanguages, hasBunRuntime, } from "./runtime.js";
|
|
8
|
-
const VERSION = "0.5.
|
|
8
|
+
const VERSION = "0.5.26";
|
|
9
9
|
const runtimes = detectRuntimes();
|
|
10
10
|
const available = getAvailableLanguages(runtimes);
|
|
11
11
|
const server = new McpServer({
|
|
@@ -30,7 +30,7 @@ const bunNote = hasBunRuntime()
|
|
|
30
30
|
// ─────────────────────────────────────────────────────────
|
|
31
31
|
server.registerTool("execute", {
|
|
32
32
|
title: "Execute Code",
|
|
33
|
-
description: `Execute code in a sandboxed subprocess. Only stdout enters context — raw data stays in the subprocess. Use instead of bash/cat when output would exceed 20 lines.${bunNote} Available: ${langList}.`,
|
|
33
|
+
description: `Execute code in a sandboxed subprocess. Only stdout enters context — raw data stays in the subprocess. Use instead of bash/cat when output would exceed 20 lines.${bunNote} Available: ${langList}.\n\nPREFER THIS OVER BASH for: API calls (gh, curl, aws), test runners (npm test, pytest), git queries (git log, git diff), data processing, and ANY CLI command that may produce large output. Bash should only be used for file mutations, git writes, and navigation.`,
|
|
34
34
|
inputSchema: z.object({
|
|
35
35
|
language: z
|
|
36
36
|
.enum([
|
|
@@ -217,7 +217,7 @@ function intentSearch(stdout, intent, source, maxResults = 5) {
|
|
|
217
217
|
// ─────────────────────────────────────────────────────────
|
|
218
218
|
server.registerTool("execute_file", {
|
|
219
219
|
title: "Execute File Processing",
|
|
220
|
-
description: "Read a file and process it without loading contents into context. The file is read into a FILE_CONTENT variable inside the sandbox. Only your printed summary enters context.",
|
|
220
|
+
description: "Read a file and process it without loading contents into context. The file is read into a FILE_CONTENT variable inside the sandbox. Only your printed summary enters context.\n\nPREFER THIS OVER Read/cat for: log files, data files (CSV, JSON, XML), large source files for analysis, and any file where you need to extract specific information rather than read the entire content.",
|
|
221
221
|
inputSchema: z.object({
|
|
222
222
|
path: z
|
|
223
223
|
.string()
|
|
@@ -521,7 +521,8 @@ server.registerTool("fetch_and_index", {
|
|
|
521
521
|
title: "Fetch & Index URL",
|
|
522
522
|
description: "Fetches URL content, converts HTML to markdown, and indexes into the searchable knowledge base. " +
|
|
523
523
|
"Raw content never enters context — only a brief confirmation is returned.\n\n" +
|
|
524
|
-
"
|
|
524
|
+
"PREFER THIS OVER WebFetch when you need to reference web documentation later via search. " +
|
|
525
|
+
"WebFetch loads entire page content into context; this tool indexes it and lets you search() on-demand.\n\n" +
|
|
525
526
|
"After fetching, use 'search' to retrieve specific sections on-demand.",
|
|
526
527
|
inputSchema: z.object({
|
|
527
528
|
url: z.string().describe("The URL to fetch and index"),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Claude Code MCP plugin that saves 98% of your context window. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
|
|
6
6
|
"author": "Mert Koseoğlu",
|
package/server.bundle.mjs
CHANGED
|
@@ -132,7 +132,9 @@ ${n}`}}};import{createRequire as aT}from"node:module";import{readFileSync as cT}
|
|
|
132
132
|
`).trim();u.length!==0&&(r.push({title:this.#o(o,i),content:u,hasCode:s.some(l=>/^`{3,}/.test(l))}),s=[])},c=0;for(;c<n.length;){let u=n[c];if(/^[-_*]{3,}\s*$/.test(u)){a(),c++;continue}let l=u.match(/^(#{1,4})\s+(.+)$/);if(l){a();let m=l[1].length,f=l[2].trim();for(;o.length>0&&o[o.length-1].level>=m;)o.pop();o.push({level:m,text:f}),i=f,s.push(u),c++;continue}let d=u.match(/^(`{3,})(.*)?$/);if(d){let m=d[1],f=[u];for(c++;c<n.length;){if(f.push(n[c]),n[c].startsWith(m)&&n[c].trim()===m){c++;break}c++}s.push(...f);continue}s.push(u),c++}return a(),r}#n(e,r){let n=e.split(/\n\s*\n/);if(n.length>=3&&n.length<=200&&n.every(c=>Buffer.byteLength(c)<5e3))return n.map((c,u)=>{let l=c.trim();return{title:l.split(`
|
|
133
133
|
`)[0].slice(0,80)||`Section ${u+1}`,content:l}}).filter(c=>c.content.length>0);let o=e.split(`
|
|
134
134
|
`);if(o.length<=r)return[{title:"Output",content:e}];let s=[],a=Math.max(r-2,1);for(let c=0;c<o.length;c+=a){let u=o.slice(c,c+r);if(u.length===0)break;let l=c+1,d=Math.min(c+u.length,o.length),m=u[0]?.trim().slice(0,80);s.push({title:m||`Lines ${l}-${d}`,content:u.join(`
|
|
135
|
-
`)})}return s}#o(e,r){return e.length===0?r||"Untitled":e.map(n=>n.text).join(" > ")}};var Qg="0.5.
|
|
135
|
+
`)})}return s}#o(e,r){return e.length===0?r||"Untitled":e.map(n=>n.text).join(" > ")}};var Qg="0.5.26",Wl=ai(),mT=Jg(Wl),dn=new oi({name:"context-mode",version:Qg}),Xl=new ci({runtimes:Wl}),Jl=null;function di(){return Jl||(Jl=new _o),Jl}var hT=mT.join(", "),gT=Kl()?" (Bun detected \u2014 JS/TS runs 3-5x faster)":"";dn.registerTool("execute",{title:"Execute Code",description:`Execute code in a sandboxed subprocess. Only stdout enters context \u2014 raw data stays in the subprocess. Use instead of bash/cat when output would exceed 20 lines.${gT} Available: ${hT}.
|
|
136
|
+
|
|
137
|
+
PREFER THIS OVER BASH for: API calls (gh, curl, aws), test runners (npm test, pytest), git queries (git log, git diff), data processing, and ANY CLI command that may produce large output. Bash should only be used for file mutations, git writes, and navigation.`,inputSchema:ie.object({language:ie.enum(["javascript","typescript","python","shell","ruby","go","rust","php","perl","r"]).describe("Runtime language"),code:ie.string().describe("Source code to execute. Use console.log (JS/TS), print (Python/Ruby/Perl/R), echo (Shell), echo (PHP), or fmt.Println (Go) to output a summary to context."),timeout:ie.number().optional().default(3e4).describe("Max execution time in ms"),intent:ie.string().optional().describe(`What you're looking for in the output. When provided and output is large (>5KB), indexes output into knowledge base and returns section titles + previews \u2014 not full content. Use search() to retrieve specific sections. Example: 'failing tests', 'HTTP 500 errors'.
|
|
136
138
|
|
|
137
139
|
TIP: Use specific technical terms, not just concepts. Check 'Searchable terms' in the response for available vocabulary.`)})},async({language:t,code:e,timeout:r,intent:n})=>{try{let o=await Xl.execute({language:t,code:e,timeout:r});if(o.timedOut)return{content:[{type:"text",text:`Execution timed out after ${r}ms
|
|
138
140
|
|
|
@@ -151,7 +153,9 @@ Use search() to query this content. Use source: "${n.label}" to scope results.`}
|
|
|
151
153
|
`).length,s=Buffer.byteLength(t),i=di(),a=i.indexPlainText(t,r),c=new _o(":memory:");try{c.indexPlainText(t,r);let u=c.search(e,n);if(u.length===0){let m=e.trim().split(/\s+/).filter(f=>f.length>2).slice(0,20);if(m.length>0){let f=new Map;for(let p of m){let h=c.search(p,10);for(let g of h){let v=f.get(g.title);v?(v.score+=1,g.rank<v.bestRank&&(v.bestRank=g.rank,v.result=g)):f.set(g.title,{result:g,score:1,bestRank:g.rank})}}u=Array.from(f.values()).sort((p,h)=>h.score-p.score||p.bestRank-h.bestRank).slice(0,n).map(p=>p.result)}}let l=i.getDistinctiveTerms(a.sourceId);if(u.length===0){let m=[`Indexed ${a.totalChunks} sections from "${r}" into knowledge base.`,`No sections matched intent "${e}" in ${o}-line output (${(s/1024).toFixed(1)}KB).`];return l.length>0&&(m.push(""),m.push(`Searchable terms: ${l.join(", ")}`)),m.push(""),m.push("Use search() to explore the indexed content."),m.join(`
|
|
152
154
|
`)}let d=[`Indexed ${a.totalChunks} sections from "${r}" into knowledge base.`,`${u.length} sections matched "${e}" (${o} lines, ${(s/1024).toFixed(1)}KB):`,""];for(let m of u){let f=m.content.split(`
|
|
153
155
|
`)[0].slice(0,120);d.push(` - ${m.title}: ${f}`)}return l.length>0&&(d.push(""),d.push(`Searchable terms: ${l.join(", ")}`)),d.push(""),d.push("Use search() to retrieve full content of any section."),d.join(`
|
|
154
|
-
`)}finally{c.close()}}dn.registerTool("execute_file",{title:"Execute File Processing",description
|
|
156
|
+
`)}finally{c.close()}}dn.registerTool("execute_file",{title:"Execute File Processing",description:`Read a file and process it without loading contents into context. The file is read into a FILE_CONTENT variable inside the sandbox. Only your printed summary enters context.
|
|
157
|
+
|
|
158
|
+
PREFER THIS OVER Read/cat for: log files, data files (CSV, JSON, XML), large source files for analysis, and any file where you need to extract specific information rather than read the entire content.`,inputSchema:ie.object({path:ie.string().describe("Absolute file path or relative to project root"),language:ie.enum(["javascript","typescript","python","shell","ruby","go","rust","php","perl","r"]).describe("Runtime language"),code:ie.string().describe("Code to process FILE_CONTENT. Print summary via console.log/print/echo."),timeout:ie.number().optional().default(3e4).describe("Max execution time in ms"),intent:ie.string().optional().describe("What you're looking for in the output. When provided and output is large (>5KB), returns only matching sections via BM25 search instead of truncated output.")})},async({path:t,language:e,code:r,timeout:n,intent:o})=>{try{let s=await Xl.executeFile({path:t,language:e,code:r,timeout:n});if(s.timedOut)return{content:[{type:"text",text:`Timed out processing ${t} after ${n}ms`}],isError:!0};if(s.exitCode!==0){let a=`Error processing ${t} (exit ${s.exitCode}):
|
|
155
159
|
${s.stderr||s.stdout}`;return o&&o.trim().length>0&&Buffer.byteLength(a)>ui?{content:[{type:"text",text:li(a,o,`file:${t}:error`)}],isError:!0}:{content:[{type:"text",text:a}],isError:!0}}let i=s.stdout||"(no output)";return o&&o.trim().length>0&&Buffer.byteLength(i)>ui?{content:[{type:"text",text:li(i,o,`file:${t}`)}]}:{content:[{type:"text",text:i}]}}catch(s){return{content:[{type:"text",text:`Runtime error: ${s instanceof Error?s.message:String(s)}`}],isError:!0}}});dn.registerTool("index",{title:"Index Content",description:`Index documentation or knowledge content into a searchable BM25 knowledge base. Chunks markdown by headings (keeping code blocks intact) and stores in ephemeral FTS5 database. The full content does NOT stay in context \u2014 only a brief summary is returned.
|
|
156
160
|
|
|
157
161
|
WHEN TO USE:
|
|
@@ -253,7 +257,7 @@ function decodeEntities(s) {
|
|
|
253
257
|
main();
|
|
254
258
|
`;dn.registerTool("fetch_and_index",{title:"Fetch & Index URL",description:`Fetches URL content, converts HTML to markdown, and indexes into the searchable knowledge base. Raw content never enters context \u2014 only a brief confirmation is returned.
|
|
255
259
|
|
|
256
|
-
|
|
260
|
+
PREFER THIS OVER WebFetch when you need to reference web documentation later via search. WebFetch loads entire page content into context; this tool indexes it and lets you search() on-demand.
|
|
257
261
|
|
|
258
262
|
After fetching, use 'search' to retrieve specific sections on-demand.`,inputSchema:ie.object({url:ie.string().describe("The URL to fetch and index"),source:ie.string().optional().describe("Label for the indexed content (e.g., 'React useEffect docs', 'Supabase Auth API')")})},async({url:t,source:e})=>{try{let r=`process.argv[1] = ${JSON.stringify(t)};
|
|
259
263
|
${yT}`,n=await Xl.execute({language:"javascript",code:r,timeout:3e4});return n.exitCode!==0?{content:[{type:"text",text:`Failed to fetch ${t}: ${n.stderr||n.stdout}`}],isError:!0}:!n.stdout||n.stdout.trim().length===0?{content:[{type:"text",text:`Fetched ${t} but got empty content after HTML conversion`}],isError:!0}:_T(n.stdout,e??t)}catch(r){return{content:[{type:"text",text:`Fetch error: ${r instanceof Error?r.message:String(r)}`}],isError:!0}}});async function vT(){let t=new ii;await dn.connect(t),console.error(`Context Mode MCP server v${Qg} running on stdio`),console.error(`Detected runtimes:
|