context-mode 1.0.131 → 1.0.133

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.
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "servers": {
3
3
  "context-mode": {
4
- "command": "npx",
5
- "args": ["-y", "context-mode"]
4
+ "command": "context-mode"
6
5
  }
7
6
  }
8
7
  }
@@ -1,8 +1,7 @@
1
1
  {
2
2
  "servers": {
3
3
  "context-mode": {
4
- "command": "npx",
5
- "args": ["-y", "context-mode"]
4
+ "command": "context-mode"
6
5
  }
7
6
  }
8
7
  }
@@ -1,2 +1,2 @@
1
- function s(t){return t==null?"":String(t)}function h(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function u(t){let e=String(t.tool_response??""),n=t.tool_output?.isError===!0||t.tool_output?.is_error===!0;return t.tool_name==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(e)||n}function y(t){if(!t)return[];let e=[];for(let r of t.split(/\r?\n/)){if(r.startsWith("*** Add File: ")){e.push({path:r.slice(14).trim(),type:"file_write"});continue}if(r.startsWith("*** Update File: ")){e.push({path:r.slice(17).trim(),type:"file_edit"});continue}if(r.startsWith("*** Delete File: ")){e.push({path:r.slice(17).trim(),type:"file_edit"});continue}r.startsWith("*** Move to: ")&&e.push({path:r.slice(13).trim(),type:"file_edit"})}let n=new Set;return e.filter(r=>{if(!r.path)return!1;let o=`${r.type}:${r.path}`;return n.has(o)?!1:(n.add(o),!0)})}function _(t){return/(?:^|[/\\])\.claude[/\\]plans[/\\]/.test(t)}function E(t){let{tool_name:e,tool_input:n,tool_response:r}=t,o=[];if(e==="Read"){let i=String(n.file_path??"");return(/(?:CLAUDE|AGENTS(?:\.override)?|GEMINI|QWEN|KIRO)\.md$/i.test(i)||/\/copilot-instructions\.md$/i.test(i)||/\/context-mode\.mdc$/i.test(i)||/\.claude[\\/]/i.test(i)||/[\\/]memor(?:y|ies)[\\/][^\\/]+\.md$/i.test(i))&&(o.push({type:"rule",category:"rule",data:s(i),priority:1}),r&&r.length>0&&o.push({type:"rule_content",category:"rule",data:s(r),priority:1})),o.push({type:"file_read",category:"file",data:s(i),priority:1}),o}if(e==="Edit"){let i=String(n.file_path??"");return o.push({type:"file_edit",category:"file",data:s(i),priority:1}),o}if(e==="NotebookEdit"){let i=String(n.notebook_path??"");return o.push({type:"file_edit",category:"file",data:s(i),priority:1}),o}if(e==="Write"){let i=String(n.file_path??"");return o.push({type:"file_write",category:"file",data:s(i),priority:1}),o}if(e==="apply_patch"){if(u(t))return[];let i=y(String(n.command??n.patch??""));for(let a of i)o.push({type:a.type,category:"file",data:s(a.path),priority:1});return o}if(e==="Glob"){let i=String(n.pattern??"");return o.push({type:"file_glob",category:"file",data:s(i),priority:3}),o}if(e==="Grep"){let i=String(n.pattern??""),a=String(n.path??"");return o.push({type:"file_search",category:"file",data:s(`${i} in ${a}`),priority:3}),o}return o}function k(t){if(t.tool_name!=="Bash")return[];let n=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!n)return[];let r=n[2]??n[3]??n[4]??"";return[{type:"cwd",category:"cwd",data:s(r),priority:2}]}function A(t){let{tool_response:e}=t,n=String(e??"");return u(t)?[{type:"error_tool",category:"error",data:s(n),priority:2}]:[]}var R=[{pattern:/\bgit\s+checkout\b/,operation:"branch"},{pattern:/\bgit\s+commit\b/,operation:"commit"},{pattern:/\bgit\s+merge\s+\S+/,operation:"merge"},{pattern:/\bgit\s+rebase\b/,operation:"rebase"},{pattern:/\bgit\s+stash\b/,operation:"stash"},{pattern:/\bgit\s+push\b/,operation:"push"},{pattern:/\bgit\s+pull\b/,operation:"pull"},{pattern:/\bgit\s+log\b/,operation:"log"},{pattern:/\bgit\s+diff\b/,operation:"diff"},{pattern:/\bgit\s+status\b/,operation:"status"},{pattern:/\bgit\s+branch\b/,operation:"branch"},{pattern:/\bgit\s+reset\b/,operation:"reset"},{pattern:/\bgit\s+add\b/,operation:"add"},{pattern:/\bgit\s+cherry-pick\b/,operation:"cherry-pick"},{pattern:/\bgit\s+tag\b/,operation:"tag"},{pattern:/\bgit\s+fetch\b/,operation:"fetch"},{pattern:/\bgit\s+clone\b/,operation:"clone"},{pattern:/\bgit\s+worktree\b/,operation:"worktree"}];function v(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),n=R.find(r=>r.pattern.test(e));return n?[{type:"git",category:"git",data:s(n.operation),priority:2}]:[]}function T(t){return new Set(["TodoWrite","TaskCreate","TaskUpdate"]).has(t.tool_name)?[{type:t.tool_name==="TaskUpdate"?"task_update":t.tool_name==="TaskCreate"?"task_create":"task",category:"task",data:s(JSON.stringify(t.tool_input)),priority:1}]:[]}function x(t){if(t.tool_name==="EnterPlanMode")return[{type:"plan_enter",category:"plan",data:"entered plan mode",priority:2}];if(t.tool_name==="ExitPlanMode"){let e=[],n=t.tool_input.allowedPrompts,r=Array.isArray(n)&&n.length>0?`exited plan mode (allowed: ${h(n.map(i=>typeof i=="object"&&i!==null&&"prompt"in i?String(i.prompt):String(i)).join(", "))})`:"exited plan mode";e.push({type:"plan_exit",category:"plan",data:s(r),priority:2});let o=String(t.tool_response??"").toLowerCase();return o.includes("approved")||o.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(o.includes("rejected")||o.includes("decline")||o.includes("denied"))&&e.push({type:"plan_rejected",category:"plan",data:s(`plan rejected: ${t.tool_response??""}`),priority:2}),e}if(t.tool_name==="Write"||t.tool_name==="Edit"){let e=String(t.tool_input.file_path??"");if(_(e))return[{type:"plan_file_write",category:"plan",data:s(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return t.tool_name==="apply_patch"?u(t)?[]:y(String(t.tool_input.command??t.tool_input.patch??"")).filter(n=>_(n.path)).map(n=>({type:"plan_file_write",category:"plan",data:s(`plan file: ${n.path.split(/[/\\]/).pop()??n.path}`),priority:2})):[]}var I=[/\bsource\s+\S*activate\b/,/\bexport\s+\w+=/,/\bnvm\s+use\b/,/\bpyenv\s+(shell|local|global)\b/,/\bconda\s+activate\b/,/\brbenv\s+(shell|local|global)\b/,/\bnpm\s+install\b/,/\bnpm\s+ci\b/,/\bpip\s+install\b/,/\bbun\s+install\b/,/\byarn\s+(add|install)\b/,/\bpnpm\s+(add|install)\b/,/\bcargo\s+(install|add)\b/,/\bgo\s+(install|get)\b/,/\brustup\b/,/\basdf\b/,/\bvolta\b/,/\bdeno\s+install\b/];function w(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!I.some(o=>o.test(e)))return[];let r=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:s(r),priority:2}]}function C(t){if(t.tool_name!=="Skill")return[];let e=String(t.tool_input.skill??"");return[{type:"skill",category:"skill",data:s(e),priority:2}]}function H(t){if(!t.tool_response?.includes("Error")&&!t.tool_output?.isError)return[];let e=String(t.tool_response||""),n=[/not supported/i,/cannot/i,/does not support/i,/FAIL/i,/refused/i,/permission denied/i,/incompatible/i];for(let r of n){let o=e.match(r);if(o){let i=e.toLowerCase().indexOf(o[0].toLowerCase()),a=e.slice(Math.max(0,i-50),Math.min(e.length,i+200)).trim();return[{type:"constraint_discovered",category:"constraint",data:s(a),priority:2}]}}return[]}function L(t){if(t.tool_name!=="Agent")return[];let e=s(String(t.tool_input.prompt??t.tool_input.description??"")),n=t.tool_response?s(String(t.tool_response)):"",r=n.length>0;return[{type:r?"subagent_completed":"subagent_launched",category:"subagent",data:s(r?`[completed] ${e} \u2192 ${n}`:`[launched] ${e}`),priority:r?2:3}]}function N(t){let{tool_name:e,tool_input:n,tool_response:r}=t;if(!e.startsWith("mcp__"))return[];let o=e.split("__"),i=o[o.length-1]||e,a=Object.values(n).find(m=>typeof m=="string"),p=a?`: ${s(String(a))}`:"",S=r&&r.length>0?`
2
- response: ${s(r)}`:"";return[{type:"mcp",category:"mcp",data:s(`${i}${p}${S}`),priority:3}]}var $=2048;function P(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let n=Buffer.from(t,"utf8"),r=e;for(;r>0&&(n[r]&192)===128;)r--;return{value:n.subarray(0,r).toString("utf8"),truncated:!0}}var O=/(authorization|auth_token|access_token|refresh_token|bearer|token|secret|password|passwd|pwd|api[-_]?key|apikey|cookie|set-cookie|signature|private[-_]?key|client[-_]?secret|x[-_]?api[-_]?key)/i,M="[REDACTED]";function d(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let n;if(Array.isArray(t))n=t.map(r=>d(r,e));else{let r={};for(let[o,i]of Object.entries(t))O.test(o)?r[o]=M:r[o]=d(i,e);n=r}return e.delete(t),n}function B(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let r=d(n??{}),o;try{o=JSON.stringify(r)}catch{o="{}"}let{value:i,truncated:a}=P(o,$),p=a?`{"tool_name":${JSON.stringify(e)},"params_raw":${JSON.stringify(i)},"truncated":true}`:`{"tool_name":${JSON.stringify(e)},"params":${i}}`;return[{type:"mcp_tool_call",category:"mcp_tool_call",data:s(p),priority:4}]}function W(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",r=s(String(t.tool_response??"")),o=n?`Q: ${s(n)} \u2192 A: ${r}`:`answer: ${r}`;return[{type:"decision_question",category:"decision",data:s(o),priority:2}]}function j(t){if(t.tool_name!=="Agent")return[];if(!t.tool_response||t.tool_response.length===0)return[];let e=t.tool_response.length>500?t.tool_response.slice(0,500):t.tool_response;return[{type:"agent_finding",category:"agent-finding",data:s(e),priority:2}]}function D(t){let e=[h(t.tool_input),s(t.tool_response)].join(" ");if(e.length===0)return[];let n=new Set,r=e.match(/https?:\/\/[^\s)]+/g);if(r)for(let i of r)i=i.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(i)||n.add(i);let o=e.match(/(?<!\w)#(\d+)/g);if(o)for(let i of o)n.add(i);return n.size===0?[]:[{type:"external_ref",category:"external-ref",data:s(Array.from(n).join(", ")),priority:3}]}function U(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:s(`entered worktree: ${e}`),priority:2}]}var b=/[,;,;、،]/u,F=15,K=500;function G(t){if(f.test(t)||!g.test(t)||!b.test(t))return!1;let e=[...t].length;return e>=F&&e<=K}function J(t){let e=t.trim();return G(e)?[{type:"decision",category:"decision",data:s(t),priority:2}]:[]}var q=8,z=120,Q=new RegExp("\\p{L}+\\s+\\p{L}+","u"),V=new RegExp("\\p{L}{6,}","u");function X(t){let e=t.split(/[.!\n。!]/u)[0].trim();if(f.test(e)||b.test(e)||!g.test(e))return!1;let n=[...e].length;return n<q||n>z?!1:Q.test(e)||V.test(e)}function Y(t){let e=t.trim();return X(e)?[{type:"role",category:"role",data:s(t),priority:3}]:[]}var f=/[??؟¿]/u,g=new RegExp("\\p{L}","u"),Z=60;function tt(t){if(f.test(t)||!g.test(t))return!1;let e=[...t].length;return e>0&&e<Z}function et(t){let e=t.trim();if(!e)return[];let n;return f.test(e)?n="investigate":tt(e)&&(n="implement"),n?[{type:"intent",category:"intent",data:s(n),priority:4}]:[]}var nt=/(?:\bError\s*:|\bException\s*:|\bTraceback\b|\bat\s+\S+\s*\([^)]*:\d+:\d+\))/u,rt=/[✓✔✅☑🎉]/u,ot=/^\s*(?:fixed|resolved)\s*:/iu;function it(t){let e=[];return rt.test(t)||ot.test(t)?(e.push({type:"blocker_resolved",category:"blocked-on",data:s(t),priority:2}),e):(nt.test(t)&&e.push({type:"blocker",category:"blocked-on",data:s(t),priority:2}),e)}function st(t){return t.length<=1024?[]:[{type:"data",category:"data",data:s(t),priority:4}]}var c=null;function at(t){let{tool_name:e,tool_response:n}=t,r=String(n??"");if(u(t))return c={tool:e,error:r.slice(0,200),callsSince:0},[];if(!c)return[];if(c.callsSince++,c.callsSince>10)return c=null,[];if(!!u(t))return[];let i=e===c.tool,a=c.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(i||a){let p={type:"error_resolved",category:"error-resolution",data:s(`Error in ${c.tool}: ${c.error} \u2192 Fixed`),priority:2};return c=null,[p]}return[]}function ft(){c=null}var l=[];function ct(t){return`${t.length}:${t.slice(0,20)}`}function lt(t){let{tool_name:e,tool_input:n}=t,r=ct(JSON.stringify(n).slice(0,200));if(l.push({tool:e,inputHash:r}),l.length>50&&l.splice(0,l.length-50),l.length<3)return[];let o=0;for(let i=l.length-1;i>=0&&(l[i].tool===e&&l[i].inputHash===r);i--)o++;return o>=3?(l.splice(l.length-o),[{type:"retry_detected",category:"iteration-loop",data:s(`${e} called ${o} times with similar input`),priority:2}]):[]}function dt(){l.length=0}var pt={run_shell_command:"Bash",read_file:"Read",read_many_files:"Read",grep_search:"Grep",search_file_content:"Grep",web_fetch:"WebFetch",write_file:"Write",edit:"Edit",glob:"Glob",todo_write:"TodoWrite",ask_user_question:"AskUserQuestion",list_directory:"LS",save_memory:"Memory",skill:"Skill",exit_plan_mode:"ExitPlanMode",agent:"Agent",bash:"Bash",view:"Read",grep:"Grep",fetch:"WebFetch",shell:"Bash",shell_command:"Bash",exec_command:"Bash","container.exec":"Bash",local_shell:"Bash",grep_files:"Grep"};function ut(t){let e=pt[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function gt(t){try{let e=ut(t),n=[];return n.push(...E(e)),n.push(...k(e)),n.push(...A(e)),n.push(...v(e)),n.push(...w(e)),n.push(...T(e)),n.push(...x(e)),n.push(...C(e)),n.push(...L(e)),n.push(...N(e)),n.push(...B(e)),n.push(...W(e)),n.push(...H(e)),n.push(...U(e)),n.push(...j(e)),n.push(...D(e)),n.push(...at(e)),n.push(...lt(e)),n}catch{return[]}}function _t(t){try{let e=[];return e.push(...J(t)),e.push(...Y(t)),e.push(...et(t)),e.push(...it(t)),e.push(...st(t)),e}catch{return[]}}export{gt as extractEvents,_t as extractUserEvents,ft as resetErrorResolutionState,dt as resetIterationLoopState};
1
+ function s(t){return t==null?"":String(t)}function y(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function d(t){let e=String(t.tool_response??""),n=t.tool_output?.isError===!0||t.tool_output?.is_error===!0;return t.tool_name==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(e)||n}function b(t){if(!t)return[];let e=[];for(let o of t.split(/\r?\n/)){if(o.startsWith("*** Add File: ")){e.push({path:o.slice(14).trim(),type:"file_write"});continue}if(o.startsWith("*** Update File: ")){e.push({path:o.slice(17).trim(),type:"file_edit"});continue}if(o.startsWith("*** Delete File: ")){e.push({path:o.slice(17).trim(),type:"file_edit"});continue}o.startsWith("*** Move to: ")&&e.push({path:o.slice(13).trim(),type:"file_edit"})}let n=new Set;return e.filter(o=>{if(!o.path)return!1;let r=`${o.type}:${o.path}`;return n.has(r)?!1:(n.add(r),!0)})}function h(t){return/(?:^|[/\\])\.claude[/\\]plans[/\\]/.test(t)}function E(t){let{tool_name:e,tool_input:n,tool_response:o}=t,r=[];if(e==="Read"){let i=String(n.file_path??"");return(/(?:CLAUDE|AGENTS(?:\.override)?|GEMINI|QWEN|KIRO)\.md$/i.test(i)||/\/copilot-instructions\.md$/i.test(i)||/\/context-mode\.mdc$/i.test(i)||/\.claude[\\/]/i.test(i)||/[\\/]memor(?:y|ies)[\\/][^\\/]+\.md$/i.test(i))&&(r.push({type:"rule",category:"rule",data:s(i),priority:1}),o&&o.length>0&&r.push({type:"rule_content",category:"rule",data:s(o),priority:1})),r.push({type:"file_read",category:"file",data:s(i),priority:1}),r}if(e==="Edit"){let i=String(n.file_path??"");return r.push({type:"file_edit",category:"file",data:s(i),priority:1}),r}if(e==="NotebookEdit"){let i=String(n.notebook_path??"");return r.push({type:"file_edit",category:"file",data:s(i),priority:1}),r}if(e==="Write"){let i=String(n.file_path??"");return r.push({type:"file_write",category:"file",data:s(i),priority:1}),r}if(e==="apply_patch"){if(d(t))return[];let i=b(String(n.command??n.patch??""));for(let a of i)r.push({type:a.type,category:"file",data:s(a.path),priority:1});return r}if(e==="Glob"){let i=String(n.pattern??"");return r.push({type:"file_glob",category:"file",data:s(i),priority:3}),r}if(e==="Grep"){let i=String(n.pattern??""),a=String(n.path??"");return r.push({type:"file_search",category:"file",data:s(`${i} in ${a}`),priority:3}),r}return r}function k(t){if(t.tool_name!=="Bash")return[];let n=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!n)return[];let o=n[2]??n[3]??n[4]??"";return[{type:"cwd",category:"cwd",data:s(o),priority:2}]}function v(t){let{tool_response:e}=t,n=String(e??"");return d(t)?[{type:"error_tool",category:"error",data:s(n),priority:2}]:[]}var A=[{pattern:/\bgit\s+checkout\b/,operation:"branch"},{pattern:/\bgit\s+commit\b/,operation:"commit"},{pattern:/\bgit\s+merge\s+\S+/,operation:"merge"},{pattern:/\bgit\s+rebase\b/,operation:"rebase"},{pattern:/\bgit\s+stash\b/,operation:"stash"},{pattern:/\bgit\s+push\b/,operation:"push"},{pattern:/\bgit\s+pull\b/,operation:"pull"},{pattern:/\bgit\s+log\b/,operation:"log"},{pattern:/\bgit\s+diff\b/,operation:"diff"},{pattern:/\bgit\s+status\b/,operation:"status"},{pattern:/\bgit\s+branch\b/,operation:"branch"},{pattern:/\bgit\s+reset\b/,operation:"reset"},{pattern:/\bgit\s+add\b/,operation:"add"},{pattern:/\bgit\s+cherry-pick\b/,operation:"cherry-pick"},{pattern:/\bgit\s+tag\b/,operation:"tag"},{pattern:/\bgit\s+fetch\b/,operation:"fetch"},{pattern:/\bgit\s+clone\b/,operation:"clone"},{pattern:/\bgit\s+worktree\b/,operation:"worktree"}];function R(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),n=A.find(o=>o.pattern.test(e));return n?[{type:"git",category:"git",data:s(n.operation),priority:2}]:[]}function T(t){return new Set(["TodoWrite","TaskCreate","TaskUpdate"]).has(t.tool_name)?[{type:t.tool_name==="TaskUpdate"?"task_update":t.tool_name==="TaskCreate"?"task_create":"task",category:"task",data:s(JSON.stringify(t.tool_input)),priority:1}]:[]}function x(t){if(t.tool_name==="EnterPlanMode")return[{type:"plan_enter",category:"plan",data:"entered plan mode",priority:2}];if(t.tool_name==="ExitPlanMode"){let e=[],n=t.tool_input.allowedPrompts,o=Array.isArray(n)&&n.length>0?`exited plan mode (allowed: ${y(n.map(i=>typeof i=="object"&&i!==null&&"prompt"in i?String(i.prompt):String(i)).join(", "))})`:"exited plan mode";e.push({type:"plan_exit",category:"plan",data:s(o),priority:2});let r=String(t.tool_response??"").toLowerCase();return r.includes("approved")||r.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(r.includes("rejected")||r.includes("decline")||r.includes("denied"))&&e.push({type:"plan_rejected",category:"plan",data:s(`plan rejected: ${t.tool_response??""}`),priority:2}),e}if(t.tool_name==="Write"||t.tool_name==="Edit"){let e=String(t.tool_input.file_path??"");if(h(e))return[{type:"plan_file_write",category:"plan",data:s(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return t.tool_name==="apply_patch"?d(t)?[]:b(String(t.tool_input.command??t.tool_input.patch??"")).filter(n=>h(n.path)).map(n=>({type:"plan_file_write",category:"plan",data:s(`plan file: ${n.path.split(/[/\\]/).pop()??n.path}`),priority:2})):[]}var I=[/\bsource\s+\S*activate\b/,/\bexport\s+\w+=/,/\bnvm\s+use\b/,/\bpyenv\s+(shell|local|global)\b/,/\bconda\s+activate\b/,/\brbenv\s+(shell|local|global)\b/,/\bnpm\s+install\b/,/\bnpm\s+ci\b/,/\bpip\s+install\b/,/\bbun\s+install\b/,/\byarn\s+(add|install)\b/,/\bpnpm\s+(add|install)\b/,/\bcargo\s+(install|add)\b/,/\bgo\s+(install|get)\b/,/\brustup\b/,/\basdf\b/,/\bvolta\b/,/\bdeno\s+install\b/];function w(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!I.some(r=>r.test(e)))return[];let o=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:s(o),priority:2}]}function N(t){if(t.tool_name!=="Skill")return[];let e=String(t.tool_input.skill??"");return[{type:"skill",category:"skill",data:s(e),priority:2}]}function C(t){if(!t.tool_response?.includes("Error")&&!t.tool_output?.isError)return[];let e=String(t.tool_response||""),n=[/not supported/i,/cannot/i,/does not support/i,/FAIL/i,/refused/i,/permission denied/i,/incompatible/i];for(let o of n){let r=e.match(o);if(r){let i=e.toLowerCase().indexOf(r[0].toLowerCase()),a=e.slice(Math.max(0,i-50),Math.min(e.length,i+200)).trim();return[{type:"constraint_discovered",category:"constraint",data:s(a),priority:2}]}}return[]}function H(t){if(t.tool_name!=="Agent")return[];let e=s(String(t.tool_input.prompt??t.tool_input.description??"")),n=t.tool_response?s(String(t.tool_response)):"",o=n.length>0;return[{type:o?"subagent_completed":"subagent_launched",category:"subagent",data:s(o?`[completed] ${e} \u2192 ${n}`:`[launched] ${e}`),priority:o?2:3}]}function L(t){let{tool_name:e,tool_input:n,tool_response:o}=t;if(!e.startsWith("mcp__"))return[];let r=e.split("__"),i=r[r.length-1]||e,a=Object.values(n).find(S=>typeof S=="string"),u=a?`: ${s(String(a))}`:"",c=o&&o.length>0?`
2
+ response: ${s(o)}`:"";return[{type:"mcp",category:"mcp",data:s(`${i}${u}${c}`),priority:3}]}var $=2048;function P(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let n=Buffer.from(t,"utf8"),o=e;for(;o>0&&(n[o]&192)===128;)o--;return{value:n.subarray(0,o).toString("utf8"),truncated:!0}}var O=/(authorization|auth_token|access_token|refresh_token|bearer|token|secret|password|passwd|pwd|api[-_]?key|apikey|cookie|set-cookie|signature|private[-_]?key|client[-_]?secret|x[-_]?api[-_]?key)/i,M="[REDACTED]";function g(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let n;if(Array.isArray(t))n=t.map(o=>g(o,e));else{let o={};for(let[r,i]of Object.entries(t))O.test(r)?o[r]=M:o[r]=g(i,e);n=o}return e.delete(t),n}function B(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let o=g(n??{}),r;try{r=JSON.stringify(o)}catch{r="{}"}let{value:i,truncated:a}=P(r,$),u=a?`{"tool_name":${JSON.stringify(e)},"params_raw":${JSON.stringify(i)},"truncated":true}`:`{"tool_name":${JSON.stringify(e)},"params":${i}}`;return[{type:"mcp_tool_call",category:"mcp_tool_call",data:s(u),priority:4}]}function W(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",o=s(String(t.tool_response??"")),r=n?`Q: ${s(n)} \u2192 A: ${o}`:`answer: ${o}`;return[{type:"decision_question",category:"decision",data:s(r),priority:2}]}function F(t){if(t.tool_name!=="Agent")return[];if(!t.tool_response||t.tool_response.length===0)return[];let e=t.tool_response.length>500?t.tool_response.slice(0,500):t.tool_response;return[{type:"agent_finding",category:"agent-finding",data:s(e),priority:2}]}function j(t){let e=[y(t.tool_input),s(t.tool_response)].join(" ");if(e.length===0)return[];let n=new Set,o=e.match(/https?:\/\/[^\s)]+/g);if(o)for(let c of o)c=c.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(c)||n.add(c);let r=e.match(/(?<!\w)#(\d+)/g);if(r)for(let c of r)n.add(c);if(n.size===0)return[];let i,a=s(t.tool_response).match(/Fetched and indexed[^\(]*\(([\d.]+)\s*KB\)/i);if(a){let c=Number(a[1]);Number.isFinite(c)&&c>0&&(i=Math.round(c*1024))}let u={type:"external_ref",category:"external-ref",data:s(Array.from(n).join(", ")),priority:3};return i!==void 0&&(u.bytes_avoided=i),[u]}function D(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:s(`entered worktree: ${e}`),priority:2}]}var m=/[,;,;、،]/u,U=15,K=500;function G(t){if(f.test(t)||!_.test(t)||!m.test(t))return!1;let e=[...t].length;return e>=U&&e<=K}function J(t){let e=t.trim();return G(e)?[{type:"decision",category:"decision",data:s(t),priority:2}]:[]}var q=8,z=120,Q=new RegExp("\\p{L}+\\s+\\p{L}+","u"),V=new RegExp("\\p{L}{6,}","u");function X(t){let e=t.split(/[.!\n。!]/u)[0].trim();if(f.test(e)||m.test(e)||!_.test(e))return!1;let n=[...e].length;return n<q||n>z?!1:Q.test(e)||V.test(e)}function Y(t){let e=t.trim();return X(e)?[{type:"role",category:"role",data:s(t),priority:3}]:[]}var f=/[??؟¿]/u,_=new RegExp("\\p{L}","u"),Z=60;function tt(t){if(f.test(t)||!_.test(t))return!1;let e=[...t].length;return e>0&&e<Z}function et(t){let e=t.trim();if(!e)return[];let n;return f.test(e)?n="investigate":tt(e)&&(n="implement"),n?[{type:"intent",category:"intent",data:s(n),priority:4}]:[]}var nt=/(?:\bError\s*:|\bException\s*:|\bTraceback\b|\bat\s+\S+\s*\([^)]*:\d+:\d+\))/u,ot=/[✓✔✅☑🎉]/u,rt=/^\s*(?:fixed|resolved)\s*:/iu;function it(t){let e=[];return ot.test(t)||rt.test(t)?(e.push({type:"blocker_resolved",category:"blocked-on",data:s(t),priority:2}),e):(nt.test(t)&&e.push({type:"blocker",category:"blocked-on",data:s(t),priority:2}),e)}function st(t){return t.length<=1024?[]:[{type:"data",category:"data",data:s(t),priority:4}]}var l=null;function at(t){let{tool_name:e,tool_response:n}=t,o=String(n??"");if(d(t))return l={tool:e,error:o.slice(0,200),callsSince:0},[];if(!l)return[];if(l.callsSince++,l.callsSince>10)return l=null,[];if(!!d(t))return[];let i=e===l.tool,a=l.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(i||a){let u={type:"error_resolved",category:"error-resolution",data:s(`Error in ${l.tool}: ${l.error} \u2192 Fixed`),priority:2};return l=null,[u]}return[]}function dt(){l=null}var p=[];function ct(t){return`${t.length}:${t.slice(0,20)}`}function lt(t){let{tool_name:e,tool_input:n}=t,o=ct(JSON.stringify(n).slice(0,200));if(p.push({tool:e,inputHash:o}),p.length>50&&p.splice(0,p.length-50),p.length<3)return[];let r=0;for(let i=p.length-1;i>=0&&(p[i].tool===e&&p[i].inputHash===o);i--)r++;return r>=3?(p.splice(p.length-r),[{type:"retry_detected",category:"iteration-loop",data:s(`${e} called ${r} times with similar input`),priority:2}]):[]}function ft(){p.length=0}var pt={run_shell_command:"Bash",read_file:"Read",read_many_files:"Read",grep_search:"Grep",search_file_content:"Grep",web_fetch:"WebFetch",write_file:"Write",edit:"Edit",glob:"Glob",todo_write:"TodoWrite",ask_user_question:"AskUserQuestion",list_directory:"LS",save_memory:"Memory",skill:"Skill",exit_plan_mode:"ExitPlanMode",agent:"Agent",bash:"Bash",view:"Read",grep:"Grep",fetch:"WebFetch",shell:"Bash",shell_command:"Bash",exec_command:"Bash","container.exec":"Bash",local_shell:"Bash",grep_files:"Grep"};function ut(t){let e=pt[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function gt(t){try{let e=ut(t),n=[];return n.push(...E(e)),n.push(...k(e)),n.push(...v(e)),n.push(...R(e)),n.push(...w(e)),n.push(...T(e)),n.push(...x(e)),n.push(...N(e)),n.push(...H(e)),n.push(...L(e)),n.push(...B(e)),n.push(...W(e)),n.push(...C(e)),n.push(...D(e)),n.push(...F(e)),n.push(...j(e)),n.push(...at(e)),n.push(...lt(e)),n}catch{return[]}}function _t(t){try{let e=[];return e.push(...J(t)),e.push(...Y(t)),e.push(...et(t)),e.push(...it(t)),e.push(...st(t)),e}catch{return[]}}export{gt as extractEvents,_t as extractUserEvents,dt as resetErrorResolutionState,ft as resetIterationLoopState};
@@ -74,13 +74,26 @@ export function attributeAndInsertEvents(db, sessionId, events, input, projectDi
74
74
  workspaceRoots: Array.isArray(input.workspace_roots) ? input.workspace_roots : [],
75
75
  lastKnownProjectDir,
76
76
  });
77
+ // Build a parallel bytesList from event-level bytes_avoided (currently
78
+ // populated by external_ref's ctx_fetch_and_index preamble parser). When
79
+ // no event carries a positive value we leave bytesList undefined so
80
+ // SessionDB falls back to its 0-default for bytes_avoided/bytes_returned
81
+ // — preserves backward compat with older callers / tests.
82
+ let bytesList;
83
+ if (events.some((e) => typeof e?.bytes_avoided === "number" && e.bytes_avoided > 0)) {
84
+ bytesList = events.map((e) =>
85
+ typeof e?.bytes_avoided === "number" && e.bytes_avoided > 0
86
+ ? { bytesAvoided: e.bytes_avoided }
87
+ : undefined,
88
+ );
89
+ }
77
90
  // Prefer bulk path (single transaction = single WAL commit). Falls back
78
91
  // to per-event insert for older SessionDB instances that lack bulkInsertEvents.
79
92
  if (typeof db.bulkInsertEvents === "function") {
80
- db.bulkInsertEvents(sessionId, events, hookName, attributions);
93
+ db.bulkInsertEvents(sessionId, events, hookName, attributions, bytesList);
81
94
  } else {
82
95
  for (let i = 0; i < events.length; i++) {
83
- db.insertEvent(sessionId, events[i], hookName, attributions[i]);
96
+ db.insertEvent(sessionId, events[i], hookName, attributions[i], bytesList?.[i]);
84
97
  }
85
98
  }
86
99
  return attributions;
@@ -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.131",
6
+ "version": "1.0.133",
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.131",
3
+ "version": "1.0.133",
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",
@@ -124,5 +124,8 @@
124
124
  "typescript": "^5.7.0",
125
125
  "vitest": "^4.0.18"
126
126
  },
127
- "packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b"
127
+ "packageManager": "pnpm@10.23.0+sha512.21c4e5698002ade97e4efe8b8b4a89a8de3c85a37919f957e7a0f30f38fbc5bbdd05980ffe29179b2fb6e6e691242e098d945d1601772cad0fef5fb6411e2a4b",
128
+ "engines": {
129
+ "node": ">=22.5.0"
130
+ }
128
131
  }
@@ -30,6 +30,15 @@
30
30
  *
31
31
  * @see https://github.com/mksglu/context-mode/issues/408
32
32
  * @see https://github.com/mksglu/context-mode/issues/533
33
+ *
34
+ * Windows VS 2026+ detection:
35
+ * node-gyp has a hardcoded internal-version→year map. VS 2026 (internal
36
+ * major 18) was absent from older node-gyp builds, causing "unknown version"
37
+ * failures on machines that only have VS 2026 installed. Rather than
38
+ * extending the map (which would break again with VS 2029, etc.), we query
39
+ * vswhere's `displayName` property ("Visual Studio Community 2026") and
40
+ * extract the 4-digit year with a regex. `catalog_productLineVersion` is NOT
41
+ * used — it returns the internal major ("18") on VS 2026, not the year.
33
42
  */
34
43
 
35
44
  import { existsSync as fsExistsSync } from "node:fs";
@@ -137,11 +146,90 @@ function isCondaActive(env = process.env) {
137
146
  return pathEntries.some((dir) => !isSafePythonPath(dir + "/python3"));
138
147
  }
139
148
 
149
+ /**
150
+ * Detect the installed Visual Studio year string via vswhere.exe.
151
+ *
152
+ * Uses the `displayName` property (e.g. "Visual Studio Community 2026")
153
+ * and extracts the 4-digit year with a regex. This is more reliable than
154
+ * `catalog_productLineVersion`, which returns the internal major version
155
+ * number ("18") on VS 2026 instead of the year — making it useless as a
156
+ * direct msvs_version value without a mapping table.
157
+ *
158
+ * `displayName` has consistently included the branded year across every
159
+ * VS release (2017, 2019, 2022, 2026) and will continue to do so because
160
+ * it is the user-visible product name Microsoft ships.
161
+ *
162
+ * Dependency-injected so unit tests can exercise all branches without
163
+ * spawning a real process or requiring vswhere to be present on the host.
164
+ *
165
+ * Returns null on non-Windows, when vswhere is absent, or on any error.
166
+ *
167
+ * Timeout: 15s. Cold-disk vswhere queries on HDD-backed Windows CI runners
168
+ * with multiple VS installs have been observed to exceed the previous 5s
169
+ * budget (see ARCH-REVIEW #571 Part B). 15s comfortably covers slow-disk
170
+ * scenarios without freezing /ctx-upgrade.
171
+ *
172
+ * Year sanity cap: the regex matches any 21st-century 4-digit year, but
173
+ * we additionally reject anything > currentYear+5. Corrupted vswhere
174
+ * output or a future MS rebrand could surface a bogus "2099"; passing
175
+ * that through to `npm_config_msvs_version` would fail node-gyp
176
+ * silently. Cap-and-null lets the caller fall back to node-gyp's own
177
+ * detection and we log a single stderr breadcrumb for support triage.
178
+ *
179
+ * @param {object} [deps]
180
+ * @param {string} [deps.platform] - process.platform override
181
+ * @param {(p: string) => boolean} [deps.existsSync] - fs probe override
182
+ * @param {(cmd: string, opts: object) => string} [deps.exec] - execSync override
183
+ * @param {() => number} [deps.now] - clock override for sanity cap (test seam)
184
+ * @returns {string | null}
185
+ */
186
+ export function detectWindowsVsYear({
187
+ platform = process.platform,
188
+ existsSync = fsExistsSync,
189
+ exec = execSync,
190
+ now = () => new Date().getFullYear(),
191
+ } = {}) {
192
+ if (platform !== "win32") return null;
193
+ try {
194
+ const vswhere =
195
+ "C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe";
196
+ if (!existsSync(vswhere)) return null;
197
+ const displayName = exec(
198
+ `"${vswhere}" -latest -property displayName`,
199
+ { encoding: "utf-8", stdio: "pipe", timeout: 15000 },
200
+ ).trim();
201
+ // "Visual Studio Community 2026" → "2026"
202
+ const match = displayName.match(/\b(20\d{2})\b/);
203
+ if (!match) return null;
204
+ const year = Number(match[1]);
205
+ const ceiling = now() + 5;
206
+ if (year > ceiling) {
207
+ // Fail LOUD, not silent: poisoning npm_config_msvs_version with
208
+ // a bogus year would manifest as opaque node-gyp errors deep in
209
+ // the rebuild. Surface a breadcrumb and return null so the caller
210
+ // falls back to node-gyp's own version detection.
211
+ try {
212
+ process.stderr.write(
213
+ `[context-mode] vswhere displayName reports VS year ${year} ` +
214
+ `(> ${ceiling}); ignoring as likely corrupted output. ` +
215
+ `Falling back to node-gyp default detection.\n`,
216
+ );
217
+ } catch { /* stderr unavailable — proceed silently */ }
218
+ return null;
219
+ }
220
+ return match[1];
221
+ } catch {
222
+ return null;
223
+ }
224
+ }
225
+
140
226
  /**
141
227
  * Build the child-process env for an npm/node-gyp invocation. Pins
142
228
  * PYTHON + npm_config_python to the resolved safe interpreter, strips
143
- * CONDA_* keys, and prepends /usr/bin to PATH on darwin so any
144
- * downstream PATH-based python3 lookup also resolves to system python.
229
+ * CONDA_* keys, prepends /usr/bin to PATH on darwin so any downstream
230
+ * PATH-based python3 lookup resolves to system python, and on Windows
231
+ * injects npm_config_msvs_version from vswhere so node-gyp finds VS
232
+ * regardless of which major version is installed.
145
233
  *
146
234
  * @param {string | null} safePython - output of resolveSafePython()
147
235
  * @param {NodeJS.ProcessEnv} [base] - starting env (defaults to process.env)
@@ -171,6 +259,15 @@ function buildSafeEnv(safePython, base = process.env) {
171
259
  env.PATH = "/usr/bin:" + parts.filter((p) => p !== "/usr/bin").join(":");
172
260
  }
173
261
  }
262
+ // ── Windows: pin npm_config_msvs_version via vswhere (#VS2026) ───────
263
+ // node-gyp defaults to VS 2022. On machines that only have VS 2026 (or
264
+ // a later release) installed the build fails with "unknown version" or
265
+ // "msvs_version does not match". Querying vswhere directly gives us the
266
+ // correct year string without a hardcoded mapping table.
267
+ if (process.platform === "win32" && !env.npm_config_msvs_version) {
268
+ const year = detectWindowsVsYear();
269
+ if (year) env.npm_config_msvs_version = year;
270
+ }
174
271
  return env;
175
272
  }
176
273
 
@@ -19,6 +19,64 @@ import { healInstalledPlugins, healSettingsEnabledPlugins, healPluginJsonMcpServ
19
19
  const __dirname = dirname(fileURLToPath(import.meta.url));
20
20
  const pkgRoot = resolve(__dirname, "..");
21
21
 
22
+ // ── -2. Issue #564 — Linux SIGSEGV class hard-fail (v1.0.132) ────────
23
+ // On Linux + Node < 22.5 + no Bun, better-sqlite3's native addon is
24
+ // vulnerable to V8 calling `madvise(MADV_DONTNEED)` on memory ranges
25
+ // that overlap the addon's `.got.plt` section, corrupting resolved
26
+ // symbol addresses and causing sporadic SIGSEGV (1-4/hour) — see
27
+ // https://github.com/nodejs/node/issues/62515 and our internal #564.
28
+ //
29
+ // node:sqlite (built-in, no native addon, no .got.plt to corrupt) ships
30
+ // from Node 22.5 onward — that is the contract `hasModernSqlite()` in
31
+ // src/db-base.ts encodes. Six prior fixes (#228, #331, #461, #540,
32
+ // #551, #556) silently assumed users had Node >= 22.5 on Linux; #564
33
+ // is the second confirmed report (after #556) of the same SIGSEGV
34
+ // class on Node 20.
35
+ //
36
+ // The architect mandate for v1.0.132 is HARD-FAIL, not warn-then-
37
+ // degrade. `engines.node >= 22.5.0` in package.json is cosmetic under
38
+ // the default npm `engine-strict=false`, so the contract has to be
39
+ // enforced HERE — preinstall/postinstall is the only place that can
40
+ // `process.exit(1)` across npm/pnpm/yarn.
41
+ //
42
+ // Linux + Bun is allowed through (bun:sqlite sidesteps better-sqlite3
43
+ // entirely). Non-Linux platforms are unaffected by the madvise bug
44
+ // and pass through unchanged.
45
+ {
46
+ const isLinux = process.platform === "linux";
47
+ const hasBun =
48
+ typeof globalThis.Bun !== "undefined" ||
49
+ typeof process.versions.bun === "string";
50
+ const [majStr, minStr] = (process.versions.node ?? "0.0.0").split(".");
51
+ const major = Number(majStr);
52
+ const minor = Number(minStr);
53
+ const hasModernNode =
54
+ Number.isFinite(major) &&
55
+ Number.isFinite(minor) &&
56
+ (major > 22 || (major === 22 && minor >= 5));
57
+ if (isLinux && !hasBun && !hasModernNode) {
58
+ process.stderr.write(
59
+ "\n" +
60
+ "context-mode: install aborted\n" +
61
+ " Linux + Node " + (process.versions.node ?? "?") + " is unsupported.\n" +
62
+ " context-mode requires Node.js >= 22.5 (or Bun) on Linux to avoid the\n" +
63
+ " V8 madvise(MADV_DONTNEED) SIGSEGV affecting better-sqlite3 (1-4/hour).\n" +
64
+ " Tracking: https://github.com/nodejs/node/issues/62515\n" +
65
+ " https://github.com/mksglu/context-mode/issues/564\n" +
66
+ "\n" +
67
+ " Fix: upgrade Node (recommended)\n" +
68
+ " nvm install 22.5 && nvm use 22.5\n" +
69
+ " npm install -g context-mode\n" +
70
+ "\n" +
71
+ " Or: run under Bun\n" +
72
+ " curl -fsSL https://bun.sh/install | bash\n" +
73
+ " bun add -g context-mode\n" +
74
+ "\n",
75
+ );
76
+ process.exit(1);
77
+ }
78
+ }
79
+
22
80
  /**
23
81
  * True when running as a real `npm install -g context-mode`. We use this
24
82
  * to keep contributors' local `npm install` runs from rewriting their HOME's