@ev-ai/agent-hook 1.1.7 → 1.2.0
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/COLLECTED-DATA.md +1 -1
- package/README.md +18 -3
- package/dist/cli.mjs +38 -36
- package/dist/hook.mjs +32 -30
- package/dist/launcher-update.mjs +5 -0
- package/dist/launcher.mjs +5 -0
- package/dist/managed-hooks-snippet.cjs +177 -0
- package/dist/managed-hooks-snippet.d.ts +3 -0
- package/dist/managed-hooks-snippet.mjs +149 -0
- package/dist/plugin-hooks.mjs +36 -25
- package/package.json +15 -2
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import{createHash as Dt}from"node:crypto";import{join as B}from"node:path";var At=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/,vt=/^>=(\d+)(?:\.(\d+)(?:\.(\d+))?)?$/,Ot=/^v?(\d+)\.(\d+)\.(\d+)/;function Ne(e){let t=At.exec(e);if(t)return{...me(t),prerelease:t[4]?.split(".")}}function Et(e,t){let n=Ne(e),r=Ne(t);if(!(!n||!r))return n.major!==r.major?n.major-r.major:n.minor!==r.minor?n.minor-r.minor:n.patch!==r.patch?n.patch-r.patch:Mt(n.prerelease,r.prerelease)}function G(e,t){let n=Et(e,t);return n!==void 0&&n>=0}function pe(e){let t=vt.exec(e.trim());return t?me(t):void 0}function me(e){return{major:Number(e[1]),minor:Number(e[2]??0),patch:Number(e[3]??0)}}function Fe(e,t){let n=pe(t),r=Ot.exec(e.trim()),o=r?me(r):void 0;return!n||!o?!1:o.major!==n.major?o.major>n.major:o.minor!==n.minor?o.minor>n.minor:o.patch>=n.patch}function Mt(e,t){if(e===void 0&&t===void 0)return 0;if(e===void 0)return 1;if(t===void 0)return-1;let n=Math.max(e.length,t.length);for(let r=0;r<n;r++){let o=e[r],c=t[r];if(o===void 0)return-1;if(c===void 0)return 1;let s=Pt(o,c);if(s!==0)return s}return 0}function Pt(e,t){let n=/^\d+$/.test(e),r=/^\d+$/.test(t);if(n&&r){let o=Number(e)-Number(t);return o<0?-1:o>0?1:0}return n?-1:r?1:e<t?-1:e>t?1:0}var Ce="EV_AI_LAUNCHER_REFRESH_SCOPE",Le="EV_AI_HOOK_UPDATE_TTL_MIN",kr=Buffer.from([1]);var xr=1024*1024,Sr=4*1024*1024,wr=64*1024,Rr=64*1024,Ar=64*1024;var P=21600,ge=604800,Ue=3e5,he=4096,X=4*1024*1024;import{open as Ie,mkdir as Nt,readFile as Ft,readdir as Ct,rename as Lt,stat as Ut,unlink as It,utimes as Tt}from"node:fs/promises";var W=new WeakMap;function _e(e){if(e&&typeof e=="object"&&"code"in e)return e}function k(e){return _e(e)?.code==="ENOENT"}function ye(e){return _e(e)?.code==="EEXIST"}function De(e){let t=_e(e)?.code;return t==="EPERM"||t==="EBUSY"||t==="EACCES"}async function U(e,t){try{return await e.readdir(t)}catch(n){if(k(n))return[];throw n}}async function be(e,t){try{await e.unlink(t)}catch(n){if(!k(n))throw n}}async function N(e,t,n){let r=await e.open(t,"wx");try{await e.write(r,n),await e.fsync(r)}finally{await e.close(r)}}function A(){return{async open(e,t){let n=await Ie(e,t),r={path:e};return W.set(r,n),r},async write(e,t){let n=Te(e),r=typeof t=="string"?Buffer.from(t,"utf8"):t;await n.write(r)},async fsync(e){await Te(e).sync()},async close(e){let t=W.get(e);W.delete(e),t&&await t.close()},rename:Lt,async readdir(e){return Ct(e)},readFile:Ft,async stat(e){let t=await Ut(e);return{mtimeMs:t.mtimeMs,size:t.size,isDirectory:()=>t.isDirectory()}},async mkdir(e,t){await Nt(e,t)},unlink:It,utimes:Tt,async fsyncDir(e){if(process.platform==="win32")return;let t=await Ie(e,"r");try{await t.sync()}finally{await t.close()}}}}function Te(e){let t=W.get(e);if(!t)throw new Error("closed");return t}function g(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}import{join as I}from"node:path";function ke(e){return I(e,".ev-ai","agent-hook","js")}function xe(e){return I(ke(e),"scopes")}function x(e,t){return I(xe(e),t)}function v(e){return I(e,"attempts")}function q(e){return I(e,"scope.json")}function T(e){return String(e).padStart(10,"0")}var D="@ev-ai/agent-hook";function S(e,t){return B(ke(e),t?"dev-artifacts":"artifacts")}function Se(e,t){return B(e,t)}function w(e,t){return B(e,t,"hook.mjs")}function Q(e,t){return B(e,t,"meta.json")}function Ht(e,t){return B(e,t,"health.json")}function F(e){return Dt("sha256").update(e).digest("hex")}async function j(e,t,n){try{let r=await e.stat(t);return r.size<=0||r.size>X?"bad":F(await e.readFile(t))===n?"ok":"bad"}catch(r){if(k(r))return"missing";throw r}}async function C(e,t,n,r,o,c=process.version){let[s,a,i]=await Promise.all([j(e,w(t,n),n),Y(e,Q(t,n)),Bt(e,Ht(t,n))]);if(s==="missing")return{usable:!1,reason:"artifact_missing"};if(s==="bad"||!a)return{usable:!1,reason:"hash_mismatch"};if(!G(a.version,r))return{usable:!1,reason:"below_floor"};if(!Fe(c,a.node_engine))return{usable:!1,reason:"incompatible_node"};if(a.min_launcher_protocol>1)return{usable:!1,reason:"incompatible_protocol"};if(i?.quarantined_until){let u=Date.parse(i.quarantined_until);if(Number.isFinite(u)&&u>o)return{usable:!1,reason:"quarantined"}}return{usable:!0,meta:a,healthFails:i?.consecutive_startup_failures??0}}async function Y(e,t){try{let n=await e.readFile(t);return He(JSON.parse(n.toString("utf8")))}catch{return}}function He(e){if(!g(e))return;let t=e;if(t.package===D&&!(typeof t.version!="string"||t.version.length===0)&&typeof t.node_engine=="string"&&!(typeof t.min_launcher_protocol!="number"||!Number.isInteger(t.min_launcher_protocol))&&!(typeof t.integrity!="string"||!t.integrity.startsWith("sha512-"))&&typeof t.installed_at=="string")return{package:D,version:t.version,node_engine:t.node_engine,min_launcher_protocol:t.min_launcher_protocol,integrity:t.integrity,installed_at:t.installed_at}}async function Bt(e,t){try{let n=await e.readFile(t),r=JSON.parse(n.toString("utf8"));if(!g(r))return;let o=r.consecutive_startup_failures;if(typeof o!="number"||!Number.isInteger(o)||o<0)return;let c={consecutive_startup_failures:o};return typeof r.quarantined_until=="string"&&(c.quarantined_until=r.quarantined_until),c}catch{return}}import{join as Be}from"node:path";var jt=/^(\d{10})$/,$t=/^(\d{10})\.done$/,Vt=/^[0-9a-f]{64}$/i;function O(e){let t=e[Le];if(t===void 0||t==="")return P;let n=Number(t);return!Number.isInteger(n)||n<=0?P:Math.min(Math.max(P,n*60),ge)}async function y(e,t,n=!1){let r=v(t),o=await U(e,r),c=new Map,s=new Map,a=je(o,jt),i=je(o,$t),u=async f=>{let p=await Ve(e,Be(r,Z(f)));return p&&c.set(f,{record:Kt(p.value),mtimeMs:p.mtimeMs}),p!==void 0},l=async f=>{let p=zt((await Ve(e,Be(r,ee(f))))?.value);return p&&s.set(f,p),p!==void 0};if(!n)return await Promise.all([...a.map(u),...i.map(l)]),{claims:c,dones:s};await Promise.all([$e(a,u),$e(i,l)]);let d=R(c);return d<R(s)&&i.includes(d)&&await l(d),{claims:c,dones:s}}function je(e,t){return e.flatMap(n=>{let r=t.exec(n);return r?[Number(r[1])]:[]})}async function $e(e,t){for(let n of[...e].sort((r,o)=>o-r))if(await t(n))return}function R(e){let t=0;for(let n of e.keys())n>t&&(t=n);return t}function E(e,t,n){let r=R(e.claims),o=R(e.dones),c=r===0?{kind:"uninitialized"}:{kind:"bundled",why:"bootstrap_failed"},s;if(o>0){let p=e.dones.get(o);p&&(c=p.selection,s=p.outcome)}let a=r>0?e.claims.get(r):void 0,i=a?Jt(a):void 0,u=r>0?e.dones.get(r):void 0,l=$(u?.interval_s,n),d=i!==void 0?i+l*1e3:void 0,f=i!==void 0&&i-t>Ue;return{latest:r,startMs:i,intervalS:l,deadlineMs:d,selection:c,lastOutcome:s,futureDated:f,highestDone:o}}function Jt(e){if(e.record!=="empty"&&e.record.started_at){let t=Date.parse(e.record.started_at);if(Number.isFinite(t))return t}return e.mtimeMs}function Z(e){return T(e)}function ee(e){return`${T(e)}.done`}function $(e,t){return typeof e!="number"||!Number.isFinite(e)||e<=0?Math.max(P,t):Math.min(Math.max(Math.floor(e),P,t),ge)}async function Ve(e,t){let n;try{n=await e.stat(t)}catch(o){if(k(o))return;throw o}let r=n.mtimeMs;if(n.size===0||n.size>he)return{mtimeMs:r};try{let o=await e.readFile(t);return o.byteLength===0||o.byteLength>he?{mtimeMs:r}:{mtimeMs:r,value:JSON.parse(o.toString("utf8"))}}catch{return{mtimeMs:r}}}function Kt(e){if(!g(e))return"empty";let t={};return typeof e.started_at=="string"&&(t.started_at=e.started_at),(e.owner==="bootstrap"||e.owner==="refresh")&&(t.owner=e.owner),e.resync===!0&&(t.resync=!0),t}function zt(e){if(!g(e))return;let t=e;if(typeof t.finished_at!="string"||typeof t.outcome!="string"||typeof t.interval_s!="number"||!Number.isFinite(t.interval_s))return;let n=Gt(t.selection);if(n)return{finished_at:t.finished_at,interval_s:t.interval_s,outcome:t.outcome,selection:n}}function Gt(e){if(!g(e))return;let t=e;if(t.kind==="bundled")return t.why==="server"||t.why==="bootstrap_failed"?{kind:"bundled",why:t.why}:void 0;if(t.kind==="cached"&&typeof t.digest=="string"&&Vt.test(t.digest)&&typeof t.version=="string"&&t.version.length>0&&typeof t.integrity=="string"&&t.integrity.startsWith("sha512-"))return{kind:"cached",digest:t.digest.toLowerCase(),version:t.version,integrity:t.integrity}}import{randomBytes as qt}from"node:crypto";import{join as V}from"node:path";var Je=/^https:\/\/registry\.npmjs\.org\/@ev-ai\/agent-hook\/-\/agent-hook-(\d+\.\d+\.\d+)\.tgz$/;async function te(e,t,n){let r=v(t);await e.mkdir(r,{recursive:!0});let o=E(await y(e,t,!0),n.nowMs,n.ttlFloorS);return o.futureDated?Ke(e,t,{...n,resync:!0,n:o.latest+1}):o.deadlineMs!==void 0&&n.nowMs<o.deadlineMs?{kind:"too_soon",deadlineMs:o.deadlineMs,latest:o.latest}:Ke(e,t,{...n,n:o.latest+1})}async function ne(e,t,n){if(n.nowMs-n.startedAtMs>n.budgetMs+3e4)return{recorded:!1,why:"expired"};let r=await y(e,t);if(R(r.claims)>n.n)return{recorded:!1,why:"superseded"};if(r.dones.has(n.n))return{recorded:!1,why:"already_done"};let o=v(t),c=V(o,ee(n.n)),s=ze(),a=V(o,`.${T(n.n)}.done.${s}`),i={finished_at:new Date(n.nowMs).toISOString(),interval_s:n.intervalS,outcome:n.outcome,selection:n.selection},u=Buffer.from(JSON.stringify(i),"utf8");try{await N(e,a,u),await e.rename(a,c),await e.fsyncDir(o)}catch(l){throw await e.unlink(a).catch(()=>{}),l}return await Qt(e,t,n.n),{recorded:!0}}async function Qt(e,t,n){let r=await y(e,t),o=n-8,c=R(r.dones),s=v(t),a=new Set([...r.claims.keys(),...r.dones.keys()]);await Promise.all([...a].map(async i=>{i>=o||i!==c&&(await be(e,V(s,Z(i))),await be(e,V(s,ee(i))))}))}async function Ke(e,t,n){if(n.n<1||n.n>9999999999)return{kind:"lost"};let r=v(t),o=V(r,Z(n.n)),c=new Date(n.nowMs).toISOString(),s=ze(),a={started_at:c,nonce:s,owner:n.owner};n.resync&&(a.resync=!0);try{await N(e,o,JSON.stringify(a)),await e.fsyncDir(r)}catch(i){if(ye(i))return{kind:"lost"};throw i}return n.collectorRedacted!==void 0&&await Yt(e,t,n.collectorRedacted,n.dev===!0),R((await y(e,t)).claims)>n.n?{kind:"lost"}:n.resync?{kind:"resynced",n:n.n,startedAt:c}:{kind:"claimed",n:n.n,startedAt:c,startedAtMs:n.nowMs,nonce:s,owner:n.owner}}async function Yt(e,t,n,r){let o=q(t);try{await N(e,o,Buffer.from(JSON.stringify({collector:n,dev:r}),"utf8")),await e.fsyncDir(t)}catch(c){if(ye(c))return;throw c}}function ze(){return qt(8).toString("hex")}import bn from"node:http";import kn from"node:https";import{URL as xn}from"node:url";import{createHash as Zt}from"node:crypto";import{access as en,readFile as tn,stat as nn}from"node:fs/promises";import{homedir as rn}from"node:os";import{dirname as on,join as we,parse as sn,resolve as Ge}from"node:path";var an="https://hooks.ev-ai.ai",cn=".claude/ev-ai-runtime-report.json",un="config.json",dn=1024*1024,Ye=new Set(["localhost","127.0.0.1","[::1]","::1"]),ln=["claude","cursor","codex"],fn=[cn,".cursor/ev-ai-runtime-report.json",".codex/ev-ai-runtime-report.json"],Xe=/^[A-Za-z0-9._~-]+$/;function pn(e){return e!==void 0&&ln.includes(e)}function re(e,t){let n=e[t+1];return n&&!n.startsWith("--")?{value:n,next:t+1}:{next:t}}function mn(e){let t,n,r,o,c;for(let s=0;s<e.length;s++){let a=e[s];if(a!==void 0){if(a==="--runner"){let i=re(e,s);t=i.value,s=i.next;continue}if(a.startsWith("--runner=")){t=a.slice(9);continue}if(a==="--url"){let i=re(e,s);i.value&&(r=i.value),s=i.next;continue}if(a.startsWith("--url=")){r=a.slice(6);continue}if(a==="--token"){let i=re(e,s);i.value&&(o=i.value),s=i.next;continue}if(a.startsWith("--token=")){o=a.slice(8);continue}if(a==="--base-url"){let i=re(e,s);i.value&&(c=i.value),s=i.next;continue}if(a.startsWith("--base-url=")){c=a.slice(11);continue}!a.startsWith("-")&&n===void 0&&(n=a)}}return{runner:pn(t)?t:void 0,event:n,collectorUrl:r,orgToken:o,baseUrl:c}}function Ze(e,t=an){let n=t.replace(/\/+$/,""),r=e.trim();return`${n}/${r}/hook`}function Re(e=rn()){return we(e,".ev-ai",un)}function gn(e,t){return{...e,...t}}function We(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<=32||n===127||n===39)return!0}return!1}function et(e){try{let t=new URL(e);return t.protocol==="https:"?!0:t.protocol==="http:"?Ye.has(t.hostname):!1}catch{return!1}}function tt(e){try{let n=new URL(e).pathname.split("/").filter(r=>r.length>0);if(n.length>=2&&n[n.length-1]==="hook"){let r=n[n.length-2];return r&&r.length>0?r:void 0}return}catch{return}}function Ae(e){let t;try{t=new URL(e)}catch{return`invalid URL (got: ${e})`}if(!et(e))return`must be https (or http on localhost / 127.0.0.1 / ::1) (got: ${e})`;let n=tt(e);if(!n)return`must end with /{orgToken}/hook (got: ${e})`;if(!Xe.test(n))return`org token must match ${Xe.source} (got: ${n})`;if(We(e))return`must not contain whitespace, control characters, or single quotes (got: ${e})`;if(We(t.pathname))return`pathname must not contain whitespace, control characters, or single quotes (got: ${e})`}function hn(e){return new URL(e).toString()}function qe(e){if(e.collector_url)return e.collector_url;let t=e.repo_ingest_token,n=typeof t=="string"?t.trim():void 0;return n?Ze(n):""}function oe(e){try{return Ye.has(new URL(e).hostname)}catch{return!1}}function nt(e){try{let t=new URL(e),n=t.pathname.split("/").filter(r=>r.length>0);return n.length>=2&&n[n.length-1]==="hook"&&(n[n.length-2]="***",t.pathname=`/${n.join("/")}`),t.toString()}catch{return"<invalid-url>"}}function _n(e){let t=e.collectorUrl?.trim(),n;if(t)n=t;else{let o=e.orgToken?.trim();o&&(n=Ze(o,e.baseUrl?.trim()??void 0))}if(!n)return{};let r=Ae(n);return r?{problem:r}:{url:hn(n)}}var ve={access:en,stat:nn,readFile:(e,t)=>tn(e,t)};async function yn(e,t,n=ve){let r=Ge(e),{root:o}=sn(r);for(;;){let s=we(r,".git");try{let i=await n.stat(s);if(i.isDirectory()||i.isFile())return r}catch{}if(r===o)break;let a=on(r);if(a===r)break;r=a}let c=t.CURSOR_PROJECT_DIR??t.CLAUDE_PROJECT_DIR;if(c)try{if((await n.stat(c)).isDirectory())return c}catch{}return Ge(e)}async function J(e,t=ve){try{let n=await t.stat(e);if(!n.isFile()||n.size>dn)return;let r=await t.readFile(e,"utf8"),o=JSON.parse(r);return o===null||typeof o!="object"||Array.isArray(o)?void 0:o}catch{return}}async function Qe(e,t){return(await Promise.all(fn.map(async r=>{let o=we(e,r);try{return await t.access(o),o}catch{return}}))).find(r=>r!==void 0)}async function rt(e){let t=e.fs??ve,n=_n(mn(e.argv));if(n.url)return{url:n.url,source:"argv"};let r=e.env.EV_AI_HOOK_MANIFEST;if(r)try{await t.access(r);let d=await J(r,t),f=d?qe(d):"";return f?{url:f,source:"manifest_override"}:{source:"none"}}catch{}let o=await yn(e.cwd,e.env,t),c=Re(e.home),[s,a]=await Promise.all([J(c,t),Qe(o,t).then(async d=>d??Qe(e.cwd,t))]),i=a?await J(a,t):void 0,u;s&&i?u=gn(i,s):s?u=s:i&&(u=i);let l=u?qe(u):"";return l?{url:l,source:"manifest"}:{source:"none"}}function ot(e){if(Ae(e))return;let t;try{t=new URL(e)}catch{return}let n=tt(e);if(!n)return;let o=t.pathname.split("/").filter(a=>a.length>0).slice(0,-2),c=o.length>0?`/${o.join("/")}`:"",s=`${t.origin}${c}/${n}`;return Zt("sha256").update(s).digest("hex").slice(0,32)}function it(e){if(Ae(e))return;let t;try{t=new URL(e)}catch{return}let n=t.pathname.split("/").filter(o=>o.length>0);if(n.length<2||n[n.length-1]!=="hook")return;n[n.length-1]="version";let r=new URL(t.origin);if(r.pathname=`/${n.join("/")}`,r.search="",r.hash="",r.username="",r.password="",!(r.username||r.password)&&r.origin===t.origin&&et(r.toString()))return r.toString()}function ie(){return{getBounded:Sn}}function se(e,t){return e==="timeout"||e==="network"?"failed:timeout":e==="http_3xx"?"failed:http_3xx":t}function Sn(e,t){let n;try{n=new xn(e)}catch{return Promise.resolve({ok:!1,reason:"origin_rejected"})}if(n.protocol==="http:"){if(!oe(e))return Promise.resolve({ok:!1,reason:"origin_rejected"})}else if(n.protocol!=="https:")return Promise.resolve({ok:!1,reason:"origin_rejected"});let r=n.protocol==="http:"?bn:kn;return new Promise(o=>{let c=!1,s=[],a=0,i=d=>{c||(c=!0,t.signal?.removeEventListener("abort",u),o(d))},u=()=>{l.destroy(),i({ok:!1,reason:"timeout"})},l=r.request(n,{method:"GET",agent:!1,timeout:t.timeoutMs},d=>{let f=d.statusCode??0;if(f>=300&&f<400){d.resume(),i({ok:!1,reason:"http_3xx"});return}let p=d.headers["content-length"];if(typeof p=="string"){let m=Number(p);if(Number.isFinite(m)&&m>t.maxBytes){d.destroy(),i({ok:!1,reason:"too_large"});return}}d.on("data",m=>{if(a+=m.length,a>t.maxBytes){d.destroy(),i({ok:!1,reason:"too_large"});return}s.push(m)}),d.on("end",()=>{i({ok:!0,response:{status:f,headers:d.headers,body:Buffer.concat(s)}})}),d.on("error",()=>{i({ok:!1,reason:"network"})})});if(l.on("timeout",()=>{l.destroy(),i({ok:!1,reason:"timeout"})}),l.on("error",()=>{i({ok:!1,reason:"network"})}),t.signal){if(t.signal.aborted){u();return}t.signal.addEventListener("abort",u,{once:!0})}l.end()})}async function M(e,t){return e.EV_AI_AUTO_UPDATE==="0"?!0:(await J(Re(t)))?.auto_update===!1}function K(e){return!!e.CURSOR_SANDBOX}function ae(e,t,n,r){return{source:"bundled",hookPath:e.bundledHookPath,fallbackReason:t,scopeId:n?.scopeId,dev:n?.dev,...r}}import{randomBytes as An}from"node:crypto";import{basename as vn,join as Oe}from"node:path";var at=/^[0-9a-f]{64}$/,On=/^\.(?:hook\.mjs|meta\.json|health\.json)\./;async function ct(e,t,n,r,o,c){if(!at.test(n)||F(r)!==n)return{ok:!1,reason:"repair_failed"};let s=Se(t,n);await e.mkdir(s,{recursive:!0}),await Mn(e,s,c);let a=w(t,n),i=Q(t,n),u=await Y(e,i);if(await j(e,a,n)==="ok"&&u){if(u.version!==o.version)return{ok:!1,reason:"metadata_conflict"};if(En(u,o))return{ok:!0}}let d={...o,installed_at:new Date(c).toISOString()};return await st(e,s,a,r),await st(e,s,i,Buffer.from(JSON.stringify(d),"utf8")),await j(e,a,n)!=="ok"?{ok:!1,reason:"repair_failed"}:{ok:!0}}async function ut(e,t,n,r){let c=(await U(e,t)).filter(a=>at.test(a)).slice(0,512);return(await Promise.all(c.map(async a=>{let i=await Y(e,Q(t,a));if(!(i?.version!==n||i?.integrity!==r))return await j(e,w(t,a),a)==="ok"?a:void 0}))).find(a=>a!==void 0)}function En(e,t){return e.package===t.package&&e.version===t.version&&e.node_engine===t.node_engine&&e.min_launcher_protocol===t.min_launcher_protocol&&e.integrity===t.integrity}async function st(e,t,n,r){let o=An(8).toString("hex"),c=`.${vn(n)}.`,s=Oe(t,`${c}${o}`),a=()=>e.unlink(s).catch(()=>{});await N(e,s,r);try{await e.rename(s,n)}catch(i){if(!De(i))throw await a(),i;let u=Oe(t,`${c}bad.${o}`);try{await e.rename(n,u)}catch(l){if(!k(l))throw await a(),l}await e.rename(s,n)}await e.fsyncDir(t)}async function Mn(e,t,n){let r=await U(e,t);await Promise.all(r.map(async o=>{if(!On.test(o))return;let c=Oe(t,o);try{let s=await e.stat(c);n-s.mtimeMs>36e5&&await e.unlink(c)}catch(s){if(!k(s))throw s}}))}import{createHash as Bn}from"node:crypto";import{gunzip as jn}from"node:zlib";import{promisify as $n}from"node:util";var Nn=/^\d+\.\d+\.\d+$/,Fn=/^https?:\/\/(?:127\.0\.0\.1|localhost|\[::1\]):\d+\/@ev-ai\/agent-hook\/-\/agent-hook-(\d+\.\d+\.\d+)\.tgz$/;function ce(e,t){return{launcher:e,protocol:String(1),current:t,platform:`${process.platform}-${process.arch}`,node:process.version}}function Ee(e){if(!e.startsWith("sha512-"))return!1;let t=e.slice(7);if(t.length===0||!/^[A-Za-z0-9+/]+=*$/.test(t))return!1;let n=Buffer.from(t,"base64");return n.length!==64?!1:n.toString("base64")===t}function Cn(e,t){if(!g(e))return{ok:!1,reason:"failed:metadata_mismatch"};let n=e.hook_js;if(n===void 0)return{ok:!0,directive:{kind:"none"}};if(!g(n))return{ok:!1,reason:"failed:metadata_mismatch"};if(n.use_bundled===!0)return{ok:!0,directive:{kind:"bundled",intervalS:dt(n.check_interval_s)}};let r=n.version,o=n.url,c=n.format,s=n.integrity;if(typeof r!="string"||!Nn.test(r))return{ok:!1,reason:"failed:metadata_mismatch"};if(c!=="npm-tgz")return{ok:!1,reason:"failed:origin_rejected"};if(typeof o!="string")return{ok:!1,reason:"failed:origin_rejected"};let a=Ln(o,t);return a?a!==r?{ok:!1,reason:"failed:metadata_mismatch"}:typeof s!="string"||!Ee(s)?{ok:!1,reason:"failed:metadata_mismatch"}:{ok:!0,directive:{kind:"target",version:r,url:o,integrity:s,intervalS:dt(n.check_interval_s)}}:{ok:!1,reason:"failed:origin_rejected"}}async function lt(e,t,n,r,o,c){let s=Un(e,t),a=await r.getBounded(s,{maxBytes:4096,timeoutMs:n,signal:c});if(!a.ok)return{ok:!1,reason:se(a.reason,"failed:metadata_mismatch")};let{status:i,body:u}=a.response;if(i!==200)return{ok:!1,reason:`failed:http_${i}`};let l;try{l=JSON.parse(u.toString("utf8"))}catch{return{ok:!1,reason:"failed:metadata_mismatch"}}return Cn(l,o)}function Ln(e,t){let n=Je.exec(e);if(n?.[1])return n[1];if(t){let r=Fn.exec(e);if(r?.[1])return r[1]}}function dt(e){if(typeof e=="number"&&Number.isInteger(e)&&e>0)return e}function Un(e,t){let n=new URL(e);for(let[r,o]of Object.entries(t))n.searchParams.set(r,o);return n.toString()}var Vn=$n(jn),L=512,Jn="package/package.json",Kn="package/dist/hook.mjs";function zn(e,t){if(!Ee(t))return!1;let n=Buffer.from(t.slice(7),"base64"),r=Bn("sha512").update(e).digest();return r.length===n.length&&r.equals(n)}async function Gn(e){return Vn(e,{maxOutputLength:16777216})}async function ft(e,t,n=Gn){if(!zn(e,t))return{ok:!1,reason:"failed:integrity_mismatch"};let r;try{r=await n(e)}catch{return{ok:!1,reason:"failed:extract_failed"}}return Xn(r)}function Xn(e){try{return Wn(e)}catch{return{ok:!1,reason:"failed:extract_failed"}}}function pt(e,t){if(!g(e))return;let n=e;if(n.name!==D||n.version!==t||typeof n.version!="string")return;let r=n.engines,o=g(r)?r.node:void 0;if(typeof o!="string"||!pe(o))return;let c=n.evAi;if(!g(c))return;let s=c.minLauncherProtocol;if(!(typeof s!="number"||!Number.isInteger(s)||s>1))return{package:D,version:n.version,node_engine:o,min_launcher_protocol:s,integrity:""}}function Wn(e){let t=0,n=0,r,o,c,s,a=0;for(;t+L<=e.length;){let i=e.subarray(t,t+L);if(t+=L,qn(i)){if(a+=1,a>=2)break;continue}if(a=0,!Qn(i)||!Yn(i))return{ok:!1,reason:"failed:extract_failed"};if(n+=1,n>1e3)return{ok:!1,reason:"failed:extract_failed"};let u=String.fromCharCode(i[156]??0),l=mt(i.subarray(124,136));if(l===void 0||l>8388608)return{ok:!1,reason:"failed:extract_failed"};let d=Zn(i),f=s??l,p=c??d;c=void 0,s=void 0;let m=t+f;if(m>e.length)return{ok:!1,reason:"failed:extract_failed"};let h=e.subarray(t,m);if(t+=er(f),u!=="5"){if(u==="x"){let b=nr(h);if(!b)return{ok:!1,reason:"failed:extract_failed"};c=b.path,s=b.size;continue}if(u!=="0"&&u!=="\0")return{ok:!1,reason:"failed:extract_failed"};if(!tr(p))return{ok:!1,reason:"failed:extract_failed"};if(p===Jn){if(r||f>65536)return{ok:!1,reason:"failed:extract_failed"};r=Buffer.from(h);continue}if(p===Kn){if(o||f>X)return{ok:!1,reason:"failed:extract_failed"};o=Buffer.from(h)}}}return!r||!o?{ok:!1,reason:"failed:extract_failed"}:{ok:!0,packageJson:r,hookMjs:o}}function qn(e){for(let t of e)if(t!==0)return!1;return!0}function Qn(e){let t=mt(e.subarray(148,156));if(t===void 0)return!1;let n=0;for(let r=0;r<L;r++)n+=r>=148&&r<156?32:e[r]??0;return n===t}function Yn(e){return e.subarray(257,262).toString("latin1")==="ustar"}function Zn(e){let t=Me(e.subarray(0,100)),n=Me(e.subarray(345,500));return n?`${n}/${t}`:t}function Me(e){let t=e.indexOf(0);return e.subarray(0,t===-1?e.length:t).toString("utf8")}function mt(e){if((e[0]??0)&128)return;let t=Me(e).trim();if(t.length===0)return 0;if(/^[0-7]+$/.test(t))return Number.parseInt(t,8)}function er(e){return Math.ceil(e/L)*L}function tr(e){return!e||e.startsWith("/")||e.includes("\\")||e.includes("\0")||e.split("/").some(n=>n==="..")?!1:e==="package"||e.startsWith("package/")}function nr(e){let t=e.toString("utf8"),n=0,r={};for(;n<t.length;){let o=t.indexOf(" ",n);if(o<0)return;let c=Number(t.slice(n,o));if(!Number.isInteger(c)||c<=0)return;let s=t.slice(n,n+c);if(!s.endsWith(`
|
|
2
|
+
`))return;let a=s.slice(o-n+1,s.length-1),i=a.indexOf("=");if(i<0)return;let u=a.slice(0,i),l=a.slice(i+1);if(u==="path"&&(r.path=l),u==="size"){let d=Number(l);if(!Number.isInteger(d)||d<0)return;r.size=d}n+=c}return r}async function ue(e,t,n,r,o,c){let s=it(e);return s?lt(s,t,n,r,o,c):{ok:!1,reason:"failed:origin_rejected"}}async function de(e,t,n,r,o,c,s,a){if(!G(r.version,o))return{ok:!1,reason:"skipped:below_floor"};let i=await ut(e,n,r.version,r.integrity);if(i){let u=await C(e,n,i,o,c);if(u.usable)return{ok:!0,digest:i,reused:!0};if(u.reason==="quarantined")return{ok:!1,reason:"skipped:quarantined"}}return or(e,t,n,r,c,s,a)}async function or(e,t,n,r,o,c,s){let a=await t.getBounded(r.url,{maxBytes:4194304,timeoutMs:c,signal:s});if(!a.ok)return{ok:!1,reason:se(a.reason,"failed:extract_failed")};if(a.response.status!==200)return{ok:!1,reason:`failed:http_${a.response.status}`};let i=await ft(a.response.body,r.integrity);if(!i.ok)return i;let u;try{u=JSON.parse(i.packageJson.toString("utf8"))}catch{return{ok:!1,reason:"failed:metadata_mismatch"}}let l=pt(u,r.version);if(!l)return{ok:!1,reason:"failed:metadata_mismatch"};let d=F(i.hookMjs),f=await ct(e,n,d,i.hookMjs,{...l,integrity:r.integrity},o);return f.ok?{ok:!0,digest:d,reused:!1}:{ok:!1,reason:`failed:${f.reason}`}}var ar={kind:"bundled",why:"bootstrap_failed"};async function cr(e){let t=e.fs??A(),n=e.http??ie(),r=x(e.home,e.scope.scopeId),o=S(e.home,e.scope.dev),c=O(e.env),s=AbortSignal.timeout(3e3),a=await te(t,r,{owner:"bootstrap",nowMs:e.nowMs,ttlFloorS:c,collectorRedacted:e.scope.collectorUrlRedacted,dev:e.scope.dev});if(a.kind!=="claimed"){let m=a.kind==="lost"||a.kind==="too_soon";return ae(e,m?"bootstrap_in_progress":"bootstrap_failed",e.scope,{didBootstrap:!1})}let i=(m,h,b)=>ne(t,r,{n:a.n,startedAtMs:a.startedAtMs,nowMs:e.nowMs,budgetMs:3e3,intervalS:$(b,c),outcome:m,selection:h}),u=async m=>(await i(m,ar),ae(e,"bootstrap_failed",e.scope,{didBootstrap:!0}));if(await M(e.env,e.home)||K(e.env)||s.aborted)return u("failed:bootstrap");let l=await ue(e.scope.collectorUrl,ce(e.bundledVersion,e.bundledVersion),1e3,n,e.scope.dev,s);if(!l.ok)return u(l.reason);let d=l.directive;if(d.kind==="none")return u("failed:bootstrap");if(d.kind==="bundled")return await i("bundled",{kind:"bundled",why:"server"},d.intervalS),ae(e,"server",e.scope,{didBootstrap:!0});let f=await de(t,n,o,d,e.bundledVersion,e.nowMs,2e3,s);if(!f.ok)return u(f.reason);let{digest:p}=f;return await i("updated",{kind:"cached",digest:p,version:d.version,integrity:d.integrity},d.intervalS),{source:"bootstrap",hookPath:w(o,p),scopeId:e.scope.scopeId,digest:p,dev:e.scope.dev,didBootstrap:!0}}async function le(e,t){let n=await rt({argv:e,env:t.env,cwd:t.cwd,home:t.home});if(!n.url)return;let r=ot(n.url);if(!(!r||n.source==="none"))return{scopeId:r,collectorUrl:n.url,collectorUrlRedacted:nt(n.url),source:n.source,dev:oe(n.url)}}var lr={kind:"bundled",why:"bootstrap_failed"};async function fr(e,t,n,r,o){try{await pr(e,t,n,r,o)}catch{}return 0}async function pr(e,t,n,r,o){if(K(t)||await M(t,r))return;let c=t[Ce],s=await le(e,{env:t,cwd:n,home:r});if(!s||!c||s.scopeId!==c)return;let a=o?.fs??A(),i=o?.http??ie(),u=o?.nowMs??Date.now(),l=O(t),d=x(r,s.scopeId),f=await te(a,d,{owner:"refresh",nowMs:u,ttlFloorS:l,collectorRedacted:s.collectorUrlRedacted,dev:s.dev});if(f.kind!=="claimed")return;let p=(St,wt,Rt)=>ne(a,d,{n:f.n,startedAtMs:f.startedAtMs,nowMs:u,budgetMs:6e4,intervalS:$(Rt,l),outcome:St,selection:wt}),m=o?.packageVersion??"",h=E(await y(a,d,!0),u,l).selection,b=h.kind==="uninitialized"?lr:h,Pe=AbortSignal.timeout(6e4),fe=await ue(s.collectorUrl,ce(m,h.kind==="cached"?h.version:m),5e3,i,s.dev,Pe);if(!fe.ok){await p(fe.reason,b);return}let _=fe.directive;if(_.kind==="none"){await p("no_directive",b);return}if(_.kind==="bundled"){await p("bundled",{kind:"bundled",why:"server"},_.intervalS);return}let z=await de(a,i,S(r,s.dev),_,m,u,3e4,Pe);if(!z.ok){await p(z.reason,b,_.intervalS);return}let kt=h.kind==="cached"&&h.version===_.version&&h.integrity===_.integrity,{digest:xt}=z;await p(kt?z.reused?"current":"repaired":"updated",{kind:"cached",digest:xt,version:_.version,integrity:_.integrity},_.intervalS)}function mr(e){return`${e.slice(0,4)}\u2026`}async function gr(e,t,n){let r=e.includes("--json"),o=e.includes("--all"),c=e.slice(1).filter(p=>p!=="--json"&&p!=="--all"),s=await le(c,t),a=await M(t.env,t.home),i=A(),u=await bt(t,n,s,i,a),l=await hr(i,t.home,s?.scopeId),d=o?await _r(t,n,i,a,l):[];if(r)return t.stdout.write(`${JSON.stringify({...u,otherScopes:d},null,2)}
|
|
3
|
+
`),0;let f=[`launcher ${n.version} protocol ${n.evAi.launcherProtocol} revision ${n.evAi.launcherRevision} bundled hook ${n.version}`];if(f.push(...yt(u)),o)for(let p of d)f.push(""),f.push(...yt(p));else f.push(`other scopes ${l.length} (status --all)`);return f.push(`auto-update ${a?"off":"on"}`),t.stdout.write(`${f.join(`
|
|
4
|
+
`)}
|
|
5
|
+
`),0}async function bt(e,t,n,r,o){let c=!o;if(o)return{..._t(n,c),selection:"bundled",fallbackReason:"kill_switch"};if(!n)return{selection:"bundled",fallbackReason:"no_collector_url",autoUpdate:c};let s=e.now(),a=await y(r,x(e.home,n.scopeId),!0),i=E(a,s,O(e.env)),u="bundled",l,d;if(i.selection.kind==="cached"){let f=S(e.home,n.dev),p=await C(r,f,i.selection.digest,t.version,s);p.usable?(u=`cached ${i.selection.version}`,d=`usable (protocol ${p.meta.min_launcher_protocol})`):l=p.reason}else i.selection.kind==="bundled"?l=i.selection.why:l="uninitialized";return{..._t(n,c),selection:u,fallbackReason:l,usable:d,lastAttempt:i.startMs!==void 0?new Date(i.startMs).toISOString():void 0,nextNotBefore:i.deadlineMs!==void 0?new Date(i.deadlineMs).toISOString():void 0,intervalS:i.intervalS,lastResult:i.lastOutcome}}function _t(e,t){return{scopeId:e?.scopeId,collectorUrlRedacted:e?.collectorUrlRedacted,urlSource:e?.source,autoUpdate:t}}function yt(e){let t=[];e.scopeId?t.push(`this repo scope ${mr(e.scopeId)} ${e.collectorUrlRedacted} (source: ${e.urlSource})`):t.push("this repo (no collector url)");let n=e.fallbackReason?` (${e.fallbackReason})`:e.usable?` ${e.usable}`:"";return t.push(` selection ${e.selection}${n}`),e.lastAttempt&&t.push(` schedule last attempt ${e.lastAttempt} next not before ${e.nextNotBefore} (interval ${Math.round((e.intervalS??0)/3600)} h)`),e.lastResult&&t.push(` last result ${e.lastResult}`),t}async function hr(e,t,n){try{return(await e.readdir(xe(t))).filter(r=>r!==n)}catch{return[]}}function _r(e,t,n,r,o){return Promise.all(o.map(async c=>{let s={scopeId:c,collectorUrl:"",collectorUrlRedacted:await yr(n,x(e.home,c))??"",source:"manifest",dev:!1};return bt(e,t,s,n,r)}))}async function yr(e,t){try{let n=JSON.parse((await e.readFile(q(t))).toString("utf8"));return g(n)&&typeof n.collector=="string"?n.collector:void 0}catch{return}}export{cr as bootstrap,fr as runRefresh,gr as runStatus};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import{spawn as Hn}from"node:child_process";import{homedir as Bn}from"node:os";import{fileURLToPath as Rt}from"node:url";import{createHash as Jt}from"node:crypto";import{join as J}from"node:path";var Ct=/^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/,kt=/^>=(\d+)(?:\.(\d+)(?:\.(\d+))?)?$/,Nt=/^v?(\d+)\.(\d+)\.(\d+)/;function be(e){let t=Ct.exec(e);if(t)return{...q(t),prerelease:t[4]?.split(".")}}function Ot(e,t){let n=be(e),r=be(t);if(!(!n||!r))return n.major!==r.major?n.major-r.major:n.minor!==r.minor?n.minor-r.minor:n.patch!==r.patch?n.patch-r.patch:Tt(n.prerelease,r.prerelease)}function Ee(e,t){let n=Ot(e,t);return n!==void 0&&n>=0}function Lt(e){let t=kt.exec(e.trim());return t?q(t):void 0}function q(e){return{major:Number(e[1]),minor:Number(e[2]??0),patch:Number(e[3]??0)}}function we(e,t){let n=Lt(t),r=Nt.exec(e.trim()),o=r?q(r):void 0;return!n||!o?!1:o.major!==n.major?o.major>n.major:o.minor!==n.minor?o.minor>n.minor:o.patch>=n.patch}function Tt(e,t){if(e===void 0&&t===void 0)return 0;if(e===void 0)return 1;if(t===void 0)return-1;let n=Math.max(e.length,t.length);for(let r=0;r<n;r++){let o=e[r],c=t[r];if(o===void 0)return-1;if(c===void 0)return 1;let s=Ft(o,c);if(s!==0)return s}return 0}function Ft(e,t){let n=/^\d+$/.test(e),r=/^\d+$/.test(t);if(n&&r){let o=Number(e)-Number(t);return o<0?-1:o>0?1:0}return n?-1:r?1:e<t?-1:e>t?1:0}var Q="EV_AI_LAUNCHER_VERSION",Z="EV_AI_LAUNCHER_PROTOCOL",ee="EV_AI_HOOK_SOURCE",D="EV_AI_HOOK_FALLBACK_REASON",U="EV_AI_LAUNCHER_SCOPE",te="EV_AI_LAUNCHER_READY_FD",xe="EV_AI_LAUNCHER_REFRESH_SCOPE",Re="EV_AI_HOOK_UPDATE_TTL_MIN",Ae=Buffer.from([1]),Pe='{"continue":true}',Ce=3e3,ke=1024*1024,Ne=4*1024*1024,ne=64*1024,re=64*1024,H=64*1024,Oe=2e3,B=250,Le=8e3,oe=14e3,Te=1e3,Fe=1e3,T=21600,ie=604800,Ie=3e5,se=4096,Me=4*1024*1024,De=2,Ue=864e5;import{open as He,mkdir as It,readFile as Mt,readdir as Dt,rename as Ut,stat as Ht,unlink as Bt,utimes as jt}from"node:fs/promises";var j=new WeakMap;function Vt(e){if(e&&typeof e=="object"&&"code"in e)return e}function I(e){return Vt(e)?.code==="ENOENT"}async function je(e,t){try{return await e.readdir(t)}catch(n){if(I(n))return[];throw n}}async function Ve(e,t,n){let r=await e.open(t,"wx");try{await e.write(r,n),await e.fsync(r)}finally{await e.close(r)}}function V(){return{async open(e,t){let n=await He(e,t),r={path:e};return j.set(r,n),r},async write(e,t){let n=Be(e),r=typeof t=="string"?Buffer.from(t,"utf8"):t;await n.write(r)},async fsync(e){await Be(e).sync()},async close(e){let t=j.get(e);j.delete(e),t&&await t.close()},rename:Ut,async readdir(e){return Dt(e)},readFile:Mt,async stat(e){let t=await Ht(e);return{mtimeMs:t.mtimeMs,size:t.size,isDirectory:()=>t.isDirectory()}},async mkdir(e,t){await It(e,t)},unlink:Bt,utimes:jt,async fsyncDir(e){if(process.platform==="win32")return;let t=await He(e,"r");try{await t.sync()}finally{await t.close()}}}}function Be(e){let t=j.get(e);if(!t)throw new Error("closed");return t}function x(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}import{join as K}from"node:path";function ae(e){return K(e,".ev-ai","agent-hook","js")}function Kt(e){return K(ae(e),"scopes")}function Ke(e,t){return K(Kt(e),t)}function Je(e){return K(e,"attempts")}function ce(e){return String(e).padStart(10,"0")}var $e="@ev-ai/agent-hook";function $(e,t){return J(ae(e),t?"dev-artifacts":"artifacts")}function de(e,t){return J(e,t,"hook.mjs")}function $t(e,t){return J(e,t,"meta.json")}function le(e,t){return J(e,t,"health.json")}function Wt(e){return Jt("sha256").update(e).digest("hex")}async function Yt(e,t,n){try{let r=await e.stat(t);return r.size<=0||r.size>Me?"bad":Wt(await e.readFile(t))===n?"ok":"bad"}catch(r){if(I(r))return"missing";throw r}}async function We(e,t,n,r,o,c=process.version){let[s,i,a]=await Promise.all([Yt(e,de(t,n),n),Gt(e,$t(t,n)),fe(e,le(t,n))]);if(s==="missing")return{usable:!1,reason:"artifact_missing"};if(s==="bad"||!i)return{usable:!1,reason:"hash_mismatch"};if(!Ee(i.version,r))return{usable:!1,reason:"below_floor"};if(!we(c,i.node_engine))return{usable:!1,reason:"incompatible_node"};if(i.min_launcher_protocol>1)return{usable:!1,reason:"incompatible_protocol"};if(a?.quarantined_until){let u=Date.parse(a.quarantined_until);if(Number.isFinite(u)&&u>o)return{usable:!1,reason:"quarantined"}}return{usable:!0,meta:i,healthFails:a?.consecutive_startup_failures??0}}async function Gt(e,t){try{let n=await e.readFile(t);return zt(JSON.parse(n.toString("utf8")))}catch{return}}function zt(e){if(!x(e))return;let t=e;if(t.package===$e&&!(typeof t.version!="string"||t.version.length===0)&&typeof t.node_engine=="string"&&!(typeof t.min_launcher_protocol!="number"||!Number.isInteger(t.min_launcher_protocol))&&!(typeof t.integrity!="string"||!t.integrity.startsWith("sha512-"))&&typeof t.installed_at=="string")return{package:$e,version:t.version,node_engine:t.node_engine,min_launcher_protocol:t.min_launcher_protocol,integrity:t.integrity,installed_at:t.installed_at}}async function fe(e,t){try{let n=await e.readFile(t),r=JSON.parse(n.toString("utf8"));if(!x(r))return;let o=r.consecutive_startup_failures;if(typeof o!="number"||!Number.isInteger(o)||o<0)return;let c={consecutive_startup_failures:o};return typeof r.quarantined_until=="string"&&(c.quarantined_until=r.quarantined_until),c}catch{return}}import{randomBytes as gn}from"node:crypto";import{basename as _n,dirname as yn,join as Sn}from"node:path";import{createHash as Xt}from"node:crypto";import{access as qt,readFile as Qt,stat as Zt}from"node:fs/promises";import{homedir as en}from"node:os";import{dirname as tn,join as me,parse as nn,resolve as Ye}from"node:path";var rn="https://hooks.ev-ai.ai",on=".claude/ev-ai-runtime-report.json",sn="config.json",an=1024*1024,Qe=new Set(["localhost","127.0.0.1","[::1]","::1"]),cn=["claude","cursor","codex"],un=[on,".cursor/ev-ai-runtime-report.json",".codex/ev-ai-runtime-report.json"],Ge=/^[A-Za-z0-9._~-]+$/;function dn(e){return e!==void 0&&cn.includes(e)}function W(e,t){let n=e[t+1];return n&&!n.startsWith("--")?{value:n,next:t+1}:{next:t}}function pe(e){let t,n,r,o,c;for(let s=0;s<e.length;s++){let i=e[s];if(i!==void 0){if(i==="--runner"){let a=W(e,s);t=a.value,s=a.next;continue}if(i.startsWith("--runner=")){t=i.slice(9);continue}if(i==="--url"){let a=W(e,s);a.value&&(r=a.value),s=a.next;continue}if(i.startsWith("--url=")){r=i.slice(6);continue}if(i==="--token"){let a=W(e,s);a.value&&(o=a.value),s=a.next;continue}if(i.startsWith("--token=")){o=i.slice(8);continue}if(i==="--base-url"){let a=W(e,s);a.value&&(c=a.value),s=a.next;continue}if(i.startsWith("--base-url=")){c=i.slice(11);continue}!i.startsWith("-")&&n===void 0&&(n=i)}}return{runner:dn(t)?t:void 0,event:n,collectorUrl:r,orgToken:o,baseUrl:c}}function Ze(e,t=rn){let n=t.replace(/\/+$/,""),r=e.trim();return`${n}/${r}/hook`}function he(e=en()){return me(e,".ev-ai",sn)}function ln(e,t){return{...e,...t}}function ze(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<=32||n===127||n===39)return!0}return!1}function fn(e){try{let t=new URL(e);return t.protocol==="https:"?!0:t.protocol==="http:"?Qe.has(t.hostname):!1}catch{return!1}}function et(e){try{let n=new URL(e).pathname.split("/").filter(r=>r.length>0);if(n.length>=2&&n[n.length-1]==="hook"){let r=n[n.length-2];return r&&r.length>0?r:void 0}return}catch{return}}function tt(e){let t;try{t=new URL(e)}catch{return`invalid URL (got: ${e})`}if(!fn(e))return`must be https (or http on localhost / 127.0.0.1 / ::1) (got: ${e})`;let n=et(e);if(!n)return`must end with /{orgToken}/hook (got: ${e})`;if(!Ge.test(n))return`org token must match ${Ge.source} (got: ${n})`;if(ze(e))return`must not contain whitespace, control characters, or single quotes (got: ${e})`;if(ze(t.pathname))return`pathname must not contain whitespace, control characters, or single quotes (got: ${e})`}function mn(e){return new URL(e).toString()}function Xe(e){if(e.collector_url)return e.collector_url;let t=e.repo_ingest_token,n=typeof t=="string"?t.trim():void 0;return n?Ze(n):""}function nt(e){try{return Qe.has(new URL(e).hostname)}catch{return!1}}function rt(e){try{let t=new URL(e),n=t.pathname.split("/").filter(r=>r.length>0);return n.length>=2&&n[n.length-1]==="hook"&&(n[n.length-2]="***",t.pathname=`/${n.join("/")}`),t.toString()}catch{return"<invalid-url>"}}function pn(e){let t=e.collectorUrl?.trim(),n;if(t)n=t;else{let o=e.orgToken?.trim();o&&(n=Ze(o,e.baseUrl?.trim()??void 0))}if(!n)return{};let r=tt(n);return r?{problem:r}:{url:mn(n)}}var ge={access:qt,stat:Zt,readFile:(e,t)=>Qt(e,t)};async function hn(e,t,n=ge){let r=Ye(e),{root:o}=nn(r);for(;;){let s=me(r,".git");try{let a=await n.stat(s);if(a.isDirectory()||a.isFile())return r}catch{}if(r===o)break;let i=tn(r);if(i===r)break;r=i}let c=t.CURSOR_PROJECT_DIR??t.CLAUDE_PROJECT_DIR;if(c)try{if((await n.stat(c)).isDirectory())return c}catch{}return Ye(e)}async function M(e,t=ge){try{let n=await t.stat(e);if(!n.isFile()||n.size>an)return;let r=await t.readFile(e,"utf8"),o=JSON.parse(r);return o===null||typeof o!="object"||Array.isArray(o)?void 0:o}catch{return}}async function qe(e,t){return(await Promise.all(un.map(async r=>{let o=me(e,r);try{return await t.access(o),o}catch{return}}))).find(r=>r!==void 0)}async function ot(e){let t=e.fs??ge,n=pn(pe(e.argv));if(n.url)return{url:n.url,source:"argv"};let r=e.env.EV_AI_HOOK_MANIFEST;if(r)try{await t.access(r);let p=await M(r,t),l=p?Xe(p):"";return l?{url:l,source:"manifest_override"}:{source:"none"}}catch{}let o=await hn(e.cwd,e.env,t),c=he(e.home),[s,i]=await Promise.all([M(c,t),qe(o,t).then(async p=>p??qe(e.cwd,t))]),a=i?await M(i,t):void 0,u;s&&a?u=ln(a,s):s?u=s:a&&(u=a);let f=u?Xe(u):"";return f?{url:f,source:"manifest"}:{source:"none"}}function it(e){if(tt(e))return;let t;try{t=new URL(e)}catch{return}let n=et(e);if(!n)return;let o=t.pathname.split("/").filter(i=>i.length>0).slice(0,-2),c=o.length>0?`/${o.join("/")}`:"",s=`${t.origin}${c}/${n}`;return Xt("sha256").update(s).digest("hex").slice(0,32)}async function Y(e,t){return e.EV_AI_AUTO_UPDATE==="0"?!0:(await M(he(t)))?.auto_update===!1}function F(e){return!!e.CURSOR_SANDBOX}async function at(e,t,n,r,o,c){if(F(c))return;let s=le(t,n),i=await fe(e,s),a=i?.consecutive_startup_failures??0;if(!r){a>0&&await st(e,s,{consecutive_startup_failures:0});return}let u={consecutive_startup_failures:a+1};a+1>=De?u.quarantined_until=new Date(o+Ue).toISOString():i?.quarantined_until&&(u.quarantined_until=i.quarantined_until),await st(e,s,u)}async function st(e,t,n){let r=yn(t),o=Sn(r,`.${_n(t)}.${gn(8).toString("hex")}`);await Ve(e,o,JSON.stringify(n));try{await e.rename(o,t)}catch(c){throw await e.unlink(o).catch(()=>{}),c}await e.fsyncDir(r)}function vn(e,t){return new Promise(n=>{try{e.write(t,()=>n())}catch{n()}})}function ct(e){let t=e.now(),n=oe,r=!1,o=Promise.resolve(),c,s=!1,i=[],a,u,f,p=()=>Math.max(0,t+n-e.now()),l=[],d=(h,S)=>{if(e.installProcessHandlers===!1)return;(e.on??((O,g)=>process.on(O,g)))(h,S),l.push({event:h,handler:S})},_=()=>{let h=e.off??((S,R)=>process.off(S,R));for(let{event:S,handler:R}of l)try{h(S,R)}catch{}l.length=0},y=h=>(r||(r=!0,o=vn(e.stdout,h??Pe)),o),v=h=>{if(c)try{c.kill(h)}catch{}},E=()=>{for(let h of i)try{h()}catch{}},N=()=>{s||(E(),v("SIGTERM"),u=e.setTimeout(()=>{v("SIGKILL")},B),y())},b=()=>{y().finally(()=>{e.exit(0)})},k=()=>{s||(E(),b())},L=()=>{a&&e.clearTimeout(a),f&&e.clearTimeout(f),a=e.setTimeout(N,p());let h=Math.max(0,t+n+Te-e.now());f=e.setTimeout(k,h)};L(),d("uncaughtException",b),d("unhandledRejection",b);for(let h of["SIGTERM","SIGINT"])d(h,()=>{v(h),b()});return{ackOnce:y,remainingMs:p,eventBudgetMs:()=>n,onEventClassified(h){let S=h?oe:Le;S<n&&(n=S,L())},setChild(h){c=h},onAbort(h){i.push(h)},dispose(){s=!0,a&&e.clearTimeout(a),u&&e.clearTimeout(u),f&&e.clearTimeout(f),_()},waitForAckWrite(){return o}}}function bn(e){let t=e.trim();if(t)try{let n=JSON.parse(t);return x(n)?n:void 0}catch{return}}function ut(e,t,n,r){if(!t||n!==0||r)return;let o=e.toString("utf8");if(bn(o)!==void 0)return o.trim()}var dt=[Q,Z,U,te,ee,D];function _e(e){return Buffer.isBuffer(e)?e:Buffer.from(e)}function En(e,t,n){let r={...e.env};return r[te]="3",r[Q]=n,r[Z]=String(1),r[ee]=t.source,t.fallbackReason?r[D]=t.fallbackReason:delete r[D],t.scopeId?r[U]=t.scopeId:delete r[U],r}function wn(e){let t=e.stdio[3];if(t&&typeof t=="object"&&"on"in t)return t}async function ye(e,t,n,r,o,c,s="live"){let i;try{i=o.spawn(o.execPath,[e.hookPath,...t],{cwd:o.cwd,env:En(o,e,c),stdio:["pipe","pipe","pipe","pipe"],windowsHide:!0})}catch{return{outcome:"spawn_failed",ready:!1}}r.setChild(i);let a=!1,u=i.stdout,f=i.stderr,p=i.stdin,l=wn(i);if(!u||!f||!p){try{i.kill("SIGKILL")}catch{}return n.stopChildWrites(),r.setChild(void 0),{outcome:"spawn_failed",ready:!1}}s==="replay"?n.replayTo(p):n.attachChild(p);let d="pending",_=Buffer.alloc(0),y=!1,v=!1,E=!1,N=0,b=null,k=!1,L=g=>{if(y)return;if(_.length+g.length>ne){_=Buffer.concat([_,g.subarray(0,ne-_.length)]),y=!0;return}_=Buffer.concat([_,g])};u.on("data",g=>{L(_e(g))}),u.on("end",()=>{v=!0}),u.on("error",()=>{E=!0,v=!0}),f.on("data",g=>{if(N>=re)return;let w=_e(g),A=re-N,m=w.length>A?w.subarray(0,A):w;N+=m.length;try{o.stderr.write(m)}catch{}}),f.resume(),l?(l.on("data",g=>{d==="pending"&&_e(g).includes(Ae[0]??1)&&(d="byte")}),l.on("end",()=>{d==="pending"&&(d="eof")}),l.on("error",()=>{d==="pending"&&(d="error")})):d="error";let h=o.setTimeout(()=>{if(!(d!=="pending"||k))try{i.kill("SIGKILL")}catch{}},Oe);await new Promise(g=>{let w=!1,A=()=>{w||(w=!0,g())};i.once("exit",m=>{k=!0,b=m,A()}),i.once("error",()=>{a=!0,k=!0,A()})}),n.stopChildWrites(),o.clearTimeout(h);let S=Math.min(B,Math.max(0,r.remainingMs()));await new Promise(g=>{let w=()=>d!=="pending"&&v;if(w()){g();return}let A=o.setTimeout(()=>g(),S),m=()=>{w()&&(o.clearTimeout(A),g())};u.on("end",m),u.on("error",m),l?.on("end",m),l?.on("error",m),l?.on("data",m)}),u.removeAllListeners(),f.removeAllListeners(),l?.removeAllListeners();try{u.destroy()}catch{}try{f.destroy()}catch{}try{l?.destroy()}catch{}if(r.setChild(void 0),a)return{outcome:"spawn_failed",ready:!1};let R=d==="byte",O=ut(_,R,b,y||E);return O!==void 0?(await r.ackOnce(O),{outcome:"success",ready:!0}):d==="eof"?{outcome:"startup_failure",ready:!1}:{outcome:"runtime_failure",ready:R}}function xn(e){let t=e.charAt(0);return t!==""&&t.toLowerCase()===t}function Rn(e,t){let n=e.toLowerCase();return n==="sessionend"||n==="stopfailure"||n==="subagentstop"?!0:n==="stop"&&t==="codex"}function lt(e,t,n){let r=n.EV_AI_HOOK_SYNC==="1";if(t===void 0||Buffer.byteLength(t,"utf8")>=H)return{isSessionStart:!1,isInProcess:r};let o=pe(e),c=o.event??"",s=o.runner??"";try{let i=JSON.parse(t);x(i)&&(!c&&typeof i.hook_event_name=="string"?c=i.hook_event_name:!c&&typeof i.event=="string"&&(c=i.event),!s&&(typeof i.conversation_id=="string"||xn(c))&&(s="cursor"))}catch{}return{isSessionStart:c.toLowerCase()==="sessionstart",isInProcess:r||Rn(c,s)}}import{readFile as An}from"node:fs/promises";import{fileURLToPath as Pn}from"node:url";async function ft(e){let t=Pn(new URL("../package.json",e)),n=await An(t,"utf8"),r=JSON.parse(n);return{version:typeof r.version=="string"?r.version:"",evAi:{launcherProtocol:Se(r.evAi?.launcherProtocol),minLauncherProtocol:Se(r.evAi?.minLauncherProtocol),launcherRevision:Se(r.evAi?.launcherRevision)}}}function Se(e){return typeof e=="number"&&Number.isInteger(e)?e:0}var Cn=new Set(["configure","install","migrate-to-plugin","update","uninstall","--version","-V","help","--help","-h"]);function G(e){let t=e[0];return t==="status"?"status":t==="__refresh"?"refresh":t==="__work"||t==="__post"?"bundled_cli":t===void 0||Cn.has(t)?"cli":"hook"}async function mt(e,t){let n=await ot({argv:e,env:t.env,cwd:t.cwd,home:t.home});if(!n.url)return;let r=it(n.url);if(!(!r||n.source==="none"))return{scopeId:r,collectorUrl:n.url,collectorUrlRedacted:rt(n.url),source:n.source,dev:nt(n.url)}}import{join as pt}from"node:path";var kn=/^(\d{10})$/,Nn=/^(\d{10})\.done$/,On=/^[0-9a-f]{64}$/i;function yt(e){let t=e[Re];if(t===void 0||t==="")return T;let n=Number(t);return!Number.isInteger(n)||n<=0?T:Math.min(Math.max(T,n*60),ie)}async function St(e,t,n=!1){let r=Je(t),o=await je(e,r),c=new Map,s=new Map,i=ht(o,kn),a=ht(o,Nn),u=async l=>{let d=await _t(e,pt(r,Tn(l)));return d&&c.set(l,{record:Mn(d.value),mtimeMs:d.mtimeMs}),d!==void 0},f=async l=>{let d=Dn((await _t(e,pt(r,Fn(l))))?.value);return d&&s.set(l,d),d!==void 0};if(!n)return await Promise.all([...i.map(u),...a.map(f)]),{claims:c,dones:s};await Promise.all([gt(i,u),gt(a,f)]);let p=z(c);return p<z(s)&&a.includes(p)&&await f(p),{claims:c,dones:s}}function ht(e,t){return e.flatMap(n=>{let r=t.exec(n);return r?[Number(r[1])]:[]})}async function gt(e,t){for(let n of[...e].sort((r,o)=>o-r))if(await t(n))return}function z(e){let t=0;for(let n of e.keys())n>t&&(t=n);return t}function vt(e,t,n){let r=z(e.claims),o=z(e.dones),c=r===0?{kind:"uninitialized"}:{kind:"bundled",why:"bootstrap_failed"},s;if(o>0){let d=e.dones.get(o);d&&(c=d.selection,s=d.outcome)}let i=r>0?e.claims.get(r):void 0,a=i?Ln(i):void 0,u=r>0?e.dones.get(r):void 0,f=In(u?.interval_s,n),p=a!==void 0?a+f*1e3:void 0,l=a!==void 0&&a-t>Ie;return{latest:r,startMs:a,intervalS:f,deadlineMs:p,selection:c,lastOutcome:s,futureDated:l,highestDone:o}}function Ln(e){if(e.record!=="empty"&&e.record.started_at){let t=Date.parse(e.record.started_at);if(Number.isFinite(t))return t}return e.mtimeMs}function Tn(e){return ce(e)}function Fn(e){return`${ce(e)}.done`}function In(e,t){return typeof e!="number"||!Number.isFinite(e)||e<=0?Math.max(T,t):Math.min(Math.max(Math.floor(e),T,t),ie)}async function _t(e,t){let n;try{n=await e.stat(t)}catch(o){if(I(o))return;throw o}let r=n.mtimeMs;if(n.size===0||n.size>se)return{mtimeMs:r};try{let o=await e.readFile(t);return o.byteLength===0||o.byteLength>se?{mtimeMs:r}:{mtimeMs:r,value:JSON.parse(o.toString("utf8"))}}catch{return{mtimeMs:r}}}function Mn(e){if(!x(e))return"empty";let t={};return typeof e.started_at=="string"&&(t.started_at=e.started_at),(e.owner==="bootstrap"||e.owner==="refresh")&&(t.owner=e.owner),e.resync===!0&&(t.resync=!0),t}function Dn(e){if(!x(e))return;let t=e;if(typeof t.finished_at!="string"||typeof t.outcome!="string"||typeof t.interval_s!="number"||!Number.isFinite(t.interval_s))return;let n=Un(t.selection);if(n)return{finished_at:t.finished_at,interval_s:t.interval_s,outcome:t.outcome,selection:n}}function Un(e){if(!x(e))return;let t=e;if(t.kind==="bundled")return t.why==="server"||t.why==="bootstrap_failed"?{kind:"bundled",why:t.why}:void 0;if(t.kind==="cached"&&typeof t.digest=="string"&&On.test(t.digest)&&typeof t.version=="string"&&t.version.length>0&&typeof t.integrity=="string"&&t.integrity.startsWith("sha512-"))return{kind:"cached",digest:t.digest.toLowerCase(),version:t.version,integrity:t.integrity}}function X(e,t){return new URL(t,e.launcherUrl??import.meta.url)}function C(e,t,n,r){return{source:"bundled",hookPath:e.bundledHookPath,fallbackReason:t,scopeId:n?.scopeId,dev:n?.dev,...r}}async function bt(e,t,n){if(await Y(t.env,t.home))return C(t,"kill_switch",n);if(!n)return C(t,"no_collector_url",n);let r=V(),o=yt(t.env),c=t.now(),s=Ke(t.home,n.scopeId),i=vt(await St(r,s,!0),c,o),a={deadlineMs:i.deadlineMs,dev:n.dev};if(i.selection.kind==="cached"){let f=$(t.home,n.dev),p=await t.readPackageInfo().then(d=>d.version,()=>""),l=await We(r,f,i.selection.digest,p,c);return l.usable?{source:"cached",hookPath:de(f,i.selection.digest),scopeId:n.scopeId,digest:i.selection.digest,healthFails:l.healthFails,...a}:C(t,l.reason,n,a)}if(i.selection.kind==="bundled")return C(t,i.selection.why,n,a);if(F(t.env))return C(t,"sandboxed",n,a);let u=await ve(t);if(!u)return C(t,"bootstrap_failed",n,a);try{let f=await t.readPackageInfo();return await u.bootstrap({home:t.home,scope:n,bundledVersion:f.version,bundledHookPath:t.bundledHookPath,env:t.env,nowMs:c})}catch{return C(t,"bootstrap_failed",n,a)}}async function ve(e){try{return e.importUpdate?await e.importUpdate():await import(X(e,"./launcher-update.mjs").href)}catch{return}}function Et(e,t,n=Ce){let r=[],o=[],c=0,s=0,i="pending",a,u=!1,f=!1,p=!1,l=!1,d=!1,_=[],y=()=>{!l&&typeof e.pause=="function"&&(e.pause(),l=!0)},v=()=>{l&&typeof e.resume=="function"&&(e.resume(),l=!1)},E=()=>{u=!1,p=!1,f=!0,v()},N=()=>{if(!(d||i==="pending")){d=!0,t.clearTimeout(g);for(let m of _)m();_.length=0}},b=m=>{i==="pending"&&(i=m),N()},k=()=>{if(u&&a)try{a.end()}catch{u=!1}},L=m=>{if(i==="oversize")return;let P=s+m.length;if(P>Ne){b("oversize");return}o.push(m),s=P},h=m=>{if(!(!u||!a))try{if(!a.write(m)){if(a.destroyed||!a.writable){E();return}p=!0,y()}}catch{E()}},S=m=>{let P=Buffer.isBuffer(m)?m:Buffer.from(m);if(!(i==="truncated"||i==="complete")&&(L(P),!f)){if(u){h(P);return}r.push(P),c+=P.length,c>=ke&&y()}},R=()=>{k(),b("complete")},O=()=>{i==="pending"&&b("truncated")},g=t.setTimeout(()=>{i==="pending"&&(b("truncated"),k(),E())},n);"isTTY"in e&&!!e.isTTY?b("complete"):(e.on("data",S),e.on("end",R),e.on("error",O),typeof e.resume=="function"&&e.resume());let A=m=>{m.on("error",()=>{E()}),m.on("drain",()=>{!u||f||(p=!1,v())})};return{get state(){return i},get replayable(){return i==="complete"},get backlogBytes(){return c},get replayBytes(){return s},attachChild(m){a=m,f=!1,u=!0,p=!1,A(m);for(let P of r){if(!u)break;h(P)}if(r.length=0,c=0,p?y():v(),i!=="pending"){try{m.end()}catch{E()}u=!1}},replayTo(m){A(m);try{m.end(o.length>0?Buffer.concat(o,s):Buffer.alloc(0))}catch{}},stopChildWrites(){E()},dispose(){t.clearTimeout(g),e.off?.("data",S),e.off?.("end",R),e.off?.("error",O)},classifiableText(){if(!(i!=="complete"||s>=H))return Buffer.concat(o,s).toString("utf8")},whenSettled(){return d?Promise.resolve():new Promise(m=>{_.push(m)})}}}var At={version:"",evAi:{launcherProtocol:1,minLauncherProtocol:1,launcherRevision:1}};function jn(e){return Rt(new URL("./hook.mjs",e))}function Vn(e){let t;return{stdin:process.stdin,stdout:process.stdout,stderr:process.stderr,env:process.env,cwd:process.cwd(),home:Bn(),now:()=>Date.now(),spawn:Hn,exit:n=>{process.exit(n)},setTimeout,clearTimeout,bundledHookPath:jn(e),execPath:process.execPath,select:bt,readPackageInfo:()=>t??=ft(e),launcherUrl:e}}async function wt(e){return e.importCli?e.importCli():import(X(e,"./cli.mjs").href)}async function Pt(e=process.argv.slice(2),t=Vn(import.meta.url)){let n=G(e);if(n==="cli")try{return await(await wt(t)).main(e)}catch(s){let i=s instanceof Error?s.message:String(s);try{t.stderr.write(`[ev-ai-agent-hook] ${i}
|
|
4
|
+
`)}catch{}return 1}if(n==="bundled_cli")return(await wt(t)).main(e);if(n==="refresh"||n==="status")try{let s=await t.readPackageInfo().catch(()=>At),i=await ve(t);return i?n==="refresh"?await i.runRefresh(e.slice(1),t.env,t.cwd,t.home,{packageVersion:s.version}):await i.runStatus(e,t,s):0}catch{return 0}let r=()=>{},o=new Promise(s=>{r=s}),c={...t,exit:s=>{t.exit(s),r(s)}};return Promise.race([Kn(e,c,r),o])}async function Kn(e,t,n){let r=ct(t),o=Et(t.stdin,t),c,s=()=>c??=lt(e,o.classifiableText(),t.env);o.whenSettled().then(()=>r.onEventClassified(s().isInProcess));let i=!1,a=new Promise(p=>{r.onAbort(()=>{i=!0,p()})}),u=p=>Promise.race([p,a.then(()=>{})]),f=async p=>(await r.ackOnce(),r.dispose(),o.dispose(),n(p),p);try{let p=t.readPackageInfo().catch(()=>At),l;try{l=await u(mt(e,t))}catch{l=void 0}if(i)return f(0);let d;try{d=await u(t.select(e,t,l))}catch{d=C(t,"selection_error",l)}let _=await u(p);if(i||!d||!_)return f(0);let y=await ye(d,e,o,r,t,_.version,"live");if(y.outcome==="success"&&d.source==="cached"&&d.healthFails&&await xt(t,d,!1),y.outcome==="startup_failure"&&d.source!=="bundled"&&(await xt(t,d,!0),o.replayable&&r.remainingMs()>Fe)){let v=C(t,"startup_failure",l);await ye(v,e,o,r,t,_.version,"replay")}return await Jn(e,t,d,l,o.replayable,s),f(0)}catch{return f(0)}}async function Jn(e,t,n,r,o,c){if(!r||n.didBootstrap||!o||F(t.env)||n.deadlineMs!==void 0&&n.deadlineMs>t.now()||!c().isSessionStart||await Y(t.env,t.home))return;let s={...t.env};for(let i of dt)delete s[i];s[xe]=r.scopeId;try{t.spawn(t.execPath,[Rt(X(t,"./launcher.mjs")),"__refresh",...e],{cwd:t.cwd,env:s,detached:!0,stdio:"ignore",windowsHide:!0}).unref()}catch{}}async function xt(e,t,n){t.digest&&await at(V(),$(e.home,t.dev===!0),t.digest,n,e.now(),e.env).catch(()=>{})}Pt().then(e=>{process.exit(e)}).catch(e=>{if(G(process.argv.slice(2))==="cli"){let t=e instanceof Error?e.message:String(e);try{process.stderr.write(`[ev-ai-agent-hook] ${t}
|
|
5
|
+
`)}catch{}process.exit(1)}try{process.stdout.write('{"continue":true}')}catch{}process.exit(0)});
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/managed-hooks-snippet.ts
|
|
21
|
+
var managed_hooks_snippet_exports = {};
|
|
22
|
+
__export(managed_hooks_snippet_exports, {
|
|
23
|
+
buildCollectorUrl: () => buildCollectorUrl,
|
|
24
|
+
managedHooksSnippet: () => managedHooksSnippet
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(managed_hooks_snippet_exports);
|
|
27
|
+
|
|
28
|
+
// src/collector-url-resolve.ts
|
|
29
|
+
var DEFAULT_COLLECTOR_BASE_URL = "https://hooks.ev-ai.ai";
|
|
30
|
+
var MAX_JSON_FILE_BYTES = 1024 * 1024;
|
|
31
|
+
function buildCollectorUrl(orgToken, baseUrl = DEFAULT_COLLECTOR_BASE_URL) {
|
|
32
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
33
|
+
const token = orgToken.trim();
|
|
34
|
+
return `${normalizedBase}/${token}/hook`;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/constants.ts
|
|
38
|
+
var HOOK_BINARY_NAME = "ev-ai-agent-hook";
|
|
39
|
+
var HOOK_CHECKSUMS_FILE = "SHA256SUMS";
|
|
40
|
+
var GLOBAL_HOOK_BINARY_RELATIVE = `current/${HOOK_BINARY_NAME}`;
|
|
41
|
+
var PROJECT_HOOK_BINARY_RELATIVE = `.ev-ai/agent-hook/${HOOK_BINARY_NAME}`;
|
|
42
|
+
var HOOK_INPUT_ALLOWLIST_MAX_BYTES = 4 * 1024;
|
|
43
|
+
var HOOK_INPUT_FULL_MAX_BYTES = 256 * 1024;
|
|
44
|
+
var HOOK_INPUT_MCP_MAX_BYTES = 4 * 1024;
|
|
45
|
+
var GZIP_MIN_BYTES = 32 * 1024;
|
|
46
|
+
var USER_SPEC_COOLDOWN_MS = 14 * 60 * 60 * 1e3;
|
|
47
|
+
var PACKAGE_VERSION = "1.2.0";
|
|
48
|
+
var NPX_PACKAGE_SPEC = `@ev-ai/agent-hook@${PACKAGE_VERSION}`;
|
|
49
|
+
var HOOK_STATUS_MESSAGE = "ev-ai runtime report";
|
|
50
|
+
|
|
51
|
+
// src/install.ts
|
|
52
|
+
function isSessionStartEvent(eventName) {
|
|
53
|
+
return eventName === "SessionStart" || eventName === "sessionStart";
|
|
54
|
+
}
|
|
55
|
+
function withoutPreferOffline(command) {
|
|
56
|
+
return command.replace(/\s+--prefer-offline\b/g, "");
|
|
57
|
+
}
|
|
58
|
+
function commandForEvent(eventName, command) {
|
|
59
|
+
return isSessionStartEvent(eventName) ? withoutPreferOffline(command) : command;
|
|
60
|
+
}
|
|
61
|
+
function npxHookCommand(packageSpec = NPX_PACKAGE_SPEC) {
|
|
62
|
+
return `npx -y --prefer-offline ${packageSpec}`;
|
|
63
|
+
}
|
|
64
|
+
function withRunnerFlag(command, runner) {
|
|
65
|
+
const stripped = command.replace(/\s+--runner(?:=|\s+)\S+/g, "").trimEnd();
|
|
66
|
+
return `${stripped} --runner ${runner}`;
|
|
67
|
+
}
|
|
68
|
+
var FLAG_VALUE = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
69
|
+
function withUrlFlag(command, collectorUrl) {
|
|
70
|
+
const stripped = command.replace(new RegExp(`\\s+--url(?:=|\\s+)${FLAG_VALUE}`, "g"), "").replace(new RegExp(`\\s+--token(?:=|\\s+)${FLAG_VALUE}`, "g"), "").replace(new RegExp(`\\s+--base-url(?:=|\\s+)${FLAG_VALUE}`, "g"), "").trimEnd();
|
|
71
|
+
const quoted = collectorUrl.replace(/'/g, `'\\''`);
|
|
72
|
+
return `${stripped} --url '${quoted}'`;
|
|
73
|
+
}
|
|
74
|
+
function toCommandList(command) {
|
|
75
|
+
return typeof command === "string" ? [command] : command;
|
|
76
|
+
}
|
|
77
|
+
function desiredClaudeHookGroups(command) {
|
|
78
|
+
const commandHook = (eventName = "") => ({
|
|
79
|
+
hooks: toCommandList(command).map((entry) => ({
|
|
80
|
+
type: "command",
|
|
81
|
+
command: commandForEvent(eventName, entry)
|
|
82
|
+
}))
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
SessionStart: [commandHook("SessionStart")],
|
|
86
|
+
// Slash skills bypass PreToolUse(Skill); UserPromptExpansion is the observable path.
|
|
87
|
+
UserPromptExpansion: [commandHook()],
|
|
88
|
+
// Prompt bodies (non-slash included). Slash skill ids still come from Expansion.
|
|
89
|
+
UserPromptSubmit: [commandHook()],
|
|
90
|
+
// All tools (replaces prior Skill-only matcher on reinstall).
|
|
91
|
+
PreToolUse: [commandHook()],
|
|
92
|
+
PostToolUse: [commandHook()],
|
|
93
|
+
PostToolUseFailure: [commandHook()],
|
|
94
|
+
// Denied-before-run tools never fire PostToolUseFailure.
|
|
95
|
+
PermissionDenied: [commandHook()],
|
|
96
|
+
Stop: [commandHook()],
|
|
97
|
+
// Turn ended due to API error (rate_limit / overloaded / …).
|
|
98
|
+
StopFailure: [commandHook()],
|
|
99
|
+
SessionEnd: [commandHook()],
|
|
100
|
+
SubagentStart: [commandHook()],
|
|
101
|
+
SubagentStop: [commandHook()]
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function desiredCodexHookGroups(command) {
|
|
105
|
+
const spec = typeof command === "string" ? { command } : command;
|
|
106
|
+
const commandHook = (eventName = "") => ({
|
|
107
|
+
hooks: [
|
|
108
|
+
{
|
|
109
|
+
type: "command",
|
|
110
|
+
command: commandForEvent(eventName, spec.command),
|
|
111
|
+
...spec.commandWindows === void 0 ? {} : { commandWindows: commandForEvent(eventName, spec.commandWindows) },
|
|
112
|
+
statusMessage: HOOK_STATUS_MESSAGE
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
SessionStart: [commandHook("SessionStart")],
|
|
118
|
+
// Slash / custom-prompt skill ids from prompt text (body never POSTed on allowlist).
|
|
119
|
+
UserPromptSubmit: [commandHook()],
|
|
120
|
+
PreToolUse: [commandHook()],
|
|
121
|
+
PostToolUse: [commandHook()],
|
|
122
|
+
Stop: [commandHook()]
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
var CURSOR_WIRED_HOOK_EVENTS = [
|
|
126
|
+
"sessionStart",
|
|
127
|
+
"beforeSubmitPrompt",
|
|
128
|
+
"preToolUse",
|
|
129
|
+
"postToolUse",
|
|
130
|
+
"postToolUseFailure",
|
|
131
|
+
"beforeShellExecution",
|
|
132
|
+
"beforeReadFile",
|
|
133
|
+
"beforeMCPExecution",
|
|
134
|
+
"subagentStart",
|
|
135
|
+
"subagentStop",
|
|
136
|
+
"stop"
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
// src/plugin-hooks.ts
|
|
140
|
+
var PLUGIN_HOOK_PAYLOAD = "hook.mjs";
|
|
141
|
+
var PLUGIN_CHECKSUMS_FILE = HOOK_CHECKSUMS_FILE;
|
|
142
|
+
function buildClaudePluginHooks(command) {
|
|
143
|
+
return { hooks: desiredClaudeHookGroups(command) };
|
|
144
|
+
}
|
|
145
|
+
function buildCursorPluginHooks(command) {
|
|
146
|
+
const hooks = {};
|
|
147
|
+
for (const eventName of CURSOR_WIRED_HOOK_EVENTS) {
|
|
148
|
+
hooks[eventName] = toCommandList(command).map((entry) => ({
|
|
149
|
+
command: commandForEvent(eventName, entry)
|
|
150
|
+
}));
|
|
151
|
+
}
|
|
152
|
+
return { hooks };
|
|
153
|
+
}
|
|
154
|
+
function buildCodexPluginHooks(command) {
|
|
155
|
+
return { hooks: desiredCodexHookGroups(command) };
|
|
156
|
+
}
|
|
157
|
+
var PLUGIN_PAYLOAD_FILES = [
|
|
158
|
+
{ source: "dist/hook.mjs", target: PLUGIN_HOOK_PAYLOAD, executable: false },
|
|
159
|
+
{
|
|
160
|
+
source: `compile-out/bin/${PLUGIN_CHECKSUMS_FILE}`,
|
|
161
|
+
target: PLUGIN_CHECKSUMS_FILE,
|
|
162
|
+
executable: false,
|
|
163
|
+
optional: true
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
|
|
167
|
+
// src/managed-hooks-snippet.ts
|
|
168
|
+
function managedHooksSnippet(runner, collectorUrl) {
|
|
169
|
+
const command = withUrlFlag(withRunnerFlag(npxHookCommand(), runner), collectorUrl);
|
|
170
|
+
const doc = runner === "cursor" ? { version: 1, ...buildCursorPluginHooks(command) } : runner === "claude" ? buildClaudePluginHooks(command) : buildCodexPluginHooks(command);
|
|
171
|
+
return JSON.stringify(doc, null, 2);
|
|
172
|
+
}
|
|
173
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
174
|
+
0 && (module.exports = {
|
|
175
|
+
buildCollectorUrl,
|
|
176
|
+
managedHooksSnippet
|
|
177
|
+
});
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// src/collector-url-resolve.ts
|
|
2
|
+
var DEFAULT_COLLECTOR_BASE_URL = "https://hooks.ev-ai.ai";
|
|
3
|
+
var MAX_JSON_FILE_BYTES = 1024 * 1024;
|
|
4
|
+
function buildCollectorUrl(orgToken, baseUrl = DEFAULT_COLLECTOR_BASE_URL) {
|
|
5
|
+
const normalizedBase = baseUrl.replace(/\/+$/, "");
|
|
6
|
+
const token = orgToken.trim();
|
|
7
|
+
return `${normalizedBase}/${token}/hook`;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// src/constants.ts
|
|
11
|
+
var HOOK_BINARY_NAME = "ev-ai-agent-hook";
|
|
12
|
+
var HOOK_CHECKSUMS_FILE = "SHA256SUMS";
|
|
13
|
+
var GLOBAL_HOOK_BINARY_RELATIVE = `current/${HOOK_BINARY_NAME}`;
|
|
14
|
+
var PROJECT_HOOK_BINARY_RELATIVE = `.ev-ai/agent-hook/${HOOK_BINARY_NAME}`;
|
|
15
|
+
var HOOK_INPUT_ALLOWLIST_MAX_BYTES = 4 * 1024;
|
|
16
|
+
var HOOK_INPUT_FULL_MAX_BYTES = 256 * 1024;
|
|
17
|
+
var HOOK_INPUT_MCP_MAX_BYTES = 4 * 1024;
|
|
18
|
+
var GZIP_MIN_BYTES = 32 * 1024;
|
|
19
|
+
var USER_SPEC_COOLDOWN_MS = 14 * 60 * 60 * 1e3;
|
|
20
|
+
var PACKAGE_VERSION = "1.2.0";
|
|
21
|
+
var NPX_PACKAGE_SPEC = `@ev-ai/agent-hook@${PACKAGE_VERSION}`;
|
|
22
|
+
var HOOK_STATUS_MESSAGE = "ev-ai runtime report";
|
|
23
|
+
|
|
24
|
+
// src/install.ts
|
|
25
|
+
function isSessionStartEvent(eventName) {
|
|
26
|
+
return eventName === "SessionStart" || eventName === "sessionStart";
|
|
27
|
+
}
|
|
28
|
+
function withoutPreferOffline(command) {
|
|
29
|
+
return command.replace(/\s+--prefer-offline\b/g, "");
|
|
30
|
+
}
|
|
31
|
+
function commandForEvent(eventName, command) {
|
|
32
|
+
return isSessionStartEvent(eventName) ? withoutPreferOffline(command) : command;
|
|
33
|
+
}
|
|
34
|
+
function npxHookCommand(packageSpec = NPX_PACKAGE_SPEC) {
|
|
35
|
+
return `npx -y --prefer-offline ${packageSpec}`;
|
|
36
|
+
}
|
|
37
|
+
function withRunnerFlag(command, runner) {
|
|
38
|
+
const stripped = command.replace(/\s+--runner(?:=|\s+)\S+/g, "").trimEnd();
|
|
39
|
+
return `${stripped} --runner ${runner}`;
|
|
40
|
+
}
|
|
41
|
+
var FLAG_VALUE = `(?:'[^']*'|"[^"]*"|\\S+)`;
|
|
42
|
+
function withUrlFlag(command, collectorUrl) {
|
|
43
|
+
const stripped = command.replace(new RegExp(`\\s+--url(?:=|\\s+)${FLAG_VALUE}`, "g"), "").replace(new RegExp(`\\s+--token(?:=|\\s+)${FLAG_VALUE}`, "g"), "").replace(new RegExp(`\\s+--base-url(?:=|\\s+)${FLAG_VALUE}`, "g"), "").trimEnd();
|
|
44
|
+
const quoted = collectorUrl.replace(/'/g, `'\\''`);
|
|
45
|
+
return `${stripped} --url '${quoted}'`;
|
|
46
|
+
}
|
|
47
|
+
function toCommandList(command) {
|
|
48
|
+
return typeof command === "string" ? [command] : command;
|
|
49
|
+
}
|
|
50
|
+
function desiredClaudeHookGroups(command) {
|
|
51
|
+
const commandHook = (eventName = "") => ({
|
|
52
|
+
hooks: toCommandList(command).map((entry) => ({
|
|
53
|
+
type: "command",
|
|
54
|
+
command: commandForEvent(eventName, entry)
|
|
55
|
+
}))
|
|
56
|
+
});
|
|
57
|
+
return {
|
|
58
|
+
SessionStart: [commandHook("SessionStart")],
|
|
59
|
+
// Slash skills bypass PreToolUse(Skill); UserPromptExpansion is the observable path.
|
|
60
|
+
UserPromptExpansion: [commandHook()],
|
|
61
|
+
// Prompt bodies (non-slash included). Slash skill ids still come from Expansion.
|
|
62
|
+
UserPromptSubmit: [commandHook()],
|
|
63
|
+
// All tools (replaces prior Skill-only matcher on reinstall).
|
|
64
|
+
PreToolUse: [commandHook()],
|
|
65
|
+
PostToolUse: [commandHook()],
|
|
66
|
+
PostToolUseFailure: [commandHook()],
|
|
67
|
+
// Denied-before-run tools never fire PostToolUseFailure.
|
|
68
|
+
PermissionDenied: [commandHook()],
|
|
69
|
+
Stop: [commandHook()],
|
|
70
|
+
// Turn ended due to API error (rate_limit / overloaded / …).
|
|
71
|
+
StopFailure: [commandHook()],
|
|
72
|
+
SessionEnd: [commandHook()],
|
|
73
|
+
SubagentStart: [commandHook()],
|
|
74
|
+
SubagentStop: [commandHook()]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function desiredCodexHookGroups(command) {
|
|
78
|
+
const spec = typeof command === "string" ? { command } : command;
|
|
79
|
+
const commandHook = (eventName = "") => ({
|
|
80
|
+
hooks: [
|
|
81
|
+
{
|
|
82
|
+
type: "command",
|
|
83
|
+
command: commandForEvent(eventName, spec.command),
|
|
84
|
+
...spec.commandWindows === void 0 ? {} : { commandWindows: commandForEvent(eventName, spec.commandWindows) },
|
|
85
|
+
statusMessage: HOOK_STATUS_MESSAGE
|
|
86
|
+
}
|
|
87
|
+
]
|
|
88
|
+
});
|
|
89
|
+
return {
|
|
90
|
+
SessionStart: [commandHook("SessionStart")],
|
|
91
|
+
// Slash / custom-prompt skill ids from prompt text (body never POSTed on allowlist).
|
|
92
|
+
UserPromptSubmit: [commandHook()],
|
|
93
|
+
PreToolUse: [commandHook()],
|
|
94
|
+
PostToolUse: [commandHook()],
|
|
95
|
+
Stop: [commandHook()]
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
var CURSOR_WIRED_HOOK_EVENTS = [
|
|
99
|
+
"sessionStart",
|
|
100
|
+
"beforeSubmitPrompt",
|
|
101
|
+
"preToolUse",
|
|
102
|
+
"postToolUse",
|
|
103
|
+
"postToolUseFailure",
|
|
104
|
+
"beforeShellExecution",
|
|
105
|
+
"beforeReadFile",
|
|
106
|
+
"beforeMCPExecution",
|
|
107
|
+
"subagentStart",
|
|
108
|
+
"subagentStop",
|
|
109
|
+
"stop"
|
|
110
|
+
];
|
|
111
|
+
|
|
112
|
+
// src/plugin-hooks.ts
|
|
113
|
+
var PLUGIN_HOOK_PAYLOAD = "hook.mjs";
|
|
114
|
+
var PLUGIN_CHECKSUMS_FILE = HOOK_CHECKSUMS_FILE;
|
|
115
|
+
function buildClaudePluginHooks(command) {
|
|
116
|
+
return { hooks: desiredClaudeHookGroups(command) };
|
|
117
|
+
}
|
|
118
|
+
function buildCursorPluginHooks(command) {
|
|
119
|
+
const hooks = {};
|
|
120
|
+
for (const eventName of CURSOR_WIRED_HOOK_EVENTS) {
|
|
121
|
+
hooks[eventName] = toCommandList(command).map((entry) => ({
|
|
122
|
+
command: commandForEvent(eventName, entry)
|
|
123
|
+
}));
|
|
124
|
+
}
|
|
125
|
+
return { hooks };
|
|
126
|
+
}
|
|
127
|
+
function buildCodexPluginHooks(command) {
|
|
128
|
+
return { hooks: desiredCodexHookGroups(command) };
|
|
129
|
+
}
|
|
130
|
+
var PLUGIN_PAYLOAD_FILES = [
|
|
131
|
+
{ source: "dist/hook.mjs", target: PLUGIN_HOOK_PAYLOAD, executable: false },
|
|
132
|
+
{
|
|
133
|
+
source: `compile-out/bin/${PLUGIN_CHECKSUMS_FILE}`,
|
|
134
|
+
target: PLUGIN_CHECKSUMS_FILE,
|
|
135
|
+
executable: false,
|
|
136
|
+
optional: true
|
|
137
|
+
}
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
// src/managed-hooks-snippet.ts
|
|
141
|
+
function managedHooksSnippet(runner, collectorUrl) {
|
|
142
|
+
const command = withUrlFlag(withRunnerFlag(npxHookCommand(), runner), collectorUrl);
|
|
143
|
+
const doc = runner === "cursor" ? { version: 1, ...buildCursorPluginHooks(command) } : runner === "claude" ? buildClaudePluginHooks(command) : buildCodexPluginHooks(command);
|
|
144
|
+
return JSON.stringify(doc, null, 2);
|
|
145
|
+
}
|
|
146
|
+
export {
|
|
147
|
+
buildCollectorUrl,
|
|
148
|
+
managedHooksSnippet
|
|
149
|
+
};
|
package/dist/plugin-hooks.mjs
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import { chmodSync, copyFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
|
|
5
|
+
// src/collector-url-resolve.ts
|
|
6
|
+
var MAX_JSON_FILE_BYTES = 1024 * 1024;
|
|
7
|
+
|
|
5
8
|
// src/constants.ts
|
|
6
9
|
var HOOK_BINARY_NAME = "ev-ai-agent-hook";
|
|
7
10
|
var HOOK_CHECKSUMS_FILE = "SHA256SUMS";
|
|
@@ -12,20 +15,32 @@ var HOOK_INPUT_FULL_MAX_BYTES = 256 * 1024;
|
|
|
12
15
|
var HOOK_INPUT_MCP_MAX_BYTES = 4 * 1024;
|
|
13
16
|
var GZIP_MIN_BYTES = 32 * 1024;
|
|
14
17
|
var USER_SPEC_COOLDOWN_MS = 14 * 60 * 60 * 1e3;
|
|
15
|
-
var PACKAGE_VERSION = "1.
|
|
18
|
+
var PACKAGE_VERSION = "1.2.0";
|
|
16
19
|
var NPX_PACKAGE_SPEC = `@ev-ai/agent-hook@${PACKAGE_VERSION}`;
|
|
17
20
|
var HOOK_STATUS_MESSAGE = "ev-ai runtime report";
|
|
18
21
|
|
|
19
22
|
// src/install.ts
|
|
23
|
+
function isSessionStartEvent(eventName) {
|
|
24
|
+
return eventName === "SessionStart" || eventName === "sessionStart";
|
|
25
|
+
}
|
|
26
|
+
function withoutPreferOffline(command) {
|
|
27
|
+
return command.replace(/\s+--prefer-offline\b/g, "");
|
|
28
|
+
}
|
|
29
|
+
function commandForEvent(eventName, command) {
|
|
30
|
+
return isSessionStartEvent(eventName) ? withoutPreferOffline(command) : command;
|
|
31
|
+
}
|
|
20
32
|
function toCommandList(command) {
|
|
21
33
|
return typeof command === "string" ? [command] : command;
|
|
22
34
|
}
|
|
23
35
|
function desiredClaudeHookGroups(command) {
|
|
24
|
-
const commandHook = () => ({
|
|
25
|
-
hooks: toCommandList(command).map((entry) => ({
|
|
36
|
+
const commandHook = (eventName = "") => ({
|
|
37
|
+
hooks: toCommandList(command).map((entry) => ({
|
|
38
|
+
type: "command",
|
|
39
|
+
command: commandForEvent(eventName, entry)
|
|
40
|
+
}))
|
|
26
41
|
});
|
|
27
42
|
return {
|
|
28
|
-
SessionStart: [commandHook()],
|
|
43
|
+
SessionStart: [commandHook("SessionStart")],
|
|
29
44
|
// Slash skills bypass PreToolUse(Skill); UserPromptExpansion is the observable path.
|
|
30
45
|
UserPromptExpansion: [commandHook()],
|
|
31
46
|
// Prompt bodies (non-slash included). Slash skill ids still come from Expansion.
|
|
@@ -46,15 +61,18 @@ function desiredClaudeHookGroups(command) {
|
|
|
46
61
|
}
|
|
47
62
|
function desiredCodexHookGroups(command) {
|
|
48
63
|
const spec = typeof command === "string" ? { command } : command;
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
const commandHook = (eventName = "") => ({
|
|
65
|
+
hooks: [
|
|
66
|
+
{
|
|
67
|
+
type: "command",
|
|
68
|
+
command: commandForEvent(eventName, spec.command),
|
|
69
|
+
...spec.commandWindows === void 0 ? {} : { commandWindows: commandForEvent(eventName, spec.commandWindows) },
|
|
70
|
+
statusMessage: HOOK_STATUS_MESSAGE
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
});
|
|
56
74
|
return {
|
|
57
|
-
SessionStart: [commandHook()],
|
|
75
|
+
SessionStart: [commandHook("SessionStart")],
|
|
58
76
|
// Slash / custom-prompt skill ids from prompt text (body never POSTed on allowlist).
|
|
59
77
|
UserPromptSubmit: [commandHook()],
|
|
60
78
|
PreToolUse: [commandHook()],
|
|
@@ -77,8 +95,6 @@ var CURSOR_WIRED_HOOK_EVENTS = [
|
|
|
77
95
|
];
|
|
78
96
|
|
|
79
97
|
// src/plugin-hooks.ts
|
|
80
|
-
var PLUGIN_LAUNCHER_SH = "launcher.sh";
|
|
81
|
-
var PLUGIN_LAUNCHER_PS1 = "launcher.ps1";
|
|
82
98
|
var PLUGIN_HOOK_PAYLOAD = "hook.mjs";
|
|
83
99
|
var PLUGIN_VERSION_FILE = "version";
|
|
84
100
|
var PLUGIN_CHECKSUMS_FILE = HOOK_CHECKSUMS_FILE;
|
|
@@ -88,18 +104,18 @@ var PLUGIN_ROOT_VARIABLE = {
|
|
|
88
104
|
codex: "PLUGIN_ROOT"
|
|
89
105
|
};
|
|
90
106
|
function pluginLauncherPosixCommand(runner) {
|
|
91
|
-
return `"\${${PLUGIN_ROOT_VARIABLE[runner]}}/${
|
|
107
|
+
return `node "\${${PLUGIN_ROOT_VARIABLE[runner]}}/${PLUGIN_HOOK_PAYLOAD}" --runner ${runner} ; exit 0`;
|
|
92
108
|
}
|
|
93
109
|
function pluginLauncherPowerShellCommand(runner) {
|
|
94
110
|
const variable = PLUGIN_ROOT_VARIABLE[runner];
|
|
95
|
-
return `powershell -NoProfile -NonInteractive -Command "
|
|
111
|
+
return `powershell -NoProfile -NonInteractive -Command "node (Join-Path (Get-Item Env:${variable}).Value '${PLUGIN_HOOK_PAYLOAD}') --runner ${runner}" ; exit 0`;
|
|
96
112
|
}
|
|
97
113
|
function pluginLauncherCommands(runner) {
|
|
98
114
|
return [pluginLauncherPosixCommand(runner), pluginLauncherPowerShellCommand(runner)];
|
|
99
115
|
}
|
|
100
116
|
function pluginLauncherCodexCommand() {
|
|
101
117
|
return {
|
|
102
|
-
command: `sh -c '"\${PLUGIN_ROOT}/${
|
|
118
|
+
command: `sh -c 'node "\${PLUGIN_ROOT}/${PLUGIN_HOOK_PAYLOAD}" --runner codex; exit 0'`,
|
|
103
119
|
commandWindows: pluginLauncherPowerShellCommand("codex")
|
|
104
120
|
};
|
|
105
121
|
}
|
|
@@ -107,10 +123,11 @@ function buildClaudePluginHooks(command) {
|
|
|
107
123
|
return { hooks: desiredClaudeHookGroups(command) };
|
|
108
124
|
}
|
|
109
125
|
function buildCursorPluginHooks(command) {
|
|
110
|
-
const commands = typeof command === "string" ? [command] : command;
|
|
111
126
|
const hooks = {};
|
|
112
127
|
for (const eventName of CURSOR_WIRED_HOOK_EVENTS) {
|
|
113
|
-
hooks[eventName] =
|
|
128
|
+
hooks[eventName] = toCommandList(command).map((entry) => ({
|
|
129
|
+
command: commandForEvent(eventName, entry)
|
|
130
|
+
}));
|
|
114
131
|
}
|
|
115
132
|
return { hooks };
|
|
116
133
|
}
|
|
@@ -133,8 +150,6 @@ function marketplacePluginHookPaths(marketplaceRoot) {
|
|
|
133
150
|
}
|
|
134
151
|
var PLUGIN_PAYLOAD_FILES = [
|
|
135
152
|
{ source: "dist/hook.mjs", target: PLUGIN_HOOK_PAYLOAD, executable: false },
|
|
136
|
-
{ source: `scripts/${PLUGIN_LAUNCHER_SH}`, target: PLUGIN_LAUNCHER_SH, executable: true },
|
|
137
|
-
{ source: `scripts/${PLUGIN_LAUNCHER_PS1}`, target: PLUGIN_LAUNCHER_PS1, executable: false },
|
|
138
153
|
{
|
|
139
154
|
source: `compile-out/bin/${PLUGIN_CHECKSUMS_FILE}`,
|
|
140
155
|
target: PLUGIN_CHECKSUMS_FILE,
|
|
@@ -144,8 +159,6 @@ var PLUGIN_PAYLOAD_FILES = [
|
|
|
144
159
|
];
|
|
145
160
|
var PLUGIN_REQUIRED_PAYLOAD_TARGETS = [
|
|
146
161
|
PLUGIN_HOOK_PAYLOAD,
|
|
147
|
-
PLUGIN_LAUNCHER_SH,
|
|
148
|
-
PLUGIN_LAUNCHER_PS1,
|
|
149
162
|
PLUGIN_VERSION_FILE
|
|
150
163
|
];
|
|
151
164
|
function writeJson(path, value) {
|
|
@@ -202,8 +215,6 @@ export {
|
|
|
202
215
|
MARKETPLACE_PLUGIN_NAME,
|
|
203
216
|
PLUGIN_CHECKSUMS_FILE,
|
|
204
217
|
PLUGIN_HOOK_PAYLOAD,
|
|
205
|
-
PLUGIN_LAUNCHER_PS1,
|
|
206
|
-
PLUGIN_LAUNCHER_SH,
|
|
207
218
|
PLUGIN_PAYLOAD_FILES,
|
|
208
219
|
PLUGIN_REQUIRED_PAYLOAD_TARGETS,
|
|
209
220
|
PLUGIN_ROOT_VARIABLE,
|