@aerostack/gateway 0.15.12 → 0.15.13

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,5 +1,5 @@
1
- import{createServer as $}from"node:http";import{readFile as y,writeFile as w,appendFile as j,stat as W}from"node:fs/promises";import{watch as R}from"node:fs";import{homedir as O}from"node:os";import{join as C}from"node:path";import{info as a,warn as m,debug as b}from"./logger.js";const z=18321,E=3e4,D=200,H=new Set(["Bash","Write","Edit","NotebookEdit"]),B=new Set(["Read","Glob","Grep","LS","WebSearch","WebFetch","Agent","AskUserQuestion","TodoRead","TaskList","TaskGet"]);function x(i){const t=i.toLowerCase();return t.includes("rm ")||t.includes("rm ")||t.includes("rmdir")||t.includes("unlink")?{category:"file_delete",risk:"high"}:t.includes("git push")||t.includes("git reset")?{category:"deploy",risk:"high"}:t.includes("npm install")||t.includes("pip install")||t.includes("yarn add")?{category:"package_install",risk:"medium"}:t.includes("curl ")||t.includes("wget ")||t.includes("fetch")?{category:"api_call",risk:"low"}:t.includes("deploy")||t.includes("wrangler")?{category:"deploy",risk:"high"}:{category:"exec_command",risk:"low"}}function A(i,t){const e=i.toLowerCase();if(i==="Bash")return x(t.command||"");if(i==="Write")return{category:"file_write",risk:"medium"};if(i==="Edit"||i==="NotebookEdit")return{category:"file_write",risk:"low"};if(e==="exec"||e==="run_command"||e==="shell"||e==="bash"||e==="terminal"){const n=t.command??t.cmd??(Array.isArray(t.args)?t.args.join(" "):"")??"";return x(n)}return e==="write_file"||e==="create_file"||e==="save_file"?{category:"file_write",risk:"medium"}:e==="edit_file"||e==="str_replace_based_edit_tool"||e==="replace_in_file"||e==="patch_file"||e==="apply_patch"?{category:"file_write",risk:"low"}:e==="delete_file"||e==="remove_file"||e==="unlink_file"?{category:"file_delete",risk:"high"}:e==="read_file"||e==="view_file"||e==="cat_file"||e==="search_files"||e==="find_files"||e==="list_dir"?{category:"data_access",risk:"low"}:e==="web_search"||e==="search_web"||e==="browser_search"?{category:"api_call",risk:"low"}:e==="web_fetch"||e==="http_request"||e==="fetch_url"||e==="browser_navigate"?{category:"api_call",risk:"low"}:e.includes("install")||e==="pip_install"||e==="npm_install"||e==="package_install"?{category:"package_install",risk:"medium"}:e==="git_push"||e==="git_reset"||e==="deploy"||e==="publish"||e==="release"?{category:"deploy",risk:"high"}:e.startsWith("git_")||e==="git"?{category:"exec_command",risk:"low"}:e==="send_message"||e==="notify"||e.includes("telegram")||e.includes("slack")||e.includes("email")||e.includes("sms")?{category:"message_send",risk:"low"}:e.includes("__")?e.includes("delete")||e.includes("remove")||e.includes("destroy")||e.includes("unlink")||e.includes("trash")?{category:"file_delete",risk:"high"}:e.includes("deploy")||e.includes("publish")||e.includes("release")||e.includes("push")?{category:"deploy",risk:"high"}:e.includes("install")||e.includes("package")?{category:"package_install",risk:"medium"}:e.includes("exec")||e.includes("run")||e.includes("bash")||e.includes("shell")||e.includes("command")?{category:"exec_command",risk:"medium"}:e.includes("write")||e.includes("edit")||e.includes("create")||e.includes("update")||e.includes("upsert")||e.includes("patch")||e.includes("save")||e.includes("upload")?{category:"file_write",risk:"low"}:e.includes("send")||e.includes("message")||e.includes("notify")||e.includes("slack")||e.includes("telegram")||e.includes("discord")||e.includes("email")||e.includes("sms")||e.includes("comment")||e.includes("reply")?{category:"message_send",risk:"low"}:e.includes("config")||e.includes("setting")||e.includes("env")?{category:"config_change",risk:"low"}:e.includes("fetch")||e.includes("http")||e.includes("request")||e.includes("api")||e.includes("post")||e.includes("put")||e.includes("import")?{category:"api_call",risk:"low"}:{category:"data_access",risk:"low"}:{category:"other",risk:"low"}}function F(i,t){const e=i.toLowerCase();if(i==="Bash"||e==="exec"||e==="run_command"||e==="shell"||e==="bash"||e==="terminal")return((t.command??t.cmd??(Array.isArray(t.args)?t.args.join(" "):""))||"").slice(0,200);if(e==="write"||e==="edit"||i==="Write"||i==="Edit"||e==="write_file"||e==="edit_file"||e==="create_file"||e==="read_file"||e==="delete_file"||e==="view_file")return t.file_path??t.path??t.filepath??"";if(e==="web_search"||e==="search_web")return t.query?.slice(0,200)||"";if(e==="web_fetch"||e==="fetch_url"||e==="browser_navigate")return t.url?.slice(0,200)||"";const n=Object.keys(t);if(n.length===0)return"";const s=t[n[0]];return typeof s=="string"?s.slice(0,200):JSON.stringify(t).slice(0,200)}let _=[],u=null,v=null,f={enabled:!0,tools:["Bash","Write","Edit"],batch_interval_seconds:30,categories:["exec_command","file_write","file_delete","deploy","config_change"]},S=E;function Z(){return f}function N(i){f.enabled&&(_.length>=D&&_.shift(),_.push(i))}async function T(){if(_.length===0||!v)return;const i=_.splice(0);b(`Flushing ${i.length} hook events`);const t=await v(i);if(t){const e=JSON.stringify(f)!==JSON.stringify(t);f=t,e&&(a("Bridge config updated from gateway",{enabled:t.enabled,tools:t.tools}),t.batch_interval_seconds*1e3!==S&&(S=t.batch_interval_seconds*1e3,u&&(clearInterval(u),u=setInterval(()=>{T().catch(()=>{})},S),a("Batch interval updated",{seconds:t.batch_interval_seconds}))))}a(`Flushed ${i.length} hook events to gateway`)}let h=null,P=null;function M(i,t){if(i.method!=="POST"||!i.url?.startsWith("/hook")){t.writeHead(404),t.end();return}const e=[];i.on("data",n=>e.push(n)),i.on("end",()=>{try{const n=JSON.parse(Buffer.concat(e).toString()),s=n.tool_name??"";if(!f.tools.includes(s)&&!H.has(s)){t.writeHead(200,{"Content-Type":"application/json"}),t.end('{"status":"skipped"}');return}if(B.has(s)&&!f.tools.includes(s)){t.writeHead(200,{"Content-Type":"application/json"}),t.end('{"status":"skipped"}');return}const l=n.tool_input??{},{category:c,risk:r}=A(s,l),o=F(s,l);N({action:`${s}: ${o}`.slice(0,500),category:c,risk_level:r,details:JSON.stringify({tool:s,...l}).slice(0,500)}),b(`Hook received: ${s}`,{category:c,risk:r}),t.writeHead(200,{"Content-Type":"application/json"}),t.end('{"status":"queued"}')}catch{t.writeHead(400),t.end('{"error":"invalid JSON"}')}})}let k=null,p=0;async function J(){try{const i=await W(d).catch(()=>null);if(!i||i.size<=p)return;const t=await y(d,"utf-8"),e=t.split(`
2
- `).filter(Boolean),n=t.slice(p);p=i.size;const s=n.split(`
3
- `).filter(Boolean);for(const l of s)try{const c=JSON.parse(l),r=c.tool_name??"";if(B.has(r)||!H.has(r)&&!f.tools.includes(r))continue;const o=c.tool_input??{},{category:g,risk:L}=A(r,o),U=F(r,o);N({action:`${r}: ${U}`.slice(0,500),category:g,risk_level:L,details:JSON.stringify({tool:r,...o}).slice(0,500)}),b(`File hook event: ${r}`,{category:g})}catch{}i.size>1048576&&(await w(d,"","utf-8"),p=0)}catch{}}async function G(i,t=z){v=i;const e=await new Promise((n,s)=>{h=$(M),h.on("error",l=>{l.code==="EADDRINUSE"?(a(`Port ${t} in use, trying ${t+1}`),h.close(),G(i,t+1).then(n).catch(s)):(m("HTTP hook server failed, using file-based hooks only",{error:l.message}),n(0))}),h.listen(t,"127.0.0.1",()=>{P=t,a(`Hook server listening on http://127.0.0.1:${t}/hook`),n(t)})});try{await j(d,""),k=R(d,()=>{J().catch(()=>{})}),a("File watcher started",{path:d})}catch(n){m("File watcher failed",{error:n instanceof Error?n.message:String(n)})}return u=setInterval(()=>{J().catch(()=>{}),T().catch(n=>{m("Batch flush failed",{error:n instanceof Error?n.message:String(n)})})},E),e}function I(){u&&(clearInterval(u),u=null),T().catch(()=>{}),k&&(k.close(),k=null),h&&(h.close(),h=null),P=null}const ee="/* aerostack-guardian-hook */",d="/tmp/aerostack-guardian-events.jsonl";async function te(i){const t=C(O(),".claude","settings.json");try{let e={};try{const r=await y(t,"utf-8");e=JSON.parse(r)}catch{}const n=e.hooks??{},l=(n.PreToolUse??[]).filter(r=>!(r.hooks??[]).some(g=>g.url?.includes("127.0.0.1")&&g.url?.includes("/hook")||g.command?.includes("aerostack-guardian"))),c={matcher:"Bash|Write|Edit",hooks:[{type:"command",command:`cat >> ${d}`}]};return l.push(c),n.PreToolUse=l,e.hooks=n,await w(t,JSON.stringify(e,null,2)+`
4
- `,"utf-8"),a("Installed Claude Code hook (file-based)",{eventsFile:d,path:t}),!0}catch(e){return m("Failed to install Claude Code hook",{error:e instanceof Error?e.message:String(e)}),!1}}async function ie(){const i=C(O(),".claude","settings.json");try{const t=await y(i,"utf-8"),e=JSON.parse(t),n=e.hooks??{},s=n.PreToolUse??[],l=s.filter(c=>!(c.hooks??[]).some(o=>o.url?.includes("127.0.0.1")&&o.url?.includes("/hook")));return l.length===s.length?!1:(n.PreToolUse=l,e.hooks=n,await w(i,JSON.stringify(e,null,2)+`
5
- `,"utf-8"),a("Uninstalled Claude Code hook"),!0)}catch{return!1}}export{d as HOOK_EVENTS_FILE,N as addToBatch,A as detectCategory,Z as getBridgeConfig,te as installClaudeHook,G as startHookServer,I as stopHookServer,F as summarizeToolInput,ie as uninstallClaudeHook};
1
+ import{createServer as $}from"node:http";import{readFile as p,writeFile as w,appendFile as W,stat as j}from"node:fs/promises";import{watch as R}from"node:fs";import{homedir as O}from"node:os";import{join as E}from"node:path";import{info as o,warn as m,debug as v}from"./logger.js";const z=18321,C=3e4,D=200,H=new Set(["Bash","Write","Edit","NotebookEdit"]),B=new Set(["Read","Glob","Grep","LS","WebSearch","WebFetch","Agent","AskUserQuestion","TodoRead","TaskList","TaskGet"]);function x(i){const t=i.toLowerCase();return t.includes("rm ")||t.includes("rm ")||t.includes("rmdir")||t.includes("unlink")?{category:"file_delete",risk:"high"}:t.includes("git push")||t.includes("git reset")?{category:"deploy",risk:"high"}:t.includes("npm install")||t.includes("pip install")||t.includes("yarn add")?{category:"package_install",risk:"medium"}:t.includes("curl ")||t.includes("wget ")||t.includes("fetch")?{category:"api_call",risk:"low"}:t.includes("deploy")||t.includes("wrangler")?{category:"deploy",risk:"high"}:{category:"exec_command",risk:"low"}}const G=new Set(["file_write","file_delete","exec_command","api_call","package_install","config_change","deploy","message_send","data_access","credential_use","approval","other"]);function N(i,t){const e=i.toLowerCase();if(typeof t.category=="string"&&G.has(t.category)&&t.category!=="other"){const s=typeof t.risk_level=="string"?t.risk_level:"low";return{category:t.category,risk:s}}if(i==="Bash")return x(t.command||"");if(i==="Write")return{category:"file_write",risk:"medium"};if(i==="Edit"||i==="NotebookEdit")return{category:"file_write",risk:"low"};if(e==="exec"||e==="run_command"||e==="shell"||e==="bash"||e==="terminal"){const s=t.command??t.cmd??(Array.isArray(t.args)?t.args.join(" "):"")??"";return x(s)}return e==="write_file"||e==="create_file"||e==="save_file"?{category:"file_write",risk:"medium"}:e==="edit_file"||e==="str_replace_based_edit_tool"||e==="replace_in_file"||e==="patch_file"||e==="apply_patch"?{category:"file_write",risk:"low"}:e==="delete_file"||e==="remove_file"||e==="unlink_file"?{category:"file_delete",risk:"high"}:e==="read_file"||e==="view_file"||e==="cat_file"||e==="search_files"||e==="find_files"||e==="list_dir"?{category:"data_access",risk:"low"}:e==="web_search"||e==="search_web"||e==="browser_search"?{category:"api_call",risk:"low"}:e==="web_fetch"||e==="http_request"||e==="fetch_url"||e==="browser_navigate"?{category:"api_call",risk:"low"}:e.includes("install")||e==="pip_install"||e==="npm_install"||e==="package_install"?{category:"package_install",risk:"medium"}:e==="git_push"||e==="git_reset"||e==="deploy"||e==="publish"||e==="release"?{category:"deploy",risk:"high"}:e.startsWith("git_")||e==="git"?{category:"exec_command",risk:"low"}:e==="send_message"||e==="message_send"||e==="notify"||e.includes("telegram")||e.includes("slack")||e.includes("email")||e.includes("sms")?{category:"message_send",risk:"low"}:e.includes("__")?e.includes("delete")||e.includes("remove")||e.includes("destroy")||e.includes("unlink")||e.includes("trash")?{category:"file_delete",risk:"high"}:e.includes("deploy")||e.includes("publish")||e.includes("release")||e.includes("push")?{category:"deploy",risk:"high"}:e.includes("install")||e.includes("package")?{category:"package_install",risk:"medium"}:e.includes("exec")||e.includes("run")||e.includes("bash")||e.includes("shell")||e.includes("command")?{category:"exec_command",risk:"medium"}:e.includes("write")||e.includes("edit")||e.includes("create")||e.includes("update")||e.includes("upsert")||e.includes("patch")||e.includes("save")||e.includes("upload")?{category:"file_write",risk:"low"}:e.includes("send")||e.includes("message")||e.includes("notify")||e.includes("slack")||e.includes("telegram")||e.includes("discord")||e.includes("email")||e.includes("sms")||e.includes("comment")||e.includes("reply")?{category:"message_send",risk:"low"}:e.includes("config")||e.includes("setting")||e.includes("env")?{category:"config_change",risk:"low"}:e.includes("fetch")||e.includes("http")||e.includes("request")||e.includes("api")||e.includes("post")||e.includes("put")||e.includes("import")?{category:"api_call",risk:"low"}:{category:"data_access",risk:"low"}:{category:"other",risk:"low"}}function A(i,t){const e=i.toLowerCase();if(i==="Bash"||e==="exec"||e==="run_command"||e==="shell"||e==="bash"||e==="terminal")return((t.command??t.cmd??(Array.isArray(t.args)?t.args.join(" "):""))||"").slice(0,200);if(e==="write"||e==="edit"||i==="Write"||i==="Edit"||e==="write_file"||e==="edit_file"||e==="create_file"||e==="read_file"||e==="delete_file"||e==="view_file")return t.file_path??t.path??t.filepath??"";if(e==="web_search"||e==="search_web")return t.query?.slice(0,200)||"";if(e==="web_fetch"||e==="fetch_url"||e==="browser_navigate")return t.url?.slice(0,200)||"";const s=Object.keys(t);if(s.length===0)return"";const n=t[s[0]];return typeof n=="string"?n.slice(0,200):JSON.stringify(t).slice(0,200)}let _=[],u=null,b=null,f={enabled:!0,tools:["Bash","Write","Edit"],batch_interval_seconds:30,categories:["exec_command","file_write","file_delete","deploy","config_change"]},S=C;function I(){return f}function F(i){f.enabled&&(_.length>=D&&_.shift(),_.push(i))}async function T(){if(_.length===0||!b)return;const i=_.splice(0);v(`Flushing ${i.length} hook events`);const t=await b(i);if(t){const e=JSON.stringify(f)!==JSON.stringify(t);f=t,e&&(o("Bridge config updated from gateway",{enabled:t.enabled,tools:t.tools}),t.batch_interval_seconds*1e3!==S&&(S=t.batch_interval_seconds*1e3,u&&(clearInterval(u),u=setInterval(()=>{T().catch(()=>{})},S),o("Batch interval updated",{seconds:t.batch_interval_seconds}))))}o(`Flushed ${i.length} hook events to gateway`)}let h=null,P=null;function K(i,t){if(i.method!=="POST"||!i.url?.startsWith("/hook")){t.writeHead(404),t.end();return}const e=[];i.on("data",s=>e.push(s)),i.on("end",()=>{try{const s=JSON.parse(Buffer.concat(e).toString()),n=s.tool_name??"";if(!f.tools.includes(n)&&!H.has(n)){t.writeHead(200,{"Content-Type":"application/json"}),t.end('{"status":"skipped"}');return}if(B.has(n)&&!f.tools.includes(n)){t.writeHead(200,{"Content-Type":"application/json"}),t.end('{"status":"skipped"}');return}const a=s.tool_input??{},{category:c,risk:r}=N(n,a),l=A(n,a);F({action:`${n}: ${l}`.slice(0,500),category:c,risk_level:r,details:JSON.stringify({tool:n,...a}).slice(0,500)}),v(`Hook received: ${n}`,{category:c,risk:r}),t.writeHead(200,{"Content-Type":"application/json"}),t.end('{"status":"queued"}')}catch{t.writeHead(400),t.end('{"error":"invalid JSON"}')}})}let k=null,y=0;async function J(){try{const i=await j(d).catch(()=>null);if(!i||i.size<=y)return;const t=await p(d,"utf-8"),e=t.split(`
2
+ `).filter(Boolean),s=t.slice(y);y=i.size;const n=s.split(`
3
+ `).filter(Boolean);for(const a of n)try{const c=JSON.parse(a),r=c.tool_name??"";if(B.has(r)||!H.has(r)&&!f.tools.includes(r))continue;const l=c.tool_input??{},{category:g,risk:L}=N(r,l),U=A(r,l);F({action:`${r}: ${U}`.slice(0,500),category:g,risk_level:L,details:JSON.stringify({tool:r,...l}).slice(0,500)}),v(`File hook event: ${r}`,{category:g})}catch{}i.size>1048576&&(await w(d,"","utf-8"),y=0)}catch{}}async function M(i,t=z){b=i;const e=await new Promise((s,n)=>{h=$(K),h.on("error",a=>{a.code==="EADDRINUSE"?(o(`Port ${t} in use, trying ${t+1}`),h.close(),M(i,t+1).then(s).catch(n)):(m("HTTP hook server failed, using file-based hooks only",{error:a.message}),s(0))}),h.listen(t,"127.0.0.1",()=>{P=t,o(`Hook server listening on http://127.0.0.1:${t}/hook`),s(t)})});try{await W(d,""),k=R(d,()=>{J().catch(()=>{})}),o("File watcher started",{path:d})}catch(s){m("File watcher failed",{error:s instanceof Error?s.message:String(s)})}return u=setInterval(()=>{J().catch(()=>{}),T().catch(s=>{m("Batch flush failed",{error:s instanceof Error?s.message:String(s)})})},C),e}function ee(){u&&(clearInterval(u),u=null),T().catch(()=>{}),k&&(k.close(),k=null),h&&(h.close(),h=null),P=null}const te="/* aerostack-guardian-hook */",d="/tmp/aerostack-guardian-events.jsonl";async function ie(i){const t=E(O(),".claude","settings.json");try{let e={};try{const r=await p(t,"utf-8");e=JSON.parse(r)}catch{}const s=e.hooks??{},a=(s.PreToolUse??[]).filter(r=>!(r.hooks??[]).some(g=>g.url?.includes("127.0.0.1")&&g.url?.includes("/hook")||g.command?.includes("aerostack-guardian"))),c={matcher:"Bash|Write|Edit",hooks:[{type:"command",command:`cat >> ${d}`}]};return a.push(c),s.PreToolUse=a,e.hooks=s,await w(t,JSON.stringify(e,null,2)+`
4
+ `,"utf-8"),o("Installed Claude Code hook (file-based)",{eventsFile:d,path:t}),!0}catch(e){return m("Failed to install Claude Code hook",{error:e instanceof Error?e.message:String(e)}),!1}}async function se(){const i=E(O(),".claude","settings.json");try{const t=await p(i,"utf-8"),e=JSON.parse(t),s=e.hooks??{},n=s.PreToolUse??[],a=n.filter(c=>!(c.hooks??[]).some(l=>l.url?.includes("127.0.0.1")&&l.url?.includes("/hook")));return a.length===n.length?!1:(s.PreToolUse=a,e.hooks=s,await w(i,JSON.stringify(e,null,2)+`
5
+ `,"utf-8"),o("Uninstalled Claude Code hook"),!0)}catch{return!1}}export{d as HOOK_EVENTS_FILE,F as addToBatch,N as detectCategory,I as getBridgeConfig,ie as installClaudeHook,M as startHookServer,ee as stopHookServer,A as summarizeToolInput,se as uninstallClaudeHook};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerostack/gateway",
3
- "version": "0.15.12",
3
+ "version": "0.15.13",
4
4
  "description": "stdio-to-HTTP bridge connecting any MCP client to Aerostack Workspaces",
5
5
  "author": "Aerostack",
6
6
  "license": "MIT",