context-mode 0.9.21 → 0.9.22
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +10 -9
- package/build/cli.d.ts +3 -2
- package/build/cli.js +8 -4
- package/build/server.js +1 -1
- package/hooks/pretooluse.mjs +3 -3
- package/hooks/routing-block.mjs +6 -6
- package/package.json +1 -1
- package/server.bundle.mjs +1 -1
- package/skills/{doctor → ctx-doctor}/SKILL.md +3 -3
- package/skills/{stats → ctx-stats}/SKILL.md +2 -2
- package/skills/{upgrade → ctx-upgrade}/SKILL.md +3 -3
|
@@ -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 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
16
|
-
"version": "0.9.
|
|
16
|
+
"version": "0.9.22",
|
|
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.9.
|
|
3
|
+
"version": "0.9.22",
|
|
4
4
|
"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.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mert Koseoğlu",
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
**The other half of the context problem.**
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/context-mode) [](https://www.npmjs.com/package/context-mode) [](https://github.com/mksglu/claude-context-mode) [](https://github.com/mksglu/claude-context-mode/stargazers) [](https://github.com/mksglu/claude-context-mode/network/members) [](https://github.com/mksglu/claude-context-mode/commits) [](LICENSE)
|
|
6
|
+
[](https://discord.gg/DCN9jUgN5v)
|
|
6
7
|
|
|
7
8
|
Every MCP tool call in Claude Code dumps raw data into your 200K context window. A Playwright snapshot costs 56 KB. Twenty GitHub issues cost 59 KB. One access log — 45 KB. After 30 minutes, 40% of your context is gone.
|
|
8
9
|
|
|
@@ -23,9 +24,9 @@ Restart Claude Code. Done. This installs the MCP server + a PreToolUse hook that
|
|
|
23
24
|
|
|
24
25
|
| Command | What it does |
|
|
25
26
|
|---|---|
|
|
26
|
-
| `/context-mode:stats` | Show context savings for the current session — per-tool breakdown, tokens consumed, savings ratio. |
|
|
27
|
-
| `/context-mode:doctor` | Run diagnostics — checks runtimes, hooks, FTS5, plugin registration, npm and marketplace versions. |
|
|
28
|
-
| `/context-mode:upgrade` | Pull latest from GitHub, rebuild, migrate cache, fix hooks. |
|
|
27
|
+
| `/context-mode:ctx-stats` | Show context savings for the current session — per-tool breakdown, tokens consumed, savings ratio. |
|
|
28
|
+
| `/context-mode:ctx-doctor` | Run diagnostics — checks runtimes, hooks, FTS5, plugin registration, npm and marketplace versions. |
|
|
29
|
+
| `/context-mode:ctx-upgrade` | Pull latest from GitHub, rebuild, migrate cache, fix hooks. |
|
|
29
30
|
|
|
30
31
|
<details>
|
|
31
32
|
<summary><strong>MCP-only install</strong> (no hooks or slash commands)</summary>
|
|
@@ -150,38 +151,38 @@ Over a full session: 315 KB of raw output becomes 5.4 KB. Session time before sl
|
|
|
150
151
|
|
|
151
152
|
## Try It
|
|
152
153
|
|
|
153
|
-
These prompts work out of the box. Run `/context-mode:stats` after each to see the savings.
|
|
154
|
+
These prompts work out of the box. Run `/context-mode:ctx-stats` after each to see the savings.
|
|
154
155
|
|
|
155
156
|
**Deep repo research** — 5 calls, 62 KB context (raw: 986 KB, 94% saved)
|
|
156
157
|
```
|
|
157
158
|
Research https://github.com/modelcontextprotocol/servers — architecture, tech stack,
|
|
158
|
-
top contributors, open issues, and recent activity. Then run /context-mode:stats.
|
|
159
|
+
top contributors, open issues, and recent activity. Then run /context-mode:ctx-stats.
|
|
159
160
|
```
|
|
160
161
|
|
|
161
162
|
**Git history analysis** — 1 call, 5.6 KB context
|
|
162
163
|
```
|
|
163
164
|
Clone https://github.com/facebook/react and analyze the last 500 commits:
|
|
164
165
|
top contributors, commit frequency by month, and most changed files.
|
|
165
|
-
Then run /context-mode:stats.
|
|
166
|
+
Then run /context-mode:ctx-stats.
|
|
166
167
|
```
|
|
167
168
|
|
|
168
169
|
**Web scraping** — 1 call, 3.2 KB context
|
|
169
170
|
```
|
|
170
171
|
Fetch the Hacker News front page, extract all posts with titles, scores,
|
|
171
|
-
and domains. Group by domain. Then run /context-mode:stats.
|
|
172
|
+
and domains. Group by domain. Then run /context-mode:ctx-stats.
|
|
172
173
|
```
|
|
173
174
|
|
|
174
175
|
**Large JSON API** — 7.5 MB raw → 0.9 KB context (99% saved)
|
|
175
176
|
```
|
|
176
177
|
Create a local server that returns a 7.5 MB JSON with 20,000 records and a secret
|
|
177
178
|
hidden at index 13000. Fetch the endpoint, find the hidden record, and show me
|
|
178
|
-
exactly what's in it. Then run /context-mode:stats.
|
|
179
|
+
exactly what's in it. Then run /context-mode:ctx-stats.
|
|
179
180
|
```
|
|
180
181
|
|
|
181
182
|
**Documentation search** — 2 calls, 1.8 KB context
|
|
182
183
|
```
|
|
183
184
|
Fetch the React useEffect docs, index them, and find the cleanup pattern
|
|
184
|
-
with code examples. Then run /context-mode:stats.
|
|
185
|
+
with code examples. Then run /context-mode:ctx-stats.
|
|
185
186
|
```
|
|
186
187
|
|
|
187
188
|
## Security
|
package/build/cli.d.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* context-mode setup → Interactive setup (detect runtimes, install Bun)
|
|
8
8
|
* context-mode doctor → Diagnose runtime issues, hooks, FTS5, version
|
|
9
9
|
* context-mode upgrade → Fix hooks, permissions, and settings
|
|
10
|
-
* context-mode stats → (skill only — /context-mode:stats)
|
|
10
|
+
* context-mode stats → (skill only — /context-mode:ctx-stats)
|
|
11
11
|
*/
|
|
12
|
-
|
|
12
|
+
/** Normalize Windows backslash paths to forward slashes for Bash (MSYS2) compatibility. */
|
|
13
|
+
export declare function toUnixPath(p: string): string;
|
package/build/cli.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* context-mode setup → Interactive setup (detect runtimes, install Bun)
|
|
8
8
|
* context-mode doctor → Diagnose runtime issues, hooks, FTS5, version
|
|
9
9
|
* context-mode upgrade → Fix hooks, permissions, and settings
|
|
10
|
-
* context-mode stats → (skill only — /context-mode:stats)
|
|
10
|
+
* context-mode stats → (skill only — /context-mode:ctx-stats)
|
|
11
11
|
*/
|
|
12
12
|
import * as p from "@clack/prompts";
|
|
13
13
|
import color from "picocolors";
|
|
@@ -34,6 +34,10 @@ else {
|
|
|
34
34
|
/* -------------------------------------------------------
|
|
35
35
|
* Shared helpers
|
|
36
36
|
* ------------------------------------------------------- */
|
|
37
|
+
/** Normalize Windows backslash paths to forward slashes for Bash (MSYS2) compatibility. */
|
|
38
|
+
export function toUnixPath(p) {
|
|
39
|
+
return p.replace(/\\/g, "/");
|
|
40
|
+
}
|
|
37
41
|
function getPluginRoot() {
|
|
38
42
|
const __filename = fileURLToPath(import.meta.url);
|
|
39
43
|
const __dirname = dirname(__filename);
|
|
@@ -336,7 +340,7 @@ async function doctor() {
|
|
|
336
340
|
else {
|
|
337
341
|
p.log.warn(color.yellow("npm (MCP): WARN") +
|
|
338
342
|
` — local v${localVersion}, latest v${latestVersion}` +
|
|
339
|
-
color.dim("\n Run: /context-mode:upgrade"));
|
|
343
|
+
color.dim("\n Run: /context-mode:ctx-upgrade"));
|
|
340
344
|
}
|
|
341
345
|
// Marketplace version
|
|
342
346
|
if (marketplaceVersion === "not installed") {
|
|
@@ -350,7 +354,7 @@ async function doctor() {
|
|
|
350
354
|
else if (latestVersion !== "unknown") {
|
|
351
355
|
p.log.warn(color.yellow("Marketplace: WARN") +
|
|
352
356
|
` — v${marketplaceVersion}, latest v${latestVersion}` +
|
|
353
|
-
color.dim("\n Run: /context-mode:upgrade"));
|
|
357
|
+
color.dim("\n Run: /context-mode:ctx-upgrade"));
|
|
354
358
|
}
|
|
355
359
|
else {
|
|
356
360
|
p.log.info(`Marketplace: v${marketplaceVersion}` +
|
|
@@ -515,7 +519,7 @@ async function upgrade() {
|
|
|
515
519
|
}
|
|
516
520
|
// Step 4: Fix hooks
|
|
517
521
|
p.log.step("Configuring PreToolUse hooks...");
|
|
518
|
-
const hookScriptPath = resolve(pluginRoot, "hooks", "pretooluse.mjs");
|
|
522
|
+
const hookScriptPath = toUnixPath(resolve(pluginRoot, "hooks", "pretooluse.mjs"));
|
|
519
523
|
const settings = readSettings() ?? {};
|
|
520
524
|
const desiredHookEntry = {
|
|
521
525
|
matcher: "Bash|Read|Grep|WebFetch|Task|mcp__plugin_context-mode_context-mode__execute|mcp__plugin_context-mode_context-mode__execute_file|mcp__plugin_context-mode_context-mode__batch_execute",
|
package/build/server.js
CHANGED
|
@@ -7,7 +7,7 @@ import { PolyglotExecutor } from "./executor.js";
|
|
|
7
7
|
import { ContentStore, cleanupStaleDBs } from "./store.js";
|
|
8
8
|
import { readBashPolicies, evaluateCommandDenyOnly, extractShellCommands, readToolDenyPatterns, evaluateFilePath, } from "./security.js";
|
|
9
9
|
import { detectRuntimes, getRuntimeSummary, getAvailableLanguages, hasBunRuntime, } from "./runtime.js";
|
|
10
|
-
const VERSION = "0.9.
|
|
10
|
+
const VERSION = "0.9.22";
|
|
11
11
|
const runtimes = detectRuntimes();
|
|
12
12
|
const available = getAvailableLanguages(runtimes);
|
|
13
13
|
const server = new McpServer({
|
package/hooks/pretooluse.mjs
CHANGED
|
@@ -185,7 +185,7 @@ function route() {
|
|
|
185
185
|
hookSpecificOutput: {
|
|
186
186
|
hookEventName: "PreToolUse",
|
|
187
187
|
updatedInput: {
|
|
188
|
-
command: 'echo "context-mode: curl/wget blocked. You MUST use
|
|
188
|
+
command: 'echo "context-mode: curl/wget blocked. You MUST use mcp__plugin_context-mode_context-mode__fetch_and_index(url, source) to fetch URLs, or mcp__plugin_context-mode_context-mode__execute(language, code) to run HTTP calls in sandbox. Do NOT retry with curl/wget."',
|
|
189
189
|
},
|
|
190
190
|
},
|
|
191
191
|
};
|
|
@@ -201,7 +201,7 @@ function route() {
|
|
|
201
201
|
hookSpecificOutput: {
|
|
202
202
|
hookEventName: "PreToolUse",
|
|
203
203
|
updatedInput: {
|
|
204
|
-
command: 'echo "context-mode: Inline HTTP blocked. Use
|
|
204
|
+
command: 'echo "context-mode: Inline HTTP blocked. Use mcp__plugin_context-mode_context-mode__execute(language, code) to run HTTP calls in sandbox, or mcp__plugin_context-mode_context-mode__fetch_and_index(url, source) for web pages. Do NOT retry with Bash."',
|
|
205
205
|
},
|
|
206
206
|
},
|
|
207
207
|
};
|
|
@@ -238,7 +238,7 @@ function route() {
|
|
|
238
238
|
hookSpecificOutput: {
|
|
239
239
|
hookEventName: "PreToolUse",
|
|
240
240
|
permissionDecision: "deny",
|
|
241
|
-
reason: `context-mode: WebFetch blocked. Use
|
|
241
|
+
reason: `context-mode: WebFetch blocked. Use mcp__plugin_context-mode_context-mode__fetch_and_index(url: "${url}", source: "...") to fetch this URL in sandbox. Then use mcp__plugin_context-mode_context-mode__search(queries: [...]) to query results. Do NOT use curl/wget — they are also blocked.`,
|
|
242
242
|
},
|
|
243
243
|
};
|
|
244
244
|
}
|
package/hooks/routing-block.mjs
CHANGED
|
@@ -10,19 +10,19 @@ export const ROUTING_BLOCK = `
|
|
|
10
10
|
</priority_instructions>
|
|
11
11
|
|
|
12
12
|
<tool_selection_hierarchy>
|
|
13
|
-
1. GATHER:
|
|
13
|
+
1. GATHER: mcp__plugin_context-mode_context-mode__batch_execute(commands, queries)
|
|
14
14
|
- Primary tool for research. Runs all commands, auto-indexes, and searches.
|
|
15
15
|
- ONE call replaces many individual steps.
|
|
16
|
-
2. FOLLOW-UP:
|
|
16
|
+
2. FOLLOW-UP: mcp__plugin_context-mode_context-mode__search(queries: ["q1", "q2", ...])
|
|
17
17
|
- Use for all follow-up questions. ONE call, many queries.
|
|
18
|
-
3. PROCESSING:
|
|
18
|
+
3. PROCESSING: mcp__plugin_context-mode_context-mode__execute(language, code) | mcp__plugin_context-mode_context-mode__execute_file(path, language, code)
|
|
19
19
|
- Use for API calls, log analysis, and data processing.
|
|
20
20
|
</tool_selection_hierarchy>
|
|
21
21
|
|
|
22
22
|
<forbidden_actions>
|
|
23
23
|
- DO NOT use Bash for commands producing >20 lines of output.
|
|
24
24
|
- DO NOT use Read for analysis (use execute_file). Read IS correct for files you intend to Edit.
|
|
25
|
-
- DO NOT use WebFetch (use
|
|
25
|
+
- DO NOT use WebFetch (use mcp__plugin_context-mode_context-mode__fetch_and_index instead).
|
|
26
26
|
- Bash is ONLY for git/mkdir/rm/mv/navigation.
|
|
27
27
|
</forbidden_actions>
|
|
28
28
|
|
|
@@ -42,6 +42,6 @@ export const ROUTING_BLOCK = `
|
|
|
42
42
|
</output_constraints>
|
|
43
43
|
</context_window_protection>`;
|
|
44
44
|
|
|
45
|
-
export const READ_GUIDANCE = '<context_guidance>\n <tip>\n If you are reading this file to Edit it, Read is the correct tool — Edit needs file content in context.\n If you are reading to analyze or explore, use
|
|
45
|
+
export const READ_GUIDANCE = '<context_guidance>\n <tip>\n If you are reading this file to Edit it, Read is the correct tool — Edit needs file content in context.\n If you are reading to analyze or explore, use mcp__plugin_context-mode_context-mode__execute_file(path, language, code) instead — only your printed summary will enter the context.\n </tip>\n</context_guidance>';
|
|
46
46
|
|
|
47
|
-
export const GREP_GUIDANCE = '<context_guidance>\n <tip>\n This operation may flood your context window. To stay efficient:\n - Use
|
|
47
|
+
export const GREP_GUIDANCE = '<context_guidance>\n <tip>\n This operation may flood your context window. To stay efficient:\n - Use mcp__plugin_context-mode_context-mode__execute(language: "shell", code: "...") to run searches in the sandbox.\n - Only your final printed summary will enter the context.\n </tip>\n</context_guidance>';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.22",
|
|
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
|
@@ -203,7 +203,7 @@ ${n}`}}};import{createRequire as Uz}from"node:module";import{readFileSync as Vz,
|
|
|
203
203
|
`);Buffer.byteLength(b)>r&&p.length>1&&(p.pop(),g(),p=[v])}g(),i=[]},u=0;for(;u<o.length;){let l=o[u];if(/^[-_*]{3,}\s*$/.test(l)){c(),u++;continue}let d=l.match(/^(#{1,4})\s+(.+)$/);if(d){c();let f=d[1].length,p=d[2].trim();for(;s.length>0&&s[s.length-1].level>=f;)s.pop();s.push({level:f,text:p}),a=p,i.push(l),u++;continue}let m=l.match(/^(`{3,})(.*)?$/);if(m){let f=m[1],p=[l];for(u++;u<o.length;){if(p.push(o[u]),o[u].startsWith(f)&&o[u].trim()===f){u++;break}u++}i.push(...p);continue}i.push(l),u++}return c(),n}#w(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(`
|
|
204
204
|
`)[0].slice(0,80)||`Section ${u+1}`,content:l}}).filter(c=>c.content.length>0);let o=e.split(`
|
|
205
205
|
`);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(`
|
|
206
|
-
`)})}return s}#_(e,r,n,o){let s=r.length>0?r.join(" > "):"(root)",i=JSON.stringify(e,null,2);if(Buffer.byteLength(i)<=o&&!(typeof e=="object"&&e!==null&&!Array.isArray(e)&&Object.values(e).some(c=>typeof c=="object"&&c!==null))){n.push({title:s,content:i,hasCode:!0});return}if(typeof e=="object"&&e!==null&&!Array.isArray(e)){let a=Object.entries(e);if(a.length>0){for(let[c,u]of a)this.#_(u,[...r,c],n,o);return}n.push({title:s,content:i,hasCode:!0});return}if(Array.isArray(e)){this.#T(e,r,n,o);return}n.push({title:s,content:i,hasCode:!1})}#k(e){if(e.length===0)return null;let r=e[0];if(typeof r!="object"||r===null||Array.isArray(r))return null;let n=["id","name","title","path","slug","key","label"],o=r;for(let s of n)if(s in o&&(typeof o[s]=="string"||typeof o[s]=="number"))return s;return null}#S(e,r,n,o,s){let i=e?`${e} > `:"";if(!s)return r===n?`${i}[${r}]`:`${i}[${r}-${n}]`;let a=c=>String(c[s]);return o.length===1?`${i}${a(o[0])}`:o.length<=3?i+o.map(a).join(", "):`${i}${a(o[0])}\u2026${a(o[o.length-1])}`}#T(e,r,n,o){let s=r.length>0?r.join(" > "):"(root)",i=this.#k(e),a=[],c=0,u=l=>{if(a.length===0)return;let d=this.#S(s,c,l,a,i);n.push({title:d,content:JSON.stringify(a,null,2),hasCode:!0})};for(let l=0;l<e.length;l++){a.push(e[l]);let d=JSON.stringify(a,null,2);Buffer.byteLength(d)>o&&a.length>1&&(a.pop(),u(l-1),a=[e[l]],c=l)}u(c+a.length-1)}#z(e,r){return e.length===0?r||"Untitled":e.map(n=>n.text).join(" > ")}};import{readFileSync as $y}from"node:fs";import{resolve as yn}from"node:path";import{homedir as wy}from"node:os";function ky(t){let e=t.match(/^Bash\((.+)\)$/);return e?e[1]:null}function Xz(t){let e=t.match(/^(\w+)\((.+)\)$/);return e?{tool:e[1],glob:e[2]}:null}function Yz(t){return t.replace(/[.*+?^${}()|[\]\\\/\-]/g,"\\$&")}function by(t){return t.replace(/[.+?^${}()|[\]\\\/\-]/g,"\\$&").replace(/\*/g,".*")}function Qz(t,e=!1){let r,n=t.indexOf(":");if(n!==-1){let o=t.slice(0,n),s=t.slice(n+1),i=Yz(o),a=by(s);r=`^${i}(\\s${a})?$`}else r=`^${by(t)}$`;return new RegExp(r,e?"i":"")}function eE(t,e=!1){let r="",n=0;for(;n<t.length;)t[n]==="*"&&t[n+1]==="*"?n+2<t.length&&t[n+2]==="/"?(r+="(.*/)?",n+=3):(r+=".*",n+=2):t[n]==="*"?(r+="[^/]*",n++):t[n]==="?"?(r+="[^/]",n++):(r+=t[n].replace(/[.+^${}()|[\]\\\/\-]/g,"\\$&"),n++);return new RegExp(`^${r}$`,e?"i":"")}function tE(t,e,r=!1){for(let n of e){let o=ky(n);if(o&&Qz(o,r).test(t))return n}return null}function rE(t){let e=[],r="",n=!1,o=!1,s=!1;for(let i=0;i<t.length;i++){let a=t[i],c=i>0?t[i-1]:"";a==="'"&&!o&&!s&&c!=="\\"?(n=!n,r+=a):a==='"'&&!n&&!s&&c!=="\\"?(o=!o,r+=a):a==="`"&&!n&&!o&&c!=="\\"?(s=!s,r+=a):!n&&!o&&!s?a===";"?(e.push(r.trim()),r=""):a==="|"&&t[i+1]==="|"||a==="&"&&t[i+1]==="&"?(e.push(r.trim()),r="",i++):a==="|"?(e.push(r.trim()),r=""):r+=a:r+=a}return r.trim()&&e.push(r.trim()),e.filter(i=>i.length>0)}function id(t){let e;try{e=$y(t,"utf-8")}catch{return null}let r;try{r=JSON.parse(e)}catch{return null}let n=r?.permissions;if(!n||typeof n!="object")return null;let o=s=>Array.isArray(s)?s.filter(i=>typeof i=="string"&&ky(i)!==null):[];return{allow:o(n.allow),deny:o(n.deny),ask:o(n.ask)}}function ad(t,e){let r=[];if(t){let s=yn(t,".claude","settings.local.json"),i=id(s);i&&r.push(i);let a=yn(t,".claude","settings.json"),c=id(a);c&&r.push(c)}let n=e??yn(wy(),".claude","settings.json"),o=id(n);return o&&r.push(o),r}function Sy(t,e,r){let n=[],o=a=>{let c;try{c=$y(a,"utf-8")}catch{return null}let u;try{u=JSON.parse(c)}catch{return null}let l=u?.permissions?.deny;if(!Array.isArray(l))return[];let d=[];for(let m of l){if(typeof m!="string")continue;let f=Xz(m);f&&f.tool===t&&d.push(f.glob)}return d};if(e){let a=o(yn(e,".claude","settings.local.json"));a!==null&&n.push(a);let c=o(yn(e,".claude","settings.json"));c!==null&&n.push(c)}let s=r??yn(wy(),".claude","settings.json"),i=o(s);return i!==null&&n.push(i),n}function cd(t,e,r=process.platform==="win32"){let n=rE(t);for(let o of n)for(let s of e){let i=tE(o,s.deny,r);if(i)return{decision:"deny",matchedPattern:i}}return{decision:"allow"}}function Ty(t,e,r=process.platform==="win32"){let n=t.replace(/\\/g,"/");for(let o of e)for(let s of o)if(eE(s,r).test(n))return{denied:!0,matchedPattern:s};return{denied:!1}}var nE={python:[/os\.system\(\s*(['"])(.*?)\1\s*\)/g,/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*(['"])(.*?)\1/g],javascript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],typescript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],ruby:[/system\(\s*(['"])(.*?)\1/g,/`(.*?)`/g],go:[/exec\.Command\(\s*(['"`])(.*?)\1/g],php:[/shell_exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])system\(\s*(['"`])(.*?)\1/g,/passthru\(\s*(['"`])(.*?)\1/g,/proc_open\(\s*(['"`])(.*?)\1/g],rust:[/Command::new\(\s*(['"`])(.*?)\1/g]};function oE(t){let e=[],r=/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*\[([^\]]+)\]/g,n;for(;(n=r.exec(t))!==null;){let s=[...n[1].matchAll(/(['"])(.*?)\1/g)].map(i=>i[2]);s.length>0&&e.push(s.join(" "))}return e}function zy(t,e){let r=nE[e];if(!r&&e!=="python")return[];let n=[];if(r)for(let o of r){o.lastIndex=0;let s;for(;(s=o.exec(t))!==null;){let i=s[s.length-1];i&&n.push(i)}}return e==="python"&&n.push(...oE(t)),n}var Iy="0.9.
|
|
206
|
+
`)})}return s}#_(e,r,n,o){let s=r.length>0?r.join(" > "):"(root)",i=JSON.stringify(e,null,2);if(Buffer.byteLength(i)<=o&&!(typeof e=="object"&&e!==null&&!Array.isArray(e)&&Object.values(e).some(c=>typeof c=="object"&&c!==null))){n.push({title:s,content:i,hasCode:!0});return}if(typeof e=="object"&&e!==null&&!Array.isArray(e)){let a=Object.entries(e);if(a.length>0){for(let[c,u]of a)this.#_(u,[...r,c],n,o);return}n.push({title:s,content:i,hasCode:!0});return}if(Array.isArray(e)){this.#T(e,r,n,o);return}n.push({title:s,content:i,hasCode:!1})}#k(e){if(e.length===0)return null;let r=e[0];if(typeof r!="object"||r===null||Array.isArray(r))return null;let n=["id","name","title","path","slug","key","label"],o=r;for(let s of n)if(s in o&&(typeof o[s]=="string"||typeof o[s]=="number"))return s;return null}#S(e,r,n,o,s){let i=e?`${e} > `:"";if(!s)return r===n?`${i}[${r}]`:`${i}[${r}-${n}]`;let a=c=>String(c[s]);return o.length===1?`${i}${a(o[0])}`:o.length<=3?i+o.map(a).join(", "):`${i}${a(o[0])}\u2026${a(o[o.length-1])}`}#T(e,r,n,o){let s=r.length>0?r.join(" > "):"(root)",i=this.#k(e),a=[],c=0,u=l=>{if(a.length===0)return;let d=this.#S(s,c,l,a,i);n.push({title:d,content:JSON.stringify(a,null,2),hasCode:!0})};for(let l=0;l<e.length;l++){a.push(e[l]);let d=JSON.stringify(a,null,2);Buffer.byteLength(d)>o&&a.length>1&&(a.pop(),u(l-1),a=[e[l]],c=l)}u(c+a.length-1)}#z(e,r){return e.length===0?r||"Untitled":e.map(n=>n.text).join(" > ")}};import{readFileSync as $y}from"node:fs";import{resolve as yn}from"node:path";import{homedir as wy}from"node:os";function ky(t){let e=t.match(/^Bash\((.+)\)$/);return e?e[1]:null}function Xz(t){let e=t.match(/^(\w+)\((.+)\)$/);return e?{tool:e[1],glob:e[2]}:null}function Yz(t){return t.replace(/[.*+?^${}()|[\]\\\/\-]/g,"\\$&")}function by(t){return t.replace(/[.+?^${}()|[\]\\\/\-]/g,"\\$&").replace(/\*/g,".*")}function Qz(t,e=!1){let r,n=t.indexOf(":");if(n!==-1){let o=t.slice(0,n),s=t.slice(n+1),i=Yz(o),a=by(s);r=`^${i}(\\s${a})?$`}else r=`^${by(t)}$`;return new RegExp(r,e?"i":"")}function eE(t,e=!1){let r="",n=0;for(;n<t.length;)t[n]==="*"&&t[n+1]==="*"?n+2<t.length&&t[n+2]==="/"?(r+="(.*/)?",n+=3):(r+=".*",n+=2):t[n]==="*"?(r+="[^/]*",n++):t[n]==="?"?(r+="[^/]",n++):(r+=t[n].replace(/[.+^${}()|[\]\\\/\-]/g,"\\$&"),n++);return new RegExp(`^${r}$`,e?"i":"")}function tE(t,e,r=!1){for(let n of e){let o=ky(n);if(o&&Qz(o,r).test(t))return n}return null}function rE(t){let e=[],r="",n=!1,o=!1,s=!1;for(let i=0;i<t.length;i++){let a=t[i],c=i>0?t[i-1]:"";a==="'"&&!o&&!s&&c!=="\\"?(n=!n,r+=a):a==='"'&&!n&&!s&&c!=="\\"?(o=!o,r+=a):a==="`"&&!n&&!o&&c!=="\\"?(s=!s,r+=a):!n&&!o&&!s?a===";"?(e.push(r.trim()),r=""):a==="|"&&t[i+1]==="|"||a==="&"&&t[i+1]==="&"?(e.push(r.trim()),r="",i++):a==="|"?(e.push(r.trim()),r=""):r+=a:r+=a}return r.trim()&&e.push(r.trim()),e.filter(i=>i.length>0)}function id(t){let e;try{e=$y(t,"utf-8")}catch{return null}let r;try{r=JSON.parse(e)}catch{return null}let n=r?.permissions;if(!n||typeof n!="object")return null;let o=s=>Array.isArray(s)?s.filter(i=>typeof i=="string"&&ky(i)!==null):[];return{allow:o(n.allow),deny:o(n.deny),ask:o(n.ask)}}function ad(t,e){let r=[];if(t){let s=yn(t,".claude","settings.local.json"),i=id(s);i&&r.push(i);let a=yn(t,".claude","settings.json"),c=id(a);c&&r.push(c)}let n=e??yn(wy(),".claude","settings.json"),o=id(n);return o&&r.push(o),r}function Sy(t,e,r){let n=[],o=a=>{let c;try{c=$y(a,"utf-8")}catch{return null}let u;try{u=JSON.parse(c)}catch{return null}let l=u?.permissions?.deny;if(!Array.isArray(l))return[];let d=[];for(let m of l){if(typeof m!="string")continue;let f=Xz(m);f&&f.tool===t&&d.push(f.glob)}return d};if(e){let a=o(yn(e,".claude","settings.local.json"));a!==null&&n.push(a);let c=o(yn(e,".claude","settings.json"));c!==null&&n.push(c)}let s=r??yn(wy(),".claude","settings.json"),i=o(s);return i!==null&&n.push(i),n}function cd(t,e,r=process.platform==="win32"){let n=rE(t);for(let o of n)for(let s of e){let i=tE(o,s.deny,r);if(i)return{decision:"deny",matchedPattern:i}}return{decision:"allow"}}function Ty(t,e,r=process.platform==="win32"){let n=t.replace(/\\/g,"/");for(let o of e)for(let s of o)if(eE(s,r).test(n))return{denied:!0,matchedPattern:s};return{denied:!1}}var nE={python:[/os\.system\(\s*(['"])(.*?)\1\s*\)/g,/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*(['"])(.*?)\1/g],javascript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],typescript:[/exec(?:Sync|File|FileSync)?\(\s*(['"`])(.*?)\1/g,/spawn(?:Sync)?\(\s*(['"`])(.*?)\1/g],ruby:[/system\(\s*(['"])(.*?)\1/g,/`(.*?)`/g],go:[/exec\.Command\(\s*(['"`])(.*?)\1/g],php:[/shell_exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])exec\(\s*(['"`])(.*?)\1/g,/(?:^|[^.])system\(\s*(['"`])(.*?)\1/g,/passthru\(\s*(['"`])(.*?)\1/g,/proc_open\(\s*(['"`])(.*?)\1/g],rust:[/Command::new\(\s*(['"`])(.*?)\1/g]};function oE(t){let e=[],r=/subprocess\.(?:run|call|Popen|check_output|check_call)\(\s*\[([^\]]+)\]/g,n;for(;(n=r.exec(t))!==null;){let s=[...n[1].matchAll(/(['"])(.*?)\1/g)].map(i=>i[2]);s.length>0&&e.push(s.join(" "))}return e}function zy(t,e){let r=nE[e];if(!r&&e!=="python")return[];let n=[];if(r)for(let o of r){o.lastIndex=0;let s;for(;(s=o.exec(t))!==null;){let i=s[s.length-1];i&&n.push(i)}}return e==="python"&&n.push(...oE(t)),n}var Iy="0.9.22",pd=mi(),sE=dy(pd),er=new di({name:"context-mode",version:Iy}),xi=new gi({runtimes:pd,projectRoot:process.env.CLAUDE_PROJECT_DIR}),wo=null;function ko(){return wo||(wo=new yi),wo}var Ae={calls:{},bytesReturned:{},bytesIndexed:0,bytesSandboxed:0,sessionStart:Date.now()};function ee(t,e){let r=e.content.reduce((n,o)=>n+Buffer.byteLength(o.text),0);return Ae.calls[t]=(Ae.calls[t]||0)+1,Ae.bytesReturned[t]=(Ae.bytesReturned[t]||0)+r,e}function Qt(t){Ae.bytesIndexed+=t}function fd(t,e){try{let r=ad(process.env.CLAUDE_PROJECT_DIR),n=cd(t,r);if(n.decision==="deny")return ee(e,{content:[{type:"text",text:`Command blocked by security policy: matches deny pattern ${n.matchedPattern}`}],isError:!0})}catch{}return null}function Oy(t,e,r){try{let n=zy(t,e);if(n.length===0)return null;let o=ad(process.env.CLAUDE_PROJECT_DIR);for(let s of n){let i=cd(s,o);if(i.decision==="deny")return ee(r,{content:[{type:"text",text:`Command blocked by security policy: embedded shell command "${s}" matches deny pattern ${i.matchedPattern}`}],isError:!0})}}catch{}return null}function iE(t,e){try{let r=Sy("Read",process.env.CLAUDE_PROJECT_DIR),n=Ty(t,r);if(n.denied)return ee(e,{content:[{type:"text",text:`File access blocked by security policy: path matches Read deny pattern ${n.matchedPattern}`}],isError:!0})}catch{}return null}var aE=sE.join(", "),cE=nd()?" (Bun detected \u2014 JS/TS runs 3-5x faster)":"",uE="",lE="";function dE(t){let e=[],r=0,n=0;for(;n<t.length;)if(t[n]===uE){for(e.push(r),n++;n<t.length&&t[n]!==lE;)r++,n++;n<t.length&&n++}else r++,n++;return e}function Ny(t,e,r=1500,n){if(t.length<=r)return t;let o=[];if(n)for(let u of dE(n))o.push(u);if(o.length===0){let u=e.toLowerCase().split(/\s+/).filter(d=>d.length>2),l=t.toLowerCase();for(let d of u){let m=l.indexOf(d);for(;m!==-1;)o.push(m),m=l.indexOf(d,m+1)}}if(o.length===0)return t.slice(0,r)+`
|
|
207
207
|
\u2026`;o.sort((u,l)=>u-l);let s=300,i=[];for(let u of o){let l=Math.max(0,u-s),d=Math.min(t.length,u+s);i.length>0&&l<=i[i.length-1][1]?i[i.length-1][1]=d:i.push([l,d])}let a=[],c=0;for(let[u,l]of i){if(c>=r)break;let d=t.slice(u,Math.min(l,u+(r-c)));a.push((u>0?"\u2026":"")+d+(l<t.length?"\u2026":"")),c+=d.length}return a.join(`
|
|
208
208
|
|
|
209
209
|
`)}er.registerTool("execute",{title:"Execute Code",description:`MANDATORY: Use for any command where output exceeds 20 lines. Execute code in a sandboxed subprocess. Only stdout enters context \u2014 raw data stays in the subprocess.${cE} Available: ${aE}.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: doctor
|
|
2
|
+
name: ctx-doctor
|
|
3
3
|
description: |
|
|
4
4
|
Run context-mode diagnostics. Checks runtimes, hooks, FTS5,
|
|
5
5
|
plugin registration, npm and marketplace versions.
|
|
6
|
-
Trigger: /context-mode:doctor
|
|
6
|
+
Trigger: /context-mode:ctx-doctor
|
|
7
7
|
user_invocable: true
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ Run diagnostics and display results directly in the conversation.
|
|
|
13
13
|
|
|
14
14
|
## Instructions
|
|
15
15
|
|
|
16
|
-
1. Derive the **plugin root** from this skill's base directory (go up 2 levels — remove `/skills/doctor`).
|
|
16
|
+
1. Derive the **plugin root** from this skill's base directory (go up 2 levels — remove `/skills/ctx-doctor`).
|
|
17
17
|
2. Run with Bash:
|
|
18
18
|
```
|
|
19
19
|
npx tsx "<PLUGIN_ROOT>/src/cli.ts" doctor
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: stats
|
|
2
|
+
name: ctx-stats
|
|
3
3
|
description: |
|
|
4
4
|
Show how much context window context-mode saved this session.
|
|
5
5
|
Displays token consumption, context savings ratio, and per-tool breakdown.
|
|
6
|
-
Trigger: /context-mode:stats
|
|
6
|
+
Trigger: /context-mode:ctx-stats
|
|
7
7
|
user_invocable: true
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: upgrade
|
|
2
|
+
name: ctx-upgrade
|
|
3
3
|
description: |
|
|
4
4
|
Update context-mode from GitHub and fix hooks/settings.
|
|
5
5
|
Pulls latest, builds, installs, updates npm global, configures hooks.
|
|
6
|
-
Trigger: /context-mode:upgrade
|
|
6
|
+
Trigger: /context-mode:ctx-upgrade
|
|
7
7
|
user_invocable: true
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -13,7 +13,7 @@ Pull latest from GitHub and reinstall the plugin.
|
|
|
13
13
|
|
|
14
14
|
## Instructions
|
|
15
15
|
|
|
16
|
-
1. Derive the **plugin root** from this skill's base directory (go up 2 levels — remove `/skills/upgrade`).
|
|
16
|
+
1. Derive the **plugin root** from this skill's base directory (go up 2 levels — remove `/skills/ctx-upgrade`).
|
|
17
17
|
2. Run with Bash:
|
|
18
18
|
```
|
|
19
19
|
node "<PLUGIN_ROOT>/build/cli.js" upgrade
|