@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.
- package/dist/hook-server.js +5 -5
- package/package.json +1 -1
package/dist/hook-server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{createServer as $}from"node:http";import{readFile as
|
|
2
|
-
`).filter(Boolean),
|
|
3
|
-
`).filter(Boolean);for(const
|
|
4
|
-
`,"utf-8"),
|
|
5
|
-
`,"utf-8"),
|
|
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};
|