cc-safety-net 2.3.2 → 2.3.3
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/amp/cc-safety-net/index.ts +9 -9
- package/dist/api.js +1 -1
- package/dist/bin/cc-safety-net.js +105 -81
- package/dist/chunks/{index-jnb1nckj.js → index-ebfx04sr.js} +2 -2
- package/dist/chunks/{index-6fvz7zfr.js → index-tm5km50k.js} +8 -8
- package/dist/index.js +1 -1
- package/dist/openclaw/cc-safety-net/index.js +9 -9
- package/dist/openclaw/cc-safety-net/openclaw.plugin.json +1 -1
- package/dist/openclaw/cc-safety-net/package.json +1 -1
- package/dist/pi/index.js +1 -1
- package/package.json +2 -2
|
@@ -1,44 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as mi,c as gi,d as V,e as hi,f as br,g as ct,h as He,i as Mr,j as be,k as Rs,l as Kr,m as vn,n as Ps,o as Ds,p as bn}from"../chunks/index-
|
|
2
|
+
import{b as mi,c as gi,d as V,e as hi,f as br,g as ct,h as He,i as Mr,j as be,k as Rs,l as Kr,m as vn,n as Ps,o as Ds,p as bn}from"../chunks/index-ebfx04sr.js";import{$a as _r,A as it,Aa as Es,Ab as Ot,B as he,Ba as ye,Bb as _s,C as ja,Ca as Nt,D as Zi,Da as Vr,E as Pe,Ea as zr,F as yn,Fa as as,G as Pt,Ga as ls,H as xr,Ha as ki,I as je,Ia as st,J as Se,Ja as cs,K as Ne,Ka as ds,L as re,La as Ar,M as Cr,Ma as Er,Na as Xi,O as oe,Oa as Rr,P as se,Pa as ge,Qa as Qi,R as ie,Ra as Gi,S as It,Sa as Bi,T as Nd,Ta as iu,U as Ae,Ua as Ci,V as U,Va as Si,W as Re,Wa as Ee,Xa as Ri,Y as we,Ya as Ge,Z,Za as Pi,_ as Ms,_a as q,aa as Me,ab as Fr,ba as Ln,bb as jr,ca as Ut,cb as J,da as Ei,db as su,ea as _i,eb as ve,fa as $t,fb as au,ga as Ue,gb as cn,ha as Ur,hb as lu,ia as Ti,ib as cu,ja as Ii,jb as du,ka as Le,kb as Be,la as As,lb as Y,ma as Jr,mb as uu,na as Ts,nb as pu,oa as Is,ob as us,pa as Gr,pb as ps,qa as rs,qb as fs,ra as Li,rb as ms,s as Mt,sa as os,sb as Dt,t as ns,ta as is,tb as De,u as H,ua as ss,ub as W,v as Rt,va as Br,vb as es,w as x,wa as wi,wb as Dr,x as St,xa as $i,xb as _t,y as w,ya as S,yb as z,z as B,za as qr,zb as Ht}from"../chunks/index-tm5km50k.js";var Lu=["-h","--help"];function E(e,t){let n=Object.entries(e.booleans??{}),r=Object.entries(e.values??{}),o=Object.entries(e.lists??{}),i=Object.fromEntries(n.map(([g])=>[g,!1])),s={},a=Object.fromEntries(o.map(([g])=>[g,[]])),l=[],c=[],d=!1,m=-1;for(let[g,u]of t.entries()){if(g<=m)continue;if(u==="--"){l.push(...t.slice(g+1));break}if(Lu.includes(u)){d=!0;continue}let p=n.find(([,L])=>L.includes(u));if(p){i[p[0]]=!0;continue}let f=r.find(([,L])=>L.includes(u));if(f){let L=t[g+1];if(L===void 0||L.startsWith("-")){c.push(`${u} requires a value`);continue}s[f[0]]=L,m=g+1;continue}let b=o.find(([,L])=>L.includes(u));if(b){let L=t.slice(g+1),h=L.findIndex((v)=>v.startsWith("-")),R=L.slice(0,h===-1?L.length:h);if(R.length===0){c.push(`${u} requires at least one value`);continue}a[b[0]]=[...a[b[0]]??[],...R],m=g+R.length;continue}if(u.startsWith("-")){c.push(`Unknown option for ${e.label}: ${u}`);continue}if(e.positionals==="tail"){l.push(...t.slice(g));break}l.push(u)}if(e.positionals!=="list"&&e.positionals!=="tail")c.push(...l.map((g)=>`Unexpected argument for ${e.label}: ${g}`));return{flags:i,values:s,lists:a,positionals:l,help:d,errors:c}}function fe(e){for(let t of e)console.error(t);return e.length>0}import{readdirSync as wp,statSync as vs,unlinkSync as kp}from"node:fs";import{basename as bs,dirname as xp,isAbsolute as Cp,join as Sp,relative as Rp,resolve as Pp,sep as Dp}from"node:path";function F(e){return Array.from(e,(t)=>{let n=t.charCodeAt(0);if(n<=31||n>=127&&n<=159)return`\\x${n.toString(16).padStart(2,"0")}`;return t}).join("")}var gr=(e)=>{let t=Date.now()-new Date(e).getTime();if(!Number.isFinite(t))return"";let n=Math.floor(t/60000),r=Math.floor(n/60),o=Math.floor(r/24);if(o>0)return`${o}d ago`;if(r>0)return`${r}h ago`;if(n>0)return`${n}m ago`;return"just now"},rt=(e)=>{let t=(e??"").trim().split(/\s+/).filter((o)=>o&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(o)),n=t[0]?.split("/").pop();if(!n)return null;let r=t[1];return r&&/^[a-z][a-z0-9-]*$/.test(r)?`${n} ${r}`:n};import{existsSync as wu,readdirSync as ku,readFileSync as xu}from"node:fs";import{join as Cu}from"node:path";function Ce(e,t){try{return ku(e,{withFileTypes:!0,encoding:"utf8"}).flatMap((n)=>{let r=Cu(e,n.name);if(n.isDirectory())return Ce(r,t);if(n.name.endsWith(".jsonl"))return[r];return[]})}catch{if(t&&wu(e))t.count++;return[]}}function hr(e){let t=(o)=>`${o.sessionId}
|
|
3
3
|
${rt(o.segment||o.command)}`,n=e.filter((o)=>o.decision!=="allow"),r=n.filter((o)=>o.sessionId).reduce((o,i)=>o.set(t(i),(o.get(t(i))??0)+1),new Map);return new Set(n.filter((o)=>o.failureStage||(r.get(t(o))??0)>=2))}var Su=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Ru(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e;if(typeof t.ts!=="string"||typeof t.command!=="string")return!1;return Su.every((n)=>t[n]===void 0||typeof t[n]==="string")}function Fe(e,t){try{return xu(e,"utf-8").split(`
|
|
4
4
|
`).filter(Boolean).flatMap((n)=>{try{let r=JSON.parse(n);if(!Ru(r)){if(t)t.count++;return[]}return[r]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as up}from"node:path";var Pu=["AKIA","ASIA","ghp_","gho_","ghu_","ghs_","ghr_","github_pat_","glpat-","xox","npm_","pypi-","rk_","sk-","sk_","gsk_","xai-","pplx-","bastn_","tgp_v1_","flp_","wfr_","fw_","fwp_","tp-","psk-"];function yi(e){let t=0,n={allocateSegment(){return t++},getNextSegmentIndex(){return t},recordGlobal(r){e.record({kind:"step",scope:"global",step:r})},recordSegment(r,o=n.currentSegmentIndex){if(o===void 0)return;e.record({kind:"step",scope:"segment",segmentIndex:o,step:r})}};return n}function vi(e={}){let t=[],n=e.maxEvents??512,r={maxTextLength:e.maxTextLength??2048,maxListLength:e.maxListLength??128,maxObjectProperties:e.maxObjectProperties??e.maxListLength??128,maxDepth:e.maxDepth??16},o=0,i,s=new Set;return{record(a){if(i)return;try{if(!a||t.length>=n){o++;return}t.push(vr(Du(a,r,s)))}catch{o++}},finish(a){if(i)return i;try{i=vr({events:Object.freeze(t),droppedEvents:o,terminal:Au(a,r,s)})}catch{o++,i=Object.freeze({events:Object.freeze(t),droppedEvents:o,terminal:Object.freeze({result:"blocked",reason:"trace unavailable".slice(0,r.maxTextLength),segment:"trace unavailable".slice(0,r.maxTextLength)})})}return i}}}function Du(e,t,n){if(e.kind!=="step")throw TypeError("invalid trace event");let{scope:r,step:o}=e;pn(o,n,t);let i=ot(o,t,n);if(r==="global")return{kind:"step",scope:"global",step:i};if(r!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:e.segmentIndex,step:i}}function Au(e,t,n){let r=e.result;if(r==="allowed")return Object.freeze({result:"allowed"});if(r!=="blocked")throw TypeError("invalid trace terminal");let o=e.ruleId;return Object.freeze({result:"blocked",reason:ot(e.reason,t,n),segment:ot(e.segment,t,n),...o?{ruleId:ot(o,t,n)}:{}})}function pn(e,t,n,r=0,o=new WeakSet){if(typeof e==="string"){let a=e.slice(0,n.maxTextLength);if(!br(a))return;for(let l of hi(a))for(let c of l.match(/[^\s"'()$]+/g)??[])t.add(bi(c));return}if(!e||typeof e!=="object"||r>=n.maxDepth||o.has(e))return;if(o.add(e),Array.isArray(e)){let a=Math.min(e.length,n.maxListLength);for(let l=0;l<a;l++)pn(e[l],t,n,r+1,o);return}let i=0,s=new Set;for(let a in e){if(!Object.hasOwn(e,a))continue;if(i>=n.maxObjectProperties)break;i++,pn(a,t,n);let l=yr(a,n,t);if(s.has(l))continue;s.add(l),pn(e[a],t,n,r+1,o)}}function ot(e,t,n,r=0,o=new WeakSet){if(typeof e==="string")return yr(e,t,n);if(!e||typeof e!=="object")return e;if(r>=t.maxDepth)return;if(o.has(e))return;if(o.add(e),Array.isArray(e)){let a=[],l=Math.min(e.length,t.maxListLength);for(let c=0;c<l;c++)a.push(ot(e[c],t,n,r+1,o));return a}let i={},s=0;for(let a in e){if(!Object.hasOwn(e,a))continue;if(s>=t.maxObjectProperties)break;s++;let l=yr(a,t,n);if(Object.hasOwn(i,l))continue;Object.defineProperty(i,l,{value:ot(e[a],t,n,r+1,o),enumerable:!0,configurable:!0,writable:!0})}return i}function yr(e,t,n){let r=e.slice(0,t.maxTextLength),o=br(r)?gi(r):r,i=n.size>0?_u(o,n):o;return(Eu(i)?mi(i):i).slice(0,t.maxTextLength)}function Eu(e){return e.includes("PRIVATE KEY")||e.includes("://")||e.includes("eyJ")||e.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(e)||e.length>=14&&Pu.some((t)=>e.includes(t))||e.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(e)}function _u(e,t){return e.replace(/[^\s"'()$]+/g,(n)=>t.has(bi(n))?"<redacted>":n)}function bi(e){let t=2166136261,n=2166136261;for(let r=0;r<e.length;r++)t=Math.imul(t^e.charCodeAt(r),16777619),n=Math.imul(n^e.charCodeAt(e.length-r-1),16777619);return`${t>>>0}:${n>>>0}:${e.length}`}function vr(e){if(e&&typeof e==="object"&&!Object.isFrozen(e)){for(let t of Object.values(e))vr(t);Object.freeze(e)}return e}function xi(e,t,n){let r=n??Li(),o=r.getCommandProgram(e,t.shell??"auto"),i=vi(),s=yi(i),a=o.dialect==="powershell"?r.getCommandProgram(e,"posix"):o,l=wi(a);s.recordGlobal({type:"parse",input:e,segments:l.map((m)=>[...m])});let c=ki(e,{...t,analyzePartialProgram:!0,trace:s},o,r),d=s.getNextSegmentIndex();if(c&&d>0&&d<l.length)s.recordSegment({type:"segment-skipped",index:d,reason:"prior-segment-blocked"},d);return Object.freeze({decision:c,trace:i.finish(c?{result:"blocked",reason:c.reason,segment:c.evidence.find((m)=>m.kind==="command")?.segment??e,...c.ruleId?{ruleId:c.ruleId}:{}}:{result:"allowed"})})}import{resolve as Tu}from"node:path";function Lr(e){let t=Ci().safeParse(e);return{errors:t.success?[]:Ri(t.error.issues),ruleNames:new Set(Si(e).map((n)=>n.toLowerCase()))}}function wr(e){let t=Di(e);if(!t.ok)return t.result;return Lr(t.parsed)}function Di(e){let t=[],n=new Set;try{let r=typeof e==="string"?St(e):e,o=w(r);if(o===null)return t.push(`File not found: ${r.path}`),{ok:!1,result:{errors:t,ruleNames:n}};if(!o.trim())return t.push("Config file is empty"),{ok:!1,result:{errors:t,ruleNames:n}};return{ok:!0,parsed:JSON.parse(o)}}catch(r){if(r instanceof H)return t.push(r.message),{ok:!1,result:{errors:t,ruleNames:n}};let o=r instanceof Error?r.message:String(r);return t.push(r instanceof SyntaxError?"Invalid JSON":o),{ok:!1,result:{errors:t,ruleNames:n}}}}function Ai(e){return Tu(e??process.cwd(),".safety-net.json")}function me(e){let t=Di(e);if(!t.ok)return t.result;let n=Pi(t.parsed);return{errors:n.errors,ruleNames:n.sources}}import{join as Tr,resolve as qu}from"node:path";import{dirname as mn}from"node:path";var Iu="custom.";function fn(e){if(e.rulebook_version!==2)return[];let t=e.rules.map((n)=>({name:n.name,command:n.command,block_args:[],match:n.match,reason:n.reason,intent:n.intent}));return(e.tests??[]).flatMap((n,r)=>{let o=kr(Ii(n.command));if(o.length===0)return[`tests[${r}]: could not parse fixture command: ${n.command}`];let i=o.reduce((s,a)=>s??$i(a,t)?.id.slice(Iu.length),void 0);if(n.expect==="blocked"){if(i===n.rule)return[];let s=i?`"${i}" matched first`:"no rule matched";return[`tests[${r}]: expected "${n.rule}" to block "${n.command}" but ${s}`]}return i?[`tests[${r}]: expected "${n.command}" to be allowed but "${i}" matched`]:[]})}function kr(e){return e.nodes.flatMap((t)=>{if(t.kind==="group"||t.kind==="function")return kr(t.body);if(t.kind!=="command")return[];let n=Ti(_i(t.dialect,t.words)).words.map(Ei);return[...n.length>0?[n]:[],...t.nested.flatMap((r)=>kr(r))]})}var $u=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function Oi(e,t){let n=Ni(e.rules,t);if(n.length>0)return{ok:!0,specs:n};return ji(e.rules,t)}function Fi(e,t){let n=Ni(e,t);if(n.length>0)return{ok:!0,specs:n};let r=Fu(e,t);if(r.length>0)return{ok:!0,specs:r};let o=ju(e,t);if(!o.ok)return o;if(o.specs.length>0)return{ok:!0,specs:o.specs};return ji(e,t)}function ji(e,t){let n=e.filter((r)=>Sr(r)?.name===t);if(n.length===1)return{ok:!0,specs:n};return Ou(t,n)}function Ou(e,t){return{ok:!1,result:{ok:!1,errors:t.length===0?[`No configured rulebook matches ${e}`]:[`Ambiguous rulebook match ${e}: ${t.join(", ")}`],entries:[]}}}function Ni(e,t){return e.filter((n)=>n===t)}function Fu(e,t){let n=t.match($u),r=n?.[1],o=n?.[2],i=n?.[3];if(!r||!o||!i||!Ne(i))return[];return Hi(e,(s)=>s.owner===r&&s.repo===o&&s.ref===i)}function ju(e,t){if(!Se(t))return{ok:!0,specs:[]};let[n,r]=t.split("/"),o=Hi(e,(s)=>s.owner===n&&s.repo===r);if(new Set(o.map((s)=>Sr(s)?.ref).filter((s)=>!!s)).size<2)return{ok:!0,specs:o};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${t}. Use an explicit ref:`,` cc-safety-net rule remove ${t}#<ref>`],entries:[]}}}function Sr(e){try{return je(e)}catch{return null}}function Hi(e,t){return e.filter((n)=>{let r=Sr(n);return r?t(r):!1})}var qi=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Mi(e,t,n=Rt(mn(mn(t)),"rules policy"),r=ge()){if(re(e))return Uu(e,r);return Mu(e,t,n)}async function Vi(e,t,n,r,o,i){if(!re(e))return Mi(e,t,n,r);let s=o?null:Nu(e,t,n);if(s)return s;if(!o&&!i)throw Error(`${e} is not vendored; run rule update ${e} to vendor it`);return Mi(e,t,n,r)}function Nu(e,t,n=Rt(mn(mn(t)),"rules policy")){let r=je(e),o=Re(t,r.name),i=w(x(n,o));if(i===null)return null;let s=Dt(Pr(i,`Invalid rulebook ${o}.`));if(s.name!==r.name)throw Error(`rulebook name "${s.name}" in ${o} must match "${r.name}"`);return{spec:e,rulebook:s,content:i}}async function zi(e,t={}){if(!Se(e))throw Error(`Invalid GitHub repository source: ${e}`);let[n,r]=e.split("/");if(!n||!r)throw Error(`Invalid GitHub repository source: ${e}`);if(t.ref!==void 0&&!Ne(t.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${t.ref}`);let o=t.operation??ge(),i=t.ref??await Hu(n,r,e,o),s=await Ji(n,r,i,e,o),a=await gn(`https://api.github.com/repos/${n}/${r}/git/trees/${s}?recursive=1`,"tree",o),l=a.response;if(!l.ok)throw Error(`Failed to inspect ${e}: GitHub tree returned ${l.status}`);let c=JSON.parse(a.content);if(!Array.isArray(c?.tree))throw Error(`Failed to inspect ${e}: unexpected GitHub tree response`);let d=c.tree,m=[...new Set(d.flatMap((g)=>{if(!g||typeof g!=="object")return[];let u=g;if(u.type!=="blob"||typeof u.path!=="string")return[];let p=u.path.match(xr);return p?.[1]?[p[1]]:[]}))].sort();if(m.length===0)throw Error(`No rulebooks found in ${e} under ${Pt}/`);return{source:e,owner:n,repo:r,ref:i,commit:s,names:m}}async function Hu(e,t,n,r){let o=await gn(`https://api.github.com/repos/${e}/${t}`,"metadata",r),i=o.response;if(!i.ok)throw Error(`Failed to inspect ${n}: GitHub returned ${i.status}`);let a=JSON.parse(o.content)?.default_branch;if(typeof a!=="string"||a==="")throw Error(`Failed to inspect ${n}: missing default branch`);if(!Ne(a))throw Error(`GitHub returned an invalid default branch: ${a}`);return a}function Mu(e,t,n){Cr(e);let r=Re(t,e),o=w(x(n,r));if(o===null)throw Error(`Rulebook source not found: ${e}`);let i=Ki(Pr(o,"Invalid local rulebook source."));if(i.name!==e)throw Error(`rulebook name "${i.name}" must match local source "${e}"`);return{spec:e,rulebook:i,content:o}}async function Uu(e,t){let n=je(e),r=await Ji(n.owner,n.repo,n.ref,e,t),o=await gn(`https://raw.githubusercontent.com/${n.owner}/${n.repo}/${r}/${n.path}`,"raw",t),i=o.response;if(!i.ok)throw Error(`Failed to fetch ${e}: GitHub raw returned ${i.status}`);let s=o.content,a=Ki(Pr(s,"Invalid GitHub rulebook response."));if(a.name!==n.name)throw Error(`rulebook name "${a.name}" must match GitHub source "${n.name}"`);return{spec:e,rulebook:a,content:s}}function Ki(e){let t=Dt(e),n=fn(t);if(n.length>0)throw Error(n.join("; "));return t}function Pr(e,t){try{return JSON.parse(e)}catch{throw Error(t)}}async function Ji(e,t,n,r,o){let i=await gn(`https://api.github.com/repos/${e}/${t}/commits/${encodeURIComponent(n)}`,"commit",o),s=i.response;if(!s.ok)throw Error(`Failed to resolve ${r}: GitHub returned ${s.status}`);let a=JSON.parse(i.content);if(typeof a?.sha!=="string"||a.sha==="")throw Error(`Failed to resolve commit for ${r}`);return a.sha}async function Gu(e,t,n={}){if(n.signal?.aborted)throw n.signal.reason;let r=n.budget??Rr(),o=new AbortController,i=()=>o.abort(n.signal?.reason);n.signal?.addEventListener("abort",i,{once:!0});let s=!1,a=setTimeout(()=>{if(o.signal.aborted)return;s=!0,o.abort()},n.timeoutMs??qi.timeoutMs);try{if(n.signal?.aborted)throw n.signal.reason;Gi(r);let l=await(n.fetch??fetch)(e,{signal:o.signal,redirect:"error"});if(!l.ok)return Wi(l),{response:l,content:""};return{response:l,content:await Bu(l,t,r,()=>o.abort())}}catch(l){if(s)throw Error("GitHub request timed out",{cause:l});if(n.signal?.aborted)throw n.signal.reason;throw l}finally{clearTimeout(a),n.signal?.removeEventListener("abort",i)}}function gn(e,t,n){return Gu(n.resolveUrl?.(e)??e,t,{budget:n.budget,signal:n.controller.signal})}async function Bu(e,t,n=Rr(),r){let o=qi[`${t}Bytes`],i=Number(e.headers.get("content-length"));if(Number.isFinite(i)&&i>o)throw Wi(e),Error(`GitHub ${t} response exceeds ${o} bytes`);if(!e.body)return"";let s=e.body.getReader(),a=[],l=0;while(!0){let c=await s.read();if(c.done)break;try{Bi(n,c.value.byteLength)}catch(d){throw r?.(),Ui(s),d}if(l+=c.value.byteLength,l>o)throw r?.(),Ui(s),Error(`GitHub ${t} response exceeds ${o} bytes`);a.push(Buffer.from(c.value))}return Buffer.concat(a,l).toString("utf-8")}function Wi(e){if(!e.body)return;Yi(()=>e.body?.cancel())}function Ui(e){Yi(()=>e.cancel())}function Yi(e){try{Promise.resolve(e()).catch(()=>{})}catch{}}async function Tt(e={}){let t=$r(e);return Vu(t,await hn(t,ge()))}function Vu(e,t){if(!t.ok)return t;let n=U(e),r=[...new Set(W(n.configPath,n.filesystemScope))];if(r.length===0)return t;return{ok:!1,errors:r,entries:t.entries}}async function hn(e,t,n={},r=new Set,o=new Set){try{let i=U(e),s=_r(i.configTarget);if(!s.ok)return s.result;let a=s.config;if(e.check)return ap(a,i,e);let l=e.only?Oi(a,e.only):{ok:!0,specs:a.rules};if(!l.ok)return l.result;let c=new Set([...e.refresh?l.specs:[],...r]),d=(v)=>Vi(v,i.configDir,i.filesystemScope,t,c.has(v),!e.refresh||c.has(v)),m=await np(a.rules,e.refresh?(v)=>d(v).then((P)=>({ok:!0,item:P})).catch((P)=>{if(Qi(P))throw P;return{ok:!1,spec:v,message:P instanceof Error?P.message:String(P)}}):async(v)=>({ok:!0,item:await d(v)}),t),g=m.filter((v)=>!v.ok),u=m.filter((v)=>v.ok).map((v)=>v.item),p=u.flatMap((v)=>zu(v,a.rules)),f=u.flatMap((v)=>Ku(v,o,i)),b=new Set([...p,...f].map((v)=>v.spec)),L=[...g,...p,...f],h=[],R=Wu(h,()=>u.flatMap((v)=>b.has(v.spec)||L.length>0&&o.has(v.spec)?[]:Ju(v,i,n,h)));return{ok:L.length===0,errors:L.map((v)=>`Failed to update ${v.spec}: ${v.message}`),entries:u.map(Zu),changes:R}}catch(i){return Et(i)}}function zu(e,t){if(!re(e.spec))return[];let n=Dr(e.spec),r=t.filter((o)=>o!==e.spec&&Dr(o).toLowerCase()===n.toLowerCase());if(r.length===0)return[];return[{ok:!1,spec:e.spec,message:`rulebook name "${n}" is also claimed by ${r.join(", ")}; rename one of them`}]}function Ku(e,t,n){if(!t.has(e.spec)||!re(e.spec))return[];let r=Re(n.configDir,e.rulebook.name),o=w(x(n.filesystemScope,r));if(o===null||o===e.content)return[];return[{ok:!1,spec:e.spec,message:`${r} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Ju(e,t,n,r){if(!re(e.spec))return[];let o=Re(t.configDir,e.rulebook.name),i=x(t.filesystemScope,o),s=w(i);if(s===e.content)return[];return r?.push({target:i,previous:s}),B(i,e.content,void 0,n._testAfterPolicyRename),Yu(e,s)}function Wu(e,t){try{return t()}catch(n){for(let r of[...e].reverse()){if(r.previous===null){he(r.target);continue}B(r.target,r.previous)}throw n}}function Yu(e,t){if(t===null)return[`Vendored ${e.spec} (${e.rulebook.version})`];let n=_t(t),r="problem"in n?null:n.rulebook,o=new Map(r?.rules.map((s)=>[s.name,JSON.stringify(s)])??[]),i=new Set(e.rulebook.rules.map((s)=>s.name));return[`Updated ${e.spec} (${r?.version??"unreadable"} -> ${e.rulebook.version})`,...[...i].filter((s)=>!o.has(s)).map((s)=>` + ${s}`),...[...o.keys()].filter((s)=>!i.has(s)).map((s)=>` - ${s}`),...e.rulebook.rules.filter((s)=>{let a=o.get(s.name);return a!==void 0&&a!==JSON.stringify(s)}).map((s)=>` ~ ${s.name}`)]}function Zu(e){return{spec:e.spec,name:e.rulebook.name,version:e.rulebook.version,ruleCount:e.rulebook.rules.length}}async function Ir(e,t={}){return Xu(e,op(t),ge())}async function Xu(e,t,n,r={}){let o=null,i=!1;try{let s=U(t),a=w(s.configTarget);o={target:s.configTarget,content:a};let l=_r(s.configTarget);if(!l.ok)return l.result;let c=l.config,d=Se(e);Qu(e,t,d);let m=d?await zi(e,{ref:t.ref,operation:n}):null,g=m?ep(m,t.rulebooks):[],u=m?g.map((h)=>tp(c.rules,m,h)??`${e}#${m.ref}/${h}`):[e],p=u.filter((h)=>!c.rules.includes(h)),f=[...c.rules,...p];if(f.length>Ar)return rp();if(f.length!==c.rules.length)i=!0,J(s.configTarget,{version:1,rules:f,overrides:c.overrides??{},transparent_wrappers:c.transparent_wrappers??[]},void 0,r._testAfterPolicyRename);let b=await hn(t,n,r,new Set(p),new Set(p));if(!b.ok)At(s.configTarget,a);if(!b.ok||!m)return b;let L=g.filter((h,R)=>p.includes(u[R]??""));return{...b,add:{source:e,ref:m.ref,selected:g,added:L,alreadyConfigured:g.filter((h)=>!L.includes(h)),commits:p.length>0?[m.commit]:[]}}}catch(s){if(i&&o)try{At(o.target,o.content)}catch(a){return Et(a)}return Et(s)}}function Qu(e,t,n){if(!n&&t.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!n&&t.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${e}`);if(t.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let r=t.rulebooks?.filter((o)=>!Pe.test(o))??[];if(r.length>0)throw Error(`Invalid rulebook names: ${r.join(", ")}`)}function ep(e,t){let n=t?[...new Set(t)]:e.names,r=n.filter((o)=>!e.names.includes(o));if(r.length>0)throw Error(`Rulebooks not found in ${e.source} at ${e.ref}: ${r.join(", ")}
|
|
5
|
-
Available rulebooks: ${e.names.join(", ")}`);return n}function tp(e,t,n){let r=`${t.source}#${t.ref}/${n}`;if(e.includes(r))return r;let o=`${t.source}#${t.commit}/${n}`;return e.find((i)=>i===o)}async function np(e,t,n=ge()){if(e.length>Ar)throw Error(Er);let r=Array(e.length),o=0,i,s=Array.from({length:Math.min(e.length,Xi.concurrency)},async()=>{while(!i){let a=o;if(a>=e.length)return;o++;try{r[a]=await t(e[a],a,n.controller.signal)}catch(l){if(!i)i={value:l},o=e.length,n.controller.abort(l);return}}});if(await Promise.all(s),i)throw i.value;return r}function rp(){return{ok:!1,errors:[Er],entries:[]}}function $r(e){return{cwd:e.cwd,userConfigDir:e.userConfigDir,userConfigPath:e.userConfigPath,projectConfigPath:e.projectConfigPath,global:e.global,check:e.check,only:e.only,refresh:e.refresh}}function op(e){return{...$r(e),ref:e.ref,rulebooks:e.rulebooks}}function ip(e){return{...$r(e),deleteSource:e.deleteSource}}async function Or(e,t={}){try{return await sp(e,ip(t),{})}catch(n){return Et(n)}}async function sp(e,t,n){let r=U(t),o=q(r.configTarget);if(o.errors.length>0)return{ok:!1,errors:o.errors,entries:[]};if(!o.config)return{ok:!1,errors:[`No config found at ${r.configPath}`],entries:[]};let i=Fi(o.config.rules,e);if(!i.ok)return i.result;let s=t.deleteSource?lp(r.configDir,i.specs,r.filesystemScope):{ok:!0,dirs:[]};if(!s.ok)return s.result;let a=w(r.configTarget);if(a===null)return Et(Error("Rules config is unavailable."));try{J(r.configTarget,{version:1,rules:o.config.rules.filter((d)=>!i.specs.includes(d)),overrides:o.config.overrides??{},transparent_wrappers:o.config.transparent_wrappers??[]},void 0,n._testAfterPolicyRename)}catch(d){throw At(r.configTarget,a),d}let l=await hn(t,ge(),n);if(!l.ok)return At(r.configTarget,a),l;let c=cp(s.dirs,n,r.filesystemScope);if(!c.ok){At(r.configTarget,a);let d=await hn(t,ge(),n);if(!d.ok)return{ok:!1,errors:[...c.result.errors,...d.errors],entries:d.entries};return c.result}return l}async function ap(e,t,n){let r=es(e,t.configDir,n.global?"user":"project",t.filesystemScope);return{ok:r.errors.length===0&&r.warnings.length===0,errors:[...r.errors,...r.warnings],entries:r.entries}}function lp(e,t,n){let r=t.flatMap((a)=>Pe.test(a)?[]:["--delete-source can only delete local rulebook sources"]),o=t.map((a)=>Tr(e,a)),i=r.length>0?[]:o.flatMap((a)=>ts(a,n)),s=[...r,...i];return s.length>0?{ok:!1,result:{ok:!1,errors:s,entries:[]}}:{ok:!0,dirs:o}}function ts(e,t){let n=qu(e),r=x(t,n),o=it(r);if(!o)return[`Local rulebook source directory not found: ${e}`];let i=o.find((s)=>s.name==="rulebook.json");if(!i)return[`Local rulebook source directory is missing rulebook.json: ${e}`];if(i.kind!=="file")throw new H(t.label);if(w(x(t,Tr(n,"rulebook.json"))),o.length>1)return[`Local rulebook source directory contains extra files: ${e}. delete manually if you really want to remove the directory.`];return[]}function cp(e,t,n){let r=e.flatMap((o)=>{try{if(!it(x(n,o)))return[];let i=ts(o,n);if(i.length>0)return i;return dp(o,t,n),[]}catch(i){return[`Failed to delete local rulebook source ${o}: ${i instanceof Error?i.message:String(i)}`]}});return r.length>0?{ok:!1,result:{ok:!1,errors:r,entries:[]}}:{ok:!0}}function dp(e,t,n){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(e);return}he(x(n,Tr(e,yn))),Zi(x(n,e))}function At(e,t){if(t===null){he(e);return}B(e,t)}function Et(e){return{ok:!1,errors:[e instanceof Error?e.message:String(e)],entries:[]}}function at(e,t){let n=fp(t),r=as(n),o={effectiveLevel:r.effectiveLevel,selectedPreset:n.policySnapshot.policy.safety.level??"standard",...n.policySnapshot.policyScopes?{safetyPresetScope:n.policySnapshot.policyScopes.levelScope}:{},effectiveCapabilities:r.effectiveCapabilities,destructiveCommandRuleOverrides:n.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:i,configValid:s}=pp({cwd:t?.cwd,userConfigDir:t?.userConfigDir});if(!e||!e.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:i,configValid:s,...o};let a=mp(e,n);if(a)return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:a.rule,matched:!0,reason:a.reason}]}]},result:"blocked",reason:V(a.reason),segment:V(a.target),...a.ruleId?{ruleId:V(a.ruleId)}:{},configSource:i,configValid:s,...o};let l=xi(e,n),c=l.decision,d=c?.ruleId??gp(e,n),m=$t.find((u)=>u.id===d&&u.activationCapability),g=m?r.policy.effectiveDestructiveCommandRules[m.id]:void 0;return{trace:yp(l.trace),result:c?"blocked":"allowed",reason:c?V(c.reason):void 0,segment:c?V(c.evidence.find((u)=>u.kind==="command")?.segment??e):void 0,ruleId:c?.ruleId?V(c.ruleId):void 0,customRule:hp(vp(c?.ruleId,n.policySnapshot)),configSource:i,configValid:s,...o,...m&&g?{ruleActivation:{id:m.id,...g}}:{}}}function pp(e){let t=oe(e?.cwd),n=e?.userConfigPath??ie(e),r=Ae({cwd:e?.cwd,userConfigDir:e?.userConfigDir,userConfigPath:e?.userConfigPath});try{if(w(r.projectConfigTarget)!==null){if(me(r.projectConfigTarget).errors.length===0)return{configSource:t,configValid:!0};return{configSource:t,configValid:!1}}}catch(o){if(o instanceof H)return{configSource:t,configValid:!1};throw o}try{if(w(r.userConfigTarget)!==null){let o=me(r.userConfigTarget);return{configSource:n,configValid:o.errors.length===0}}return{configSource:null,configValid:!0}}catch(o){if(o instanceof H)return{configSource:n,configValid:!1};throw o}}function fp(e){let t=up(e?.cwd??process.cwd()),n=e?.policySnapshot??z({cwd:t,userConfigDir:e?.userConfigDir}),r=ye(n.policy);return{cwd:t,effectiveCwd:t,policySnapshot:n,environment:ns(),protectedGitMetadata:ss([t]),effectiveCapabilities:r.capabilities,strict:e?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function mp(e,t){let n=t.cwd??process.cwd(),r=rs(st("",{command:e},{kind:"command",shell:"posix"},{executionCwd:n,configCwd:n},e)),o=ps(r);if(o)return{reason:us,target:o.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let i=ds(r);if(i)return{reason:cs,target:i.target,ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};let s=is(r,t.protectedGitMetadata);if(s)return{reason:os,target:s.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let a=t.policySnapshot.policy,l=a.secretProtection.enabled===!1?null:ms(r,a.secretProtection,{strict:t.strict});if(l)return{reason:fs,target:l.target,ruleId:l.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function gp(e,t){let n=t.policySnapshot.policy,r=Ot({...n,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...n.destructiveCommandRuleOverrides,...Object.fromEntries($t.flatMap((o)=>o.activationCapability?[[o.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return ls(e,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function hp(e){if(!e)return;return{id:V(e.id),...e.rulebook?{rulebook:{name:V(e.rulebook.name),version:V(e.rulebook.version)}}:{},...e.source?{source:V(e.source)}:{},...e.override?{override:{type:"reason",reason:V(e.override.reason)}}:{}}}function yp(e){let t=e.events.flatMap((r)=>r.kind==="step"&&r.scope==="global"?[r.step]:[]),n=new Map;for(let r of e.events){if(r.kind!=="step"||r.scope!=="segment")continue;let o=n.get(r.segmentIndex)??{index:r.segmentIndex,steps:[]};o.steps.push(r.step),n.set(r.segmentIndex,o)}return{steps:t,segments:[...n.values()]}}function vp(e,t){let n=e?.replace(/^custom\./,"");if(!n||!t.policy.rules.some((r)=>r.name===n))return;return t.ruleMetadata[n]??Object.freeze({id:n})}import{existsSync as hs,readFileSync as bp}from"node:fs";function gs(e,t){return{"safety.level":e.safety.level,...Nr("safety.overrides",e.safety.overrides),"workflow.worktree_mode":String(e.workflow.worktree_mode),"destructive_command_protection.enabled":String(e.destructive_command_protection.enabled),...Nr("destructive_command_protection.overrides",e.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":Hr(e.destructive_command_protection.allow_paths),"secret_protection.enabled":String(e.secret_protection.enabled),...Nr("secret_protection.overrides",e.secret_protection.overrides),"secret_protection.deny_paths":Hr(e.secret_protection.deny_paths),"secret_protection.allow_paths":Hr(e.secret_protection.allow_paths),...t?{"audit.retention_days":String(e.audit.retention_days)}:{}}}function Ft(e,t,n){let r=gs(e,n),o=gs(t,n);return[...new Set([...Object.keys(r),...Object.keys(o)])].flatMap((i)=>r[i]===o[i]?[]:[{field:i,before:r[i],after:o[i]}])}function lt(e){let t=ve(e);if(!hs(t))return{baseline:Y(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__),diagnostics:[]};let n=_e(t);return{baseline:Y(n.value),diagnostics:n.errors.length>0?n.errors:Ee(n.value)}}function _e(e){if(!hs(e))return{errors:[`${e}: file not found`]};try{return{value:JSON.parse(bp(e,"utf-8")),errors:[]}}catch(t){let n=t instanceof Error?t.message:String(t);return{errors:[`${e}: ${t instanceof SyntaxError?`Invalid JSON: ${n}`:n}`]}}}function jt(e,t){let n=Lp(e)?e:{};return{version:t.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((r)=>n[r]!==void 0).map((r)=>[r,n[r]]))}}function Nr(e,t){return Object.fromEntries(Object.entries(t).flatMap(([n,r])=>r===void 0?[]:[[`${e}.${n}`,String(r)]]))}function Hr(e){return e.length===0?"(none)":e.join(", ")}function Lp(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Rp(e){let t=ct(),n=E({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},e);if(fe(n.errors))return null;if(n.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(n.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let r=n.values.limit===void 0?20:ys(n.values.limit);if(r===null)return console.error("--limit must be a positive number"),null;let o=n.values.since===void 0?Math.min(30,t):ys(n.values.since);if(o===null||o>t)return console.error(`--since must be a positive number of days no greater than ${t}`),null;let i={limit:r,limitExplicit:n.values.limit!==void 0,since:o,sinceExplicit:n.values.since!==void 0,all:n.flags.all,json:n.flags.json,suspect:n.flags.suspect,pruneLegacy:n.flags.pruneLegacy,dryRun:n.flags.dryRun,id:n.values.id,agent:n.values.agent,rule:n.values.rule,session:n.values.session,project:n.values.project===void 0?void 0:Sp(n.values.project)};if(i.id&&(i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.sinceExplicit||i.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(i.pruneLegacy&&(i.id!==void 0||i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.all||i.sinceExplicit||i.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(i.dryRun&&!i.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return i}async function Ls(e,t={}){let n=Rp(e);if(!n)return 1;let r=t.logsDir??be();if(n.pruneLegacy)return Pp(r,n.json,n.dryRun);if(!r)return console.log(n.json?"[]":n.id?`No retained audit log entry found for id ${F(n.id)}.`:"No audit log entries found."),0;He(r);let o={count:0},i=Ce(r,o).flatMap((d)=>Fe(d,o).map((m)=>({entry:m,file:d})));if(o.count>0)console.error(`warning: ${o.count} audit log ${o.count===1?"source":"sources"} could not be read; these results are incomplete`);if(n.id)return _p(i,n,t.timeZone);let s=Date.now()-n.since*24*60*60*1000,a=i.filter((d)=>Tp(d,n,r,s)),l=n.suspect?hr(a.map((d)=>d.entry)):null,c=(l?a.filter((d)=>l.has(d.entry)):a).sort((d,m)=>Date.parse(m.entry.ts)-Date.parse(d.entry.ts)).slice(0,n.limit);if(n.json)return console.log(JSON.stringify(c.map((d)=>d.entry),null,2)),0;if(c.length===0)return console.log("No audit log entries found."),0;for(let d of c)console.log(Op(d.entry,t.timeZone));return 0}function Pp(e,t,n){let r=e?Ap(e).map((a)=>Cp(e,a)):[];if(n)return Dp(r,t);let o=[],i=0,s=0;for(let a of r){let l=vs(a,{throwIfNoEntry:!1})?.size??0,c=Ep(a);if(c){o.push(`${bs(a)}: ${c}`);continue}i++,s+=l}if(t)return console.log(JSON.stringify({removedFiles:i,removedBytes:s,failedFiles:o.length})),o.length===0?0:1;console.log(i===0&&o.length===0?"No legacy audit log files found.":`Removed ${i} legacy audit log ${i===1?"file":"files"} (${ws(s)}).`);for(let a of o)console.error(`Could not remove ${F(a)}`);if(console.log("Nested v2 audit logs were not changed."),i>0)console.log("This deletion cannot be undone.");return o.length===0?0:1}function Dp(e,t){let n=e.reduce((r,o)=>r+(vs(o,{throwIfNoEntry:!1})?.size??0),0);if(t)return console.log(JSON.stringify({dryRun:!0,files:e.length,bytes:n})),0;if(console.log(e.length===0?"No legacy audit log files found.":`Would remove ${e.length} legacy audit log ${e.length===1?"file":"files"} (${ws(n)}).`),console.log("Nested v2 audit logs are not included."),e.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Ap(e){try{return wp(e,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function Ep(e){try{return kp(e),null}catch(t){return t instanceof Error?t.message:String(t)}}function ws(e){let t=["B","KiB","MiB","GiB"],n=Math.min(Math.floor(Math.log2(Math.max(e,1))/10),t.length-1);return`${Math.round(e/1024**n*10)/10} ${t[n]}`}function _p(e,t,n){let r=e.filter((i)=>i.entry.id===t.id);if(r.length>1)return console.error(`Multiple audit log entries found for id ${F(t.id??"")}.`),1;if(t.json)return console.log(JSON.stringify(r.map((i)=>i.entry),null,2)),0;let o=r[0];if(!o)return console.log(`No retained audit log entry found for id ${F(t.id??"")}.`),0;return console.log(Fp(o.entry,n)),0}function Tp(e,t,n,r){if(!t.all&&e.entry.decision==="allow")return!1;if(Date.parse(e.entry.ts)<r)return!1;if(t.agent!==void 0&&e.entry.agent!==t.agent)return!1;if(t.rule!==void 0&&e.entry.ruleId!==t.rule)return!1;if(t.session!==void 0&&!Ip(e,n,t.session))return!1;if(t.project!==void 0&&!$p(e.entry.cwd,t.project))return!1;return!0}function Ip(e,t,n){if(e.entry.sessionId===n)return!0;return xp(e.file)===t&&bs(e.file,".jsonl")===n}function $p(e,t){if(!e)return!1;return e===t||e.startsWith(`${t}/`)}function Op(e,t){let n=F(e.id??"-"),r=F(e.decision??"deny"),o=e.cwd?` [${F(e.cwd)}]`:"",i=e.segment||e.command,s=i===e.command?"":"↳ ",a=i.length>50?`${i.slice(0,50)}…`:i;return`${n.padEnd(16)} ${F(ks(e.ts,t))} ${r.padEnd(5)} ${F(e.agent??"-").padEnd(15)} ${F(e.ruleId??"-").padEnd(20)} ${s}${F(a)}${o}`}function Fp(e,t){let n=(o)=>F(o===void 0||o===null||o===""?"-":o),r=e.shape?`${e.agent??"-"} (shape: ${e.shape})`:e.agent??"-";return[`id: ${n(e.id)}`,`ts: ${n(ks(e.ts,t))}`,`decision: ${n(e.decision)}`,`agent: ${n(r)}`,`level: ${n(e.level)}`,`tool: ${n(e.toolName)}`,`rule: ${n(e.ruleId)}`,`intent: ${n(e.intent)}`,`stage: ${n(e.failureStage)}`,`error: ${n(e.errorCode)}`,`session: ${n(e.sessionId)}`,`cwd: ${n(e.cwd)}`,`version: ${n(e.v)}`,`truncated: ${n(e.truncated===!0?"yes":void 0)}`,`reason: ${n(e.reason)}`,`command: ${n(e.command)}`,`segment: ${n(e.segment)}`].join(`
|
|
6
|
-
`)}function ks(e,t){let n=new Date(e);if(Number.isNaN(n.getTime()))return e;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:t}).format(n)}function ys(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:null}var xs={name:"doctor",aliases:["--doctor"],description:"Run diagnostic checks to verify installation and configuration",usage:"doctor [options]",options:[{flags:"--json",description:"Output diagnostics as JSON"},{flags:"--skip-update-check",description:"Skip npm registry version check"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net doctor","cc-safety-net doctor --json","cc-safety-net doctor --skip-update-check"]};var Cs={name:"explain",description:"Show step-by-step analysis trace of how a command would be analyzed",usage:"explain [options] <command>",argument:"<command>",options:[{flags:"--json",description:"Output analysis as JSON"},{flags:"--cwd",argument:"<path>",description:"Use custom working directory"},{flags:"-h, --help",description:"Show this help"}],examples:['cc-safety-net explain "git reset --hard"','cc-safety-net explain --json "rm -rf /"','cc-safety-net explain --cwd /tmp "git status"']};var Ss={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};import{isAbsolute as $s,join as Kp,relative as Jp}from"node:path";var jp=8388608;function Np(e,t){console.log(JSON.stringify(e(Ps(t))))}async function Hp(e){let t;try{t=(await Wr(process.stdin)).trim()}catch{e({reason:"Failed to parse hook input JSON."});return}if(!t){e({reason:"Missing hook input JSON."});return}return Yr(t,e,"Failed to parse hook input JSON.")}async function Wr(e){let t=[],n=0;for await(let r of e){let o=typeof r==="string"?Buffer.from(r,"utf-8"):Buffer.from(r.buffer,r.byteOffset,r.byteLength);if(n+=o.byteLength,n>jp)throw Mp(e),Error("hook input byte limit exceeded");t.push(o)}return Buffer.concat(t,n).toString("utf-8")}function Mp(e){let t=e.destroy??e.cancel;if(!t)return;try{Promise.resolve(t.call(e)).catch(()=>{})}catch{}}function Yr(e,t,n){try{return JSON.parse(e)}catch{t({reason:n});return}}function j(e,t){let n=t.get(e);return n?{kind:"command",shell:n}:{kind:As(e)}}function ae(e,t,n,r){let o=e===void 0?process.cwd():e,i=typeof o==="string"&&o.trim()!==""?Z([o]):void 0;if(i)return{configCwd:i,executionCwd:i};return T(r,t,n,qp(o)),null}function T(e,t,n,r){let o;try{o=Jr(t)}catch(i){if(!(i instanceof Le))throw i}e(vn({command:o,segment:r,toolName:n}))}async function Up(e){let t=await Hp(e.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){T(e.outputDeny);return}if(!e.isSupported(t))return;let n=e.getAgent?.(t)??e.agent,r=e.agent===n?void 0:e.agent,o=zp(t),i=(u,p)=>{Rs(u,()=>e.getSessionId(t),{agent:n,shape:r,toolName:p,cwd:o}),e.outputDeny(u)},s=e.getToolName(t);if(typeof s!=="string"||s.trim()===""){T((u)=>i(u),Vp(t));return}let a=s,l=(u)=>i(u,a),c;try{c=e.getToolInput(t,a,l)}catch(u){if(!(u instanceof Le))throw u;T(l,void 0,a);return}if(!c.ok)return;let d=e.getContext(t,c.input,a,l);if(!d)return;let m;try{m=Jr(c.input)}catch(u){if(!(u instanceof Le))throw u;T(l,void 0,a);return}let g=st(a,c.input,c.route,d,m??null);try{let u=bn(g,{guard:{auditAllowed:Es(),dependencies:e.guardDependencies},audit:{agent:n,shape:r,getSessionId:()=>e.getSessionId(t)}}),p=Kr(u,{includeEvidence:!0,toolName:u.stage==="command-analysis"?void 0:a});if(p){e.outputDeny(p);return}e.outputAllow?.()}catch(u){if(!(u instanceof _s))throw u;Gp(u);let p=Kr(u.evaluation,{includeEvidence:!0,toolName:u.evaluation.stage==="command-analysis"?void 0:a});if(p)e.outputDeny(p);return}}function Gp(e){if(!Nt(S.debug))return;console.error(`CC Safety Net debug: ${Bp(e.stage)}: ${Ds(e.cause)}`)}function Bp(e){if(e==="policy-protection")return"hook policy protection failed";if(e==="config-load")return"hook config loading failed";if(e==="secret-protection")return"hook secret protection failed";return"hook analysis failed"}function qp(e){return typeof e==="string"?e:void 0}function Vp(e){if(!e||typeof e!=="object"||Array.isArray(e))return;if(Object.hasOwn(e,"tool_input"))return e.tool_input;let t=e.toolCall;if(t&&typeof t==="object"&&!Array.isArray(t))return t.args;return}function zp(e){if(!e||typeof e!=="object"||Array.isArray(e))return null;let t=e.cwd;if(typeof t==="string")return t;let n=e.toolCall;if(!n||typeof n!=="object"||Array.isArray(n))return null;let r=n.args;if(!r||typeof r!=="object"||Array.isArray(r))return null;let o=r.Cwd;return typeof o==="string"?o:null}async function N(e){let t=(o)=>Np(e.createDenyOutput,o),n=e.createAllowOutput;await Up({...e,outputDeny:t,outputAllow:n?()=>console.log(JSON.stringify(n())):void 0})}function Gt(e){return Kp(e,".gemini","config","hooks.json")}var Wp=new Map([["run_command","auto"]]),Yp=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function Os(e){return j(e,Wp)}async function Fs(){await N({agent:"antigravity-cli",createDenyOutput:(e)=>({decision:"deny",reason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolCall?.name,getToolInput:(e,t)=>({ok:!0,input:t2(e.toolCall?.args,t),route:Os(t)}),getContext:Zp,getSessionId:(e)=>e.conversationId})}function Zp(e,t,n,r){let i=e2(e).flatMap((c)=>{let d=Z([c]);return d?[d]:[]});if(!i[0])return qe(r,t,n),null;if(n!=="run_command"){let c;try{c=Xp(t,n,i)}catch(d){if(d instanceof Le)return qe(r,void 0,n),null;if(!(d instanceof Me))throw d;return qe(r,t,n),null}if(!c)return qe(r,t,n),null;return{configCwd:c,executionCwd:c}}let s=e.toolCall?.args;if(!s||!Object.hasOwn(s,"Cwd"))return{configCwd:i[0],executionCwd:i[0]};let a=s.Cwd;if(typeof a!=="string"||a.trim()==="")return qe(r,t,n),null;let l=we(a,i);if(l){let c=js(l,i);if(!c)return qe(r,t,n,a),null;return{configCwd:c,executionCwd:l}}return qe(r,t,n,a),null}function Xp(e,t,n){let r=Os(t),o=[...Ts(e,Yp),...r.kind==="patch"?Is(e):[]].filter($s),i=Ln(),s=new Set(o.flatMap((a)=>{let l=js(Ut(a,Mt,i),n);return l?[l]:[]}));if(s.size>1)return null;return[...s][0]??n[0]??null}function js(e,t){return t.filter((n)=>Qp(e,n)).reduce((n,r)=>r.length>n.length?r:n,"")||null}function Qp(e,t){let n=Jp(t,e);return n===""||!n.startsWith("..")&&!$s(n)}function qe(e,t,n,r){let o=t&&typeof t==="object"?t.command:void 0;e(vn({command:typeof o==="string"?o:void 0,segment:r,toolName:n}))}function e2(e){if(e.workspacePaths===void 0)return[process.cwd()];let t=Array.isArray(e.workspacePaths)?e.workspacePaths.filter((n)=>typeof n==="string"&&n.trim()!==""):[];return Z(t)?t:[]}function t2(e,t){if(!e)return;if(t!=="run_command")return e;return{...e,command:typeof e.CommandLine==="string"&&e.CommandLine!==""?e.CommandLine:void 0}}var Bt=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],wn=Bt.slice().sort((e,t)=>e.doctorOrder-t.doctorOrder).map((e)=>e.id),Ns=Bt.filter((e)=>("runtime"in e)).slice().sort((e,t)=>e.runtime.order-t.runtime.order).map((e)=>({id:e.id,displayName:"displayName"in e.runtime?e.runtime.displayName:e.displayName,flags:e.runtime.flags,legacyFlags:"legacyFlags"in e.runtime?e.runtime.legacyFlags:[],description:e.runtime.description,legacyTopLevelFlags:e.runtime.legacyTopLevelFlags})),X=Bt.slice().sort((e,t)=>e.install.order-t.install.order).map((e)=>({id:e.id,...e.install})).map(({order:e,...t})=>t),Yv=Object.fromEntries(Bt.map((e)=>[e.id,e.displayName]));function D(e){return Bt.find((t)=>t.id===e)?.displayName??e}import{homedir as n2}from"node:os";import{isAbsolute as Hs,join as Zr}from"node:path";function Us(e){if(e!==void 0&&e!==null&&typeof e!=="string")return"unknown";if(typeof e==="string"&&!Hs(e))return"unknown";try{let t=Ln(),n=typeof e==="string"&&e?Ut(e,Mt,t):void 0,r=process.env.HOME||n2(),o=[["codex",process.env.CODEX_HOME||Zr(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||Zr(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||Zr(r,".claude")]],i=n?o.flatMap(([s,a])=>{if(!Hs(a))return[];return Ms(n,Ut(a,Mt,t))?[s]:[]}):[];if(i.length===1)return i[0]??"unknown";if(i.length>1)return"unknown"}catch(t){if(t instanceof Me)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var Xr="PreToolUse",Gs="BeforeTool",Bs="pre_tool_call",Qr="PreToolUse";async function kn(e){await N({agent:e.agent,...e.getAgent?{getAgent:e.getAgent}:{},createDenyOutput:(t)=>({hookSpecificOutput:{hookEventName:Xr,permissionDecision:"deny",permissionDecisionReason:t}}),isSupported:(t)=>t.hook_event_name===Xr,getToolName:(t)=>t.tool_name,getToolInput:(t,n)=>({ok:!0,input:t.tool_input,route:e.getToolRoute(n)}),getContext:(t,n,r,o)=>ae(t.cwd,n,r,o),getSessionId:(t)=>t.session_id})}var r2=new Map([["Bash","posix"],["PowerShell","powershell"]]);function o2(e){return j(e,r2)}async function qs(){await kn({agent:"claude-code",getAgent:(e)=>Us(e.transcript_path),getToolRoute:o2})}var i2=new Map([["Bash","auto"]]);async function Vs(){await kn({agent:"codex",getToolRoute:(e)=>j(e,i2)})}var s2=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function a2(e){return j(e,s2)}async function zs(){await N({agent:"copilot-cli",createDenyOutput:(e)=>({permissionDecision:"deny",permissionDecisionReason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(typeof e.toolArgs!=="string")return n({reason:"Failed to parse toolArgs JSON."}),{ok:!1};let r=Yr(e.toolArgs,n,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:a2(t)}},getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>typeof e.sessionId==="string"&&e.sessionId.trim()?e.sessionId:void 0})}var l2=new Map([["Shell","auto"]]);function c2(e){return j(e,l2)}async function Ks(){await N({agent:"cursor",createDenyOutput:(e)=>({permission:"deny",user_message:e,agent_message:e}),createAllowOutput:()=>({permission:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:c2(t)}),getContext:d2,getSessionId:(e)=>e.conversation_id})}function d2(e,t,n,r){let o=u2(e);if(!o[0])return T(r,t,n),null;let i=we(f2(e.cwd),o);if(!i)return T(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;if(t===null||typeof t!=="object"||Array.isArray(t))return{configCwd:i,executionCwd:i};if(!Object.hasOwn(t,"working_directory"))return{configCwd:i,executionCwd:i};let s=t.working_directory;if(typeof s!=="string"||s.trim()==="")return T(r,t,n),null;let a=we(s,o);if(!a)return T(r,t,n,s),null;return{configCwd:i,executionCwd:a}}function u2(e){return p2(e).flatMap((t)=>{let n=Z([t]);return n?[n]:[]})}function p2(e){if(e.workspace_roots===void 0)return typeof e.cwd==="string"&&e.cwd.trim()!==""?[e.cwd]:[];if(!Array.isArray(e.workspace_roots))return[];return e.workspace_roots.filter((t)=>typeof t==="string"&&t.trim()!=="")}function f2(e){return typeof e==="string"&&e.trim()!==""?e:"."}var m2=new Map([["run_shell_command","auto"]]);function g2(e){return j(e,m2)}async function Js(){await N({agent:"gemini-cli",createDenyOutput:(e)=>({decision:"deny",reason:e,systemMessage:e}),isSupported:(e)=>e.hook_event_name===Gs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:g2(t)}),getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var h2=new Map([["run_terminal_command","auto"]]);function y2(e){return j(e,h2)}async function Ws(){await N({agent:"grok-build",createDenyOutput:(e)=>({decision:"deny",reason:e}),createAllowOutput:()=>({decision:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(e.toolInputTruncated===!0)return T(n,e.toolInput,t),{ok:!1};return{ok:!0,input:e.toolInput,route:y2(t)}},getContext:v2,getSessionId:(e)=>e.sessionId})}function v2(e,t,n,r){let o=Z(b2(e));if(!o)return T(r,t,n),null;let i=we(L2(e.cwd),[o]);if(!i)return T(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;return{configCwd:i,executionCwd:i}}function b2(e){let t=e.workspaceRoot===void 0?e.cwd:e.workspaceRoot;return typeof t==="string"&&t.trim()!==""?[t]:[]}function L2(e){return typeof e==="string"&&e.trim()!==""?e:"."}import{resolve as w2}from"node:path";var k2=new Map([["terminal","posix"]]);async function Ys(){await N({agent:"hermes-agent",createDenyOutput:(e)=>({action:"block",message:e}),isSupported:(e)=>e.hook_event_name===Bs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:j(t,k2)}),getContext:x2,getSessionId:(e)=>e.session_id})}function x2(e,t,n,r){let o=ae(e.cwd,t,n,r);if(!o)return null;if(!t||typeof t!=="object"||Array.isArray(t))return o;if(!Object.hasOwn(t,"workdir"))return o;let i=t.workdir;if(typeof i!=="string"||i.trim()==="")return T(r,t,n),null;let s=Z([w2(o.configCwd,i)]);if(!s)return T(r,t,n,i),null;return{...o,executionCwd:s}}var Zs=new Map([["Bash","posix"]]);function C2(e){return j(e,Zs)}async function Xs(){await N({agent:"kimi-code",createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Qr,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Qr,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:C2(t)}),getContext:(e,t,n,r)=>{let o=ae(e.cwd,t,n,r);if(!o)return null;let i=e.tool_input;if(!Zs.has(n)||!i||!Object.hasOwn(i,"cwd"))return o;let s=i.cwd;if(typeof s!=="string"||s.trim()==="")return T(r,t,n),null;let a=we(s,[o.configCwd]);if(!a)return T(r,t,n,s),null;return{configCwd:o.configCwd,executionCwd:a}},getSessionId:(e)=>e.session_id})}var S2={"antigravity-cli":Fs,"claude-code":qs,codex:Vs,"copilot-cli":zs,cursor:Ks,"gemini-cli":Js,"grok-build":Ws,"hermes-agent":Ys,"kimi-code":Xs},dt=Ns.map((e)=>({...e,run:S2[e.id]}));function Qs(e){let t=E({label:"hook",booleans:Object.fromEntries(dt.map((r)=>[r.id,[...r.flags,...r.legacyFlags]]))},e);if(t.errors.length>0)return;let n=dt.filter((r)=>t.flags[r.id]);return n.length===1?n[0]:void 0}function ea(e){return dt.find((t)=>t.legacyTopLevelFlags.some((n)=>n===e))}var R2=dt.map((e)=>({flags:e.flags.join(", "),description:e.description})),P2=dt.flatMap((e)=>e.flags.map((t)=>`cc-safety-net hook ${t}`)),ta={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...R2,{flags:"-h, --help",description:"Show this help"}],examples:P2};var na={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...X.map((e)=>({flags:e.flag,description:`Install ${D(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...X.map((e)=>`cc-safety-net install ${e.flag}`)]},ra={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...X.map((e)=>({flags:e.flag,description:`Uninstall ${D(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...X.map((e)=>`cc-safety-net uninstall ${e.flag}`)]},oa={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var ia={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],ut={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var sa={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var aa={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var Cn=[sa,xs,ia,Cs,ut,xn,na,oa,ra,ta,Ss,aa];function D2(e){return e.aliases??[]}function Sn(e){let t=e.toLowerCase();return Cn.find((n)=>n.name.toLowerCase()===t||D2(n).some((r)=>r.toLowerCase()===t))}import{basename as A2}from"node:path";function Rn(e=7,t=be()){let n=Date.now()-e*24*60*60*1000,r=[],o=new Set,i=0,s,a,l,c;if(t)He(t);let d={count:0},m=t?Ce(t,d):[];for(let u of m)for(let p of Fe(u,d)){if(p.decision==="allow")continue;let f=new Date(p.ts).getTime();if(f>=n){if(i++,o.add(p.sessionId??A2(u,".jsonl")),a===void 0||f<=a)s=p.ts,a=f;if(c===void 0||f>c)l=p.ts,c=f;E2(r,p,f)}}let g=r.map((u)=>({timestamp:u.ts,command:u.command,reason:u.reason,relativeTime:gr(new Date(u.ts))}));return{totalBlocked:i,sessionCount:o.size,recentEntries:g,oldestEntry:s,newestEntry:l,unreadable:d.count}}function E2(e,t,n){let r=e.findIndex((o)=>n>new Date(o.ts).getTime());if(r===-1){if(e.length<3)e.push(t);return}if(e.splice(r,0,t),e.length>3)e.pop()}import{dirname as _2}from"node:path";function la(e,t,n){let r;try{if(w(t)===null)return{path:e,exists:!1,valid:!1,ruleCount:0};r=me(t),r.errors.push(...W(e,n))}catch(o){if(!(o instanceof H))throw o;r={errors:[o.message],ruleNames:new Set}}return{path:e,exists:!0,valid:r.errors.length===0,ruleCount:r.ruleNames.size,...r.errors.length>0?{errors:r.errors}:{}}}function T2(e,t){return{source:t,name:e.name,command:e.command,subcommand:e.subcommand,blockArgs:[...e.block_args],reason:e.reason}}function ca(e,t){let n=t?.userConfigPath??ie(),r=t?.projectConfigPath??oe(e),o=_2(n),i=De({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),s=Ae({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),a=new Map(i.rulebooks.flatMap((l)=>l.rules.map((c)=>[c,l.source])));return{userConfig:la(n,s.userConfigTarget,s.userScope),projectConfig:la(r,s.projectConfigTarget,s.projectScope),effectiveRules:i.rules.map((l)=>T2(l,a.get(l.name)??"project")),shadowedRules:[]}}var I2=[{flag:S.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:S.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:S.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:S.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:S.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:S.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:S.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:S.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function da(){return[...I2.map((e)=>({name:e.flag.name,value:Vr(e.flag),isSet:zr(e.flag),legacyName:e.flag.legacyName,legacyValue:e.flag.legacyName?process.env[e.flag.legacyName]:void 0,legacyIsSet:e.flag.legacyName?process.env[e.flag.legacyName]!==void 0:void 0,description:e.description,defaultBehavior:e.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:process.env.CC_SAFETY_NET_HOME,isSet:process.env.CC_SAFETY_NET_HOME!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ua={error:0,warning:1,info:2},$2=["policy","config","audit"];function O2(e){return e.map((t)=>{if(t==="ownership")return"is not owned by the current user";if(t==="permissions")return"has unsafe permissions";if(t==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var F2=[{derive:(e)=>e.hooks.length>0&&e.hooks.every((t)=>!t.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(e)=>e.hooks.filter((t)=>t.inspectionStatus==="failed").map((t)=>{let n=D(t.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${n} inspection failed`,detail:`Doctor could not verify the ${n} integration configuration.`,fixHint:`Correct the reported ${n} configuration error, then run \`cc-safety-net doctor\` again.`,integration:t.platform}})},{derive:(e)=>e.userConfig.exists&&!e.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.userConfig.path}]:[]},{derive:(e)=>e.projectConfig.exists&&!e.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.projectConfig.path}]:[]},{derive:(e)=>e.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${e.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(e)=>e.v2Leftovers&&e.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${e.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(e)=>{let t=e.environment.find((n)=>n.name==="CC_SAFETY_NET_AUDIT_SCOPE");return qr(t?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...$2.map((e)=>({derive:(t)=>t.posture.directories.filter((n)=>n.kind===e&&n.status==="unsafe").map((n)=>({checkId:`posture.${e}-directory-unsafe`,severity:"error",title:`${e[0]?.toUpperCase()}${e.slice(1)} directory is unsafe`,detail:`The ${e} directory ${O2(n.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...n.path?{path:n.path}:{}}))})),{derive:(e)=>{let t=[...e.effectiveSafety.weakenedRuleOverrides].sort();return t.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${t.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${t.join(", ")}.`}]:[]}}];function pa(e){return F2.flatMap((t,n)=>t.derive(e).map((r,o)=>({finding:r,catalogOrder:n,occurrence:o}))).sort((t,n)=>ua[t.finding.severity]-ua[n.finding.severity]||t.catalogOrder-n.catalogOrder||t.occurrence-n.occurrence).map((t)=>t.finding)}function le(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var j2=(e)=>le()?`\x1B[32m${e}\x1B[0m`:e,N2=(e)=>le()?`\x1B[33m${e}\x1B[0m`:e,H2=(e)=>le()?`\x1B[34m${e}\x1B[0m`:e,M2=(e)=>le()?`\x1B[35m${e}\x1B[0m`:e,U2=(e)=>le()?`\x1B[36m${e}\x1B[0m`:e,G2=(e)=>le()?`\x1B[31m${e}\x1B[0m`:e,B2=(e)=>le()?`\x1B[2m${e}\x1B[0m`:e,q2=(e)=>le()?`\x1B[1m${e}\x1B[0m`:e,y={green:j2,yellow:N2,blue:H2,magenta:M2,cyan:U2,red:G2,dim:B2,bold:q2},V2="\x1B[0m",z2=[39,82,198,226,208,51,196,46,201,214,93,154,220,27,49,190,200,33,129,227,45,160,63,118,123,202];function K2(e){let t=e;return()=>(t=(t*1664525+1013904223)%4294967296,t/4294967296)}function J2(e){let t=[...z2],n=K2(e);for(let r=t.length-1;r>0;r--){let o=Math.floor(n()*(r+1)),i=t[r];t[r]=t[o],t[o]=i}return t}function W2(e,t=0){if(!le())return"";let n=J2(t);return`\x1B[38;5;${n[e%n.length]}m`}function fa(e,t,n=0){if(!le())return`"${e}"`;return`${W2(t,n)}"${e}"${V2}`}function Pn(e){return e==="default"?"built-in default":`${e} policy`}var Y2=new RegExp("\x1B\\[[0-9;]*m","g"),no=(e)=>e.replace(Y2,"").length;function Ve(e){let t=(e.headers??e.rows[0]??[]).map((s,a)=>{let l=Math.max(...e.rows.map((c)=>no(c[a]??"")));return Math.max(no(s),l)}),n=(s,a)=>s+" ".repeat(Math.max(0,a-no(s))),r=(s,a)=>a[0]+t.map((l)=>s.repeat(l+2)).join(a[1])+a[2],o=(s)=>`│ ${s.map((a,l)=>n(a,t[l]??0)).join(" │ ")} │`,i=e.headers?[` ${o(e.headers)}`,` ${r("─",["├","┼","┤"])}`]:[];return[` ${r("─",["┌","┬","┐"])}`,...i,...e.rows.map((s)=>` ${o(s)}`),` ${r("─",["└","┴","┘"])}`].join(`
|
|
7
|
-
`)}function ma(e){let t=[];t.push("Hook Integration"),t.push(
|
|
8
|
-
`)}function
|
|
9
|
-
`)}function
|
|
10
|
-
`)}function
|
|
5
|
+
Available rulebooks: ${e.names.join(", ")}`);return n}function tp(e,t,n){let r=`${t.source}#${t.ref}/${n}`;if(e.includes(r))return r;let o=`${t.source}#${t.commit}/${n}`;return e.find((i)=>i===o)}async function np(e,t,n=ge()){if(e.length>Ar)throw Error(Er);let r=Array(e.length),o=0,i,s=Array.from({length:Math.min(e.length,Xi.concurrency)},async()=>{while(!i){let a=o;if(a>=e.length)return;o++;try{r[a]=await t(e[a],a,n.controller.signal)}catch(l){if(!i)i={value:l},o=e.length,n.controller.abort(l);return}}});if(await Promise.all(s),i)throw i.value;return r}function rp(){return{ok:!1,errors:[Er],entries:[]}}function $r(e){return{cwd:e.cwd,userConfigDir:e.userConfigDir,userConfigPath:e.userConfigPath,projectConfigPath:e.projectConfigPath,global:e.global,check:e.check,only:e.only,refresh:e.refresh}}function op(e){return{...$r(e),ref:e.ref,rulebooks:e.rulebooks}}function ip(e){return{...$r(e),deleteSource:e.deleteSource}}async function Or(e,t={}){try{return await sp(e,ip(t),{})}catch(n){return Et(n)}}async function sp(e,t,n){let r=U(t),o=q(r.configTarget);if(o.errors.length>0)return{ok:!1,errors:o.errors,entries:[]};if(!o.config)return{ok:!1,errors:[`No config found at ${r.configPath}`],entries:[]};let i=Fi(o.config.rules,e);if(!i.ok)return i.result;let s=t.deleteSource?lp(r.configDir,i.specs,r.filesystemScope):{ok:!0,dirs:[]};if(!s.ok)return s.result;let a=w(r.configTarget);if(a===null)return Et(Error("Rules config is unavailable."));try{J(r.configTarget,{version:1,rules:o.config.rules.filter((d)=>!i.specs.includes(d)),overrides:o.config.overrides??{},transparent_wrappers:o.config.transparent_wrappers??[]},void 0,n._testAfterPolicyRename)}catch(d){throw At(r.configTarget,a),d}let l=await hn(t,ge(),n);if(!l.ok)return At(r.configTarget,a),l;let c=cp(s.dirs,n,r.filesystemScope);if(!c.ok){At(r.configTarget,a);let d=await hn(t,ge(),n);if(!d.ok)return{ok:!1,errors:[...c.result.errors,...d.errors],entries:d.entries};return c.result}return l}async function ap(e,t,n){let r=es(e,t.configDir,n.global?"user":"project",t.filesystemScope);return{ok:r.errors.length===0&&r.warnings.length===0,errors:[...r.errors,...r.warnings],entries:r.entries}}function lp(e,t,n){let r=t.flatMap((a)=>Pe.test(a)?[]:["--delete-source can only delete local rulebook sources"]),o=t.map((a)=>Tr(e,a)),i=r.length>0?[]:o.flatMap((a)=>ts(a,n)),s=[...r,...i];return s.length>0?{ok:!1,result:{ok:!1,errors:s,entries:[]}}:{ok:!0,dirs:o}}function ts(e,t){let n=qu(e),r=x(t,n),o=it(r);if(!o)return[`Local rulebook source directory not found: ${e}`];let i=o.find((s)=>s.name==="rulebook.json");if(!i)return[`Local rulebook source directory is missing rulebook.json: ${e}`];if(i.kind!=="file")throw new H(t.label);if(w(x(t,Tr(n,"rulebook.json"))),o.length>1)return[`Local rulebook source directory contains extra files: ${e}. delete manually if you really want to remove the directory.`];return[]}function cp(e,t,n){let r=e.flatMap((o)=>{try{if(!it(x(n,o)))return[];let i=ts(o,n);if(i.length>0)return i;return dp(o,t,n),[]}catch(i){return[`Failed to delete local rulebook source ${o}: ${i instanceof Error?i.message:String(i)}`]}});return r.length>0?{ok:!1,result:{ok:!1,errors:r,entries:[]}}:{ok:!0}}function dp(e,t,n){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(e);return}he(x(n,Tr(e,yn))),Zi(x(n,e))}function At(e,t){if(t===null){he(e);return}B(e,t)}function Et(e){return{ok:!1,errors:[e instanceof Error?e.message:String(e)],entries:[]}}function at(e,t){let n=fp(t),r=as(n),o={effectiveLevel:r.effectiveLevel,selectedPreset:n.policySnapshot.policy.safety.level??"standard",...n.policySnapshot.policyScopes?{safetyPresetScope:n.policySnapshot.policyScopes.levelScope}:{},effectiveCapabilities:r.effectiveCapabilities,destructiveCommandRuleOverrides:n.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:i,configValid:s}=pp({cwd:t?.cwd,userConfigDir:t?.userConfigDir});if(!e||!e.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:i,configValid:s,...o};let a=mp(e,n);if(a)return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:a.rule,matched:!0,reason:a.reason}]}]},result:"blocked",reason:V(a.reason),segment:V(a.target),...a.ruleId?{ruleId:V(a.ruleId)}:{},configSource:i,configValid:s,...o};let l=xi(e,n),c=l.decision,d=c?.ruleId??gp(e,n),m=$t.find((u)=>u.id===d&&u.activationCapability),g=m?r.policy.effectiveDestructiveCommandRules[m.id]:void 0;return{trace:yp(l.trace),result:c?"blocked":"allowed",reason:c?V(c.reason):void 0,segment:c?V(c.evidence.find((u)=>u.kind==="command")?.segment??e):void 0,ruleId:c?.ruleId?V(c.ruleId):void 0,customRule:hp(vp(c?.ruleId,n.policySnapshot)),configSource:i,configValid:s,...o,...m&&g?{ruleActivation:{id:m.id,...g}}:{}}}function pp(e){let t=oe(e?.cwd),n=e?.userConfigPath??ie(e),r=Ae({cwd:e?.cwd,userConfigDir:e?.userConfigDir,userConfigPath:e?.userConfigPath});try{if(w(r.projectConfigTarget)!==null){if(me(r.projectConfigTarget).errors.length===0)return{configSource:t,configValid:!0};return{configSource:t,configValid:!1}}}catch(o){if(o instanceof H)return{configSource:t,configValid:!1};throw o}try{if(w(r.userConfigTarget)!==null){let o=me(r.userConfigTarget);return{configSource:n,configValid:o.errors.length===0}}return{configSource:null,configValid:!0}}catch(o){if(o instanceof H)return{configSource:n,configValid:!1};throw o}}function fp(e){let t=up(e?.cwd??process.cwd()),n=e?.policySnapshot??z({cwd:t,userConfigDir:e?.userConfigDir}),r=ye(n.policy);return{cwd:t,effectiveCwd:t,policySnapshot:n,environment:ns(),protectedGitMetadata:ss([t]),effectiveCapabilities:r.capabilities,strict:e?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function mp(e,t){let n=t.cwd??process.cwd(),r=rs(st("",{command:e},{kind:"command",shell:"posix"},{executionCwd:n,configCwd:n},e)),o=ps(r);if(o)return{reason:us,target:o.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let i=ds(r);if(i)return{reason:cs,target:i.target,ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};let s=is(r,t.protectedGitMetadata);if(s)return{reason:os,target:s.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let a=t.policySnapshot.policy,l=a.secretProtection.enabled===!1?null:ms(r,a.secretProtection,{strict:t.strict});if(l)return{reason:fs,target:l.target,ruleId:l.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function gp(e,t){let n=t.policySnapshot.policy,r=Ot({...n,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...n.destructiveCommandRuleOverrides,...Object.fromEntries($t.flatMap((o)=>o.activationCapability?[[o.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return ls(e,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function hp(e){if(!e)return;return{id:V(e.id),...e.rulebook?{rulebook:{name:V(e.rulebook.name),version:V(e.rulebook.version)}}:{},...e.source?{source:V(e.source)}:{},...e.override?{override:{type:"reason",reason:V(e.override.reason)}}:{}}}function yp(e){let t=e.events.flatMap((r)=>r.kind==="step"&&r.scope==="global"?[r.step]:[]),n=new Map;for(let r of e.events){if(r.kind!=="step"||r.scope!=="segment")continue;let o=n.get(r.segmentIndex)??{index:r.segmentIndex,steps:[]};o.steps.push(r.step),n.set(r.segmentIndex,o)}return{steps:t,segments:[...n.values()]}}function vp(e,t){let n=e?.replace(/^custom\./,"");if(!n||!t.policy.rules.some((r)=>r.name===n))return;return t.ruleMetadata[n]??Object.freeze({id:n})}import{existsSync as hs,readFileSync as bp}from"node:fs";function gs(e,t){return{"safety.level":e.safety.level,...Nr("safety.overrides",e.safety.overrides),"workflow.worktree_mode":String(e.workflow.worktree_mode),"destructive_command_protection.enabled":String(e.destructive_command_protection.enabled),...Nr("destructive_command_protection.overrides",e.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":Hr(e.destructive_command_protection.allow_paths),"secret_protection.enabled":String(e.secret_protection.enabled),...Nr("secret_protection.overrides",e.secret_protection.overrides),"secret_protection.deny_paths":Hr(e.secret_protection.deny_paths),"secret_protection.allow_paths":Hr(e.secret_protection.allow_paths),...t?{"audit.retention_days":String(e.audit.retention_days)}:{}}}function Ft(e,t,n){let r=gs(e,n),o=gs(t,n);return[...new Set([...Object.keys(r),...Object.keys(o)])].flatMap((i)=>r[i]===o[i]?[]:[{field:i,before:r[i],after:o[i]}])}function lt(e){let t=ve(e);if(!hs(t))return{baseline:Y(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__),diagnostics:[]};let n=_e(t);return{baseline:Y(n.value),diagnostics:n.errors.length>0?n.errors:Ee(n.value)}}function _e(e){if(!hs(e))return{errors:[`${e}: file not found`]};try{return{value:JSON.parse(bp(e,"utf-8")),errors:[]}}catch(t){let n=t instanceof Error?t.message:String(t);return{errors:[`${e}: ${t instanceof SyntaxError?`Invalid JSON: ${n}`:n}`]}}}function jt(e,t){let n=Lp(e)?e:{};return{version:t.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((r)=>n[r]!==void 0).map((r)=>[r,n[r]]))}}function Nr(e,t){return Object.fromEntries(Object.entries(t).flatMap(([n,r])=>r===void 0?[]:[[`${e}.${n}`,String(r)]]))}function Hr(e){return e.length===0?"(none)":e.join(", ")}function Lp(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Ap(e){let t=ct(),n=E({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},e);if(fe(n.errors))return null;if(n.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(n.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let r=n.values.limit===void 0?20:ys(n.values.limit);if(r===null)return console.error("--limit must be a positive number"),null;let o=n.values.since===void 0?Math.min(30,t):ys(n.values.since);if(o===null||o>t)return console.error(`--since must be a positive number of days no greater than ${t}`),null;let i={limit:r,limitExplicit:n.values.limit!==void 0,since:o,sinceExplicit:n.values.since!==void 0,all:n.flags.all,json:n.flags.json,suspect:n.flags.suspect,pruneLegacy:n.flags.pruneLegacy,dryRun:n.flags.dryRun,id:n.values.id,agent:n.values.agent,rule:n.values.rule,session:n.values.session,project:n.values.project===void 0?void 0:Pp(n.values.project)};if(i.id&&(i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.sinceExplicit||i.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(i.pruneLegacy&&(i.id!==void 0||i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.all||i.sinceExplicit||i.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(i.dryRun&&!i.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return i}async function Ls(e,t={}){let n=Ap(e);if(!n)return 1;let r=t.logsDir??be();if(n.pruneLegacy)return Ep(r,n.json,n.dryRun);if(!r)return console.log(n.json?"[]":n.id?`No retained audit log entry found for id ${F(n.id)}.`:"No audit log entries found."),0;He(r);let o={count:0},i=Ce(r,o).flatMap((d)=>Fe(d,o).map((m)=>({entry:m,file:d})));if(o.count>0)console.error(`warning: ${o.count} audit log ${o.count===1?"source":"sources"} could not be read; these results are incomplete`);if(n.id)return $p(i,n,t.timeZone);let s=Date.now()-n.since*24*60*60*1000,a=i.filter((d)=>Op(d,n,r,s)),l=n.suspect?hr(a.map((d)=>d.entry)):null,c=(l?a.filter((d)=>l.has(d.entry)):a).sort((d,m)=>Date.parse(m.entry.ts)-Date.parse(d.entry.ts)).slice(0,n.limit);if(n.json)return console.log(JSON.stringify(c.map((d)=>d.entry),null,2)),0;if(c.length===0)return console.log("No audit log entries found."),0;for(let d of c)console.log(Np(d.entry,t.timeZone));return 0}function Ep(e,t,n){let r=e?Tp(e).map((a)=>Sp(e,a)):[];if(n)return _p(r,t);let o=[],i=0,s=0;for(let a of r){let l=vs(a,{throwIfNoEntry:!1})?.size??0,c=Ip(a);if(c){o.push(`${bs(a)}: ${c}`);continue}i++,s+=l}if(t)return console.log(JSON.stringify({removedFiles:i,removedBytes:s,failedFiles:o.length})),o.length===0?0:1;console.log(i===0&&o.length===0?"No legacy audit log files found.":`Removed ${i} legacy audit log ${i===1?"file":"files"} (${ws(s)}).`);for(let a of o)console.error(`Could not remove ${F(a)}`);if(console.log("Nested v2 audit logs were not changed."),i>0)console.log("This deletion cannot be undone.");return o.length===0?0:1}function _p(e,t){let n=e.reduce((r,o)=>r+(vs(o,{throwIfNoEntry:!1})?.size??0),0);if(t)return console.log(JSON.stringify({dryRun:!0,files:e.length,bytes:n})),0;if(console.log(e.length===0?"No legacy audit log files found.":`Would remove ${e.length} legacy audit log ${e.length===1?"file":"files"} (${ws(n)}).`),console.log("Nested v2 audit logs are not included."),e.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Tp(e){try{return wp(e,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function Ip(e){try{return kp(e),null}catch(t){return t instanceof Error?t.message:String(t)}}function ws(e){let t=["B","KiB","MiB","GiB"],n=Math.min(Math.floor(Math.log2(Math.max(e,1))/10),t.length-1);return`${Math.round(e/1024**n*10)/10} ${t[n]}`}function $p(e,t,n){let r=e.filter((i)=>i.entry.id===t.id);if(r.length>1)return console.error(`Multiple audit log entries found for id ${F(t.id??"")}.`),1;if(t.json)return console.log(JSON.stringify(r.map((i)=>i.entry),null,2)),0;let o=r[0];if(!o)return console.log(`No retained audit log entry found for id ${F(t.id??"")}.`),0;return console.log(Hp(o.entry,n)),0}function Op(e,t,n,r){if(!t.all&&e.entry.decision==="allow")return!1;if(Date.parse(e.entry.ts)<r)return!1;if(t.agent!==void 0&&e.entry.agent!==t.agent)return!1;if(t.rule!==void 0&&e.entry.ruleId!==t.rule)return!1;if(t.session!==void 0&&!Fp(e,n,t.session))return!1;if(t.project!==void 0&&!jp(e.entry.cwd,t.project))return!1;return!0}function Fp(e,t,n){if(e.entry.sessionId===n)return!0;return xp(e.file)===t&&bs(e.file,".jsonl")===n}function jp(e,t){if(!e)return!1;let n=Rp(t,e);return n!==".."&&!n.startsWith(`..${Dp}`)&&!Cp(n)}function Np(e,t){let n=F(e.id??"-"),r=F(e.decision??"deny"),o=e.cwd?` [${F(e.cwd)}]`:"",i=e.segment||e.command,s=i===e.command?"":"↳ ",a=i.length>50?`${i.slice(0,50)}…`:i;return`${n.padEnd(16)} ${F(ks(e.ts,t))} ${r.padEnd(5)} ${F(e.agent??"-").padEnd(15)} ${F(e.ruleId??"-").padEnd(20)} ${s}${F(a)}${o}`}function Hp(e,t){let n=(o)=>F(o===void 0||o===null||o===""?"-":o),r=e.shape?`${e.agent??"-"} (shape: ${e.shape})`:e.agent??"-";return[`id: ${n(e.id)}`,`ts: ${n(ks(e.ts,t))}`,`decision: ${n(e.decision)}`,`agent: ${n(r)}`,`level: ${n(e.level)}`,`tool: ${n(e.toolName)}`,`rule: ${n(e.ruleId)}`,`intent: ${n(e.intent)}`,`stage: ${n(e.failureStage)}`,`error: ${n(e.errorCode)}`,`session: ${n(e.sessionId)}`,`cwd: ${n(e.cwd)}`,`version: ${n(e.v)}`,`truncated: ${n(e.truncated===!0?"yes":void 0)}`,`reason: ${n(e.reason)}`,`command: ${n(e.command)}`,`segment: ${n(e.segment)}`].join(`
|
|
6
|
+
`)}function ks(e,t){let n=new Date(e);if(Number.isNaN(n.getTime()))return e;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:t}).format(n)}function ys(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:null}var xs={name:"doctor",aliases:["--doctor"],description:"Run diagnostic checks to verify installation and configuration",usage:"doctor [options]",options:[{flags:"--json",description:"Output diagnostics as JSON"},{flags:"--skip-update-check",description:"Skip npm registry version check"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net doctor","cc-safety-net doctor --json","cc-safety-net doctor --skip-update-check"]};var Cs={name:"explain",description:"Show step-by-step analysis trace of how a command would be analyzed",usage:"explain [options] <command>",argument:"<command>",options:[{flags:"--json",description:"Output analysis as JSON"},{flags:"--cwd",argument:"<path>",description:"Use custom working directory"},{flags:"-h, --help",description:"Show this help"}],examples:['cc-safety-net explain "git reset --hard"','cc-safety-net explain --json "rm -rf /"','cc-safety-net explain --cwd /tmp "git status"']};var Ss={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};import{isAbsolute as $s,join as Yp,relative as Zp}from"node:path";var Mp=8388608;function Up(e,t){console.log(JSON.stringify(e(Ps(t))))}async function Gp(e){let t;try{t=(await Wr(process.stdin)).trim()}catch{e({reason:"Failed to parse hook input JSON."});return}if(!t){e({reason:"Missing hook input JSON."});return}return Yr(t,e,"Failed to parse hook input JSON.")}async function Wr(e){let t=[],n=0;for await(let r of e){let o=typeof r==="string"?Buffer.from(r,"utf-8"):Buffer.from(r.buffer,r.byteOffset,r.byteLength);if(n+=o.byteLength,n>Mp)throw Bp(e),Error("hook input byte limit exceeded");t.push(o)}return Buffer.concat(t,n).toString("utf-8")}function Bp(e){let t=e.destroy??e.cancel;if(!t)return;try{Promise.resolve(t.call(e)).catch(()=>{})}catch{}}function Yr(e,t,n){try{return JSON.parse(e)}catch{t({reason:n});return}}function j(e,t){let n=t.get(e);return n?{kind:"command",shell:n}:{kind:As(e)}}function ae(e,t,n,r){let o=e===void 0?process.cwd():e,i=typeof o==="string"&&o.trim()!==""?Z([o]):void 0;if(i)return{configCwd:i,executionCwd:i};return T(r,t,n,Kp(o)),null}function T(e,t,n,r){let o;try{o=Jr(t)}catch(i){if(!(i instanceof Le))throw i}e(vn({command:o,segment:r,toolName:n}))}async function qp(e){let t=await Gp(e.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){T(e.outputDeny);return}if(!e.isSupported(t))return;let n=e.getAgent?.(t)??e.agent,r=e.agent===n?void 0:e.agent,o=Wp(t),i=(u,p)=>{Rs(u,()=>e.getSessionId(t),{agent:n,shape:r,toolName:p,cwd:o}),e.outputDeny(u)},s=e.getToolName(t);if(typeof s!=="string"||s.trim()===""){T((u)=>i(u),Jp(t));return}let a=s,l=(u)=>i(u,a),c;try{c=e.getToolInput(t,a,l)}catch(u){if(!(u instanceof Le))throw u;T(l,void 0,a);return}if(!c.ok)return;let d=e.getContext(t,c.input,a,l);if(!d)return;let m;try{m=Jr(c.input)}catch(u){if(!(u instanceof Le))throw u;T(l,void 0,a);return}let g=st(a,c.input,c.route,d,m??null);try{let u=bn(g,{guard:{auditAllowed:Es(),dependencies:e.guardDependencies},audit:{agent:n,shape:r,getSessionId:()=>e.getSessionId(t)}}),p=Kr(u,{includeEvidence:!0,toolName:u.stage==="command-analysis"?void 0:a});if(p){e.outputDeny(p);return}e.outputAllow?.()}catch(u){if(!(u instanceof _s))throw u;Vp(u);let p=Kr(u.evaluation,{includeEvidence:!0,toolName:u.evaluation.stage==="command-analysis"?void 0:a});if(p)e.outputDeny(p);return}}function Vp(e){if(!Nt(S.debug))return;console.error(`CC Safety Net debug: ${zp(e.stage)}: ${Ds(e.cause)}`)}function zp(e){if(e==="policy-protection")return"hook policy protection failed";if(e==="config-load")return"hook config loading failed";if(e==="secret-protection")return"hook secret protection failed";return"hook analysis failed"}function Kp(e){return typeof e==="string"?e:void 0}function Jp(e){if(!e||typeof e!=="object"||Array.isArray(e))return;if(Object.hasOwn(e,"tool_input"))return e.tool_input;let t=e.toolCall;if(t&&typeof t==="object"&&!Array.isArray(t))return t.args;return}function Wp(e){if(!e||typeof e!=="object"||Array.isArray(e))return null;let t=e.cwd;if(typeof t==="string")return t;let n=e.toolCall;if(!n||typeof n!=="object"||Array.isArray(n))return null;let r=n.args;if(!r||typeof r!=="object"||Array.isArray(r))return null;let o=r.Cwd;return typeof o==="string"?o:null}async function N(e){let t=(o)=>Up(e.createDenyOutput,o),n=e.createAllowOutput;await qp({...e,outputDeny:t,outputAllow:n?()=>console.log(JSON.stringify(n())):void 0})}function Gt(e){return Yp(e,".gemini","config","hooks.json")}var Xp=new Map([["run_command","auto"]]),Qp=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function Os(e){return j(e,Xp)}async function Fs(){await N({agent:"antigravity-cli",createDenyOutput:(e)=>({decision:"deny",reason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolCall?.name,getToolInput:(e,t)=>({ok:!0,input:o2(e.toolCall?.args,t),route:Os(t)}),getContext:e2,getSessionId:(e)=>e.conversationId})}function e2(e,t,n,r){let i=r2(e).flatMap((c)=>{let d=Z([c]);return d?[d]:[]});if(!i[0])return qe(r,t,n),null;if(n!=="run_command"){let c;try{c=t2(t,n,i)}catch(d){if(d instanceof Le)return qe(r,void 0,n),null;if(!(d instanceof Me))throw d;return qe(r,t,n),null}if(!c)return qe(r,t,n),null;return{configCwd:c,executionCwd:c}}let s=e.toolCall?.args;if(!s||!Object.hasOwn(s,"Cwd"))return{configCwd:i[0],executionCwd:i[0]};let a=s.Cwd;if(typeof a!=="string"||a.trim()==="")return qe(r,t,n),null;let l=we(a,i);if(l){let c=js(l,i);if(!c)return qe(r,t,n,a),null;return{configCwd:c,executionCwd:l}}return qe(r,t,n,a),null}function t2(e,t,n){let r=Os(t),o=[...Ts(e,Qp),...r.kind==="patch"?Is(e):[]].filter($s),i=Ln(),s=new Set(o.flatMap((a)=>{let l=js(Ut(a,Mt,i),n);return l?[l]:[]}));if(s.size>1)return null;return[...s][0]??n[0]??null}function js(e,t){return t.filter((n)=>n2(e,n)).reduce((n,r)=>r.length>n.length?r:n,"")||null}function n2(e,t){let n=Zp(t,e);return n===""||!n.startsWith("..")&&!$s(n)}function qe(e,t,n,r){let o=t&&typeof t==="object"?t.command:void 0;e(vn({command:typeof o==="string"?o:void 0,segment:r,toolName:n}))}function r2(e){if(e.workspacePaths===void 0)return[process.cwd()];let t=Array.isArray(e.workspacePaths)?e.workspacePaths.filter((n)=>typeof n==="string"&&n.trim()!==""):[];return Z(t)?t:[]}function o2(e,t){if(!e)return;if(t!=="run_command")return e;return{...e,command:typeof e.CommandLine==="string"&&e.CommandLine!==""?e.CommandLine:void 0}}var Bt=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],wn=Bt.slice().sort((e,t)=>e.doctorOrder-t.doctorOrder).map((e)=>e.id),Ns=Bt.filter((e)=>("runtime"in e)).slice().sort((e,t)=>e.runtime.order-t.runtime.order).map((e)=>({id:e.id,displayName:"displayName"in e.runtime?e.runtime.displayName:e.displayName,flags:e.runtime.flags,legacyFlags:"legacyFlags"in e.runtime?e.runtime.legacyFlags:[],description:e.runtime.description,legacyTopLevelFlags:e.runtime.legacyTopLevelFlags})),X=Bt.slice().sort((e,t)=>e.install.order-t.install.order).map((e)=>({id:e.id,...e.install})).map(({order:e,...t})=>t),Qv=Object.fromEntries(Bt.map((e)=>[e.id,e.displayName]));function D(e){return Bt.find((t)=>t.id===e)?.displayName??e}import{homedir as i2}from"node:os";import{isAbsolute as Hs,join as Zr}from"node:path";function Us(e){if(e!==void 0&&e!==null&&typeof e!=="string")return"unknown";if(typeof e==="string"&&!Hs(e))return"unknown";try{let t=Ln(),n=typeof e==="string"&&e?Ut(e,Mt,t):void 0,r=process.env.HOME||i2(),o=[["codex",process.env.CODEX_HOME||Zr(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||Zr(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||Zr(r,".claude")]],i=n?o.flatMap(([s,a])=>{if(!Hs(a))return[];return Ms(n,Ut(a,Mt,t))?[s]:[]}):[];if(i.length===1)return i[0]??"unknown";if(i.length>1)return"unknown"}catch(t){if(t instanceof Me)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var Xr="PreToolUse",Gs="BeforeTool",Bs="pre_tool_call",Qr="PreToolUse";async function kn(e){await N({agent:e.agent,...e.getAgent?{getAgent:e.getAgent}:{},createDenyOutput:(t)=>({hookSpecificOutput:{hookEventName:Xr,permissionDecision:"deny",permissionDecisionReason:t}}),isSupported:(t)=>t.hook_event_name===Xr,getToolName:(t)=>t.tool_name,getToolInput:(t,n)=>({ok:!0,input:t.tool_input,route:e.getToolRoute(n)}),getContext:(t,n,r,o)=>ae(t.cwd,n,r,o),getSessionId:(t)=>t.session_id})}var s2=new Map([["Bash","posix"],["PowerShell","powershell"]]);function a2(e){return j(e,s2)}async function qs(){await kn({agent:"claude-code",getAgent:(e)=>Us(e.transcript_path),getToolRoute:a2})}var l2=new Map([["Bash","auto"]]);async function Vs(){await kn({agent:"codex",getToolRoute:(e)=>j(e,l2)})}var c2=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function d2(e){return j(e,c2)}async function zs(){await N({agent:"copilot-cli",createDenyOutput:(e)=>({permissionDecision:"deny",permissionDecisionReason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(typeof e.toolArgs!=="string")return n({reason:"Failed to parse toolArgs JSON."}),{ok:!1};let r=Yr(e.toolArgs,n,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:d2(t)}},getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>typeof e.sessionId==="string"&&e.sessionId.trim()?e.sessionId:void 0})}var u2=new Map([["Shell","auto"]]);function p2(e){return j(e,u2)}async function Ks(){await N({agent:"cursor",createDenyOutput:(e)=>({permission:"deny",user_message:e,agent_message:e}),createAllowOutput:()=>({permission:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:p2(t)}),getContext:f2,getSessionId:(e)=>e.conversation_id})}function f2(e,t,n,r){let o=m2(e);if(!o[0])return T(r,t,n),null;let i=we(h2(e.cwd),o);if(!i)return T(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;if(t===null||typeof t!=="object"||Array.isArray(t))return{configCwd:i,executionCwd:i};if(!Object.hasOwn(t,"working_directory"))return{configCwd:i,executionCwd:i};let s=t.working_directory;if(typeof s!=="string"||s.trim()==="")return T(r,t,n),null;let a=we(s,o);if(!a)return T(r,t,n,s),null;return{configCwd:i,executionCwd:a}}function m2(e){return g2(e).flatMap((t)=>{let n=Z([t]);return n?[n]:[]})}function g2(e){if(e.workspace_roots===void 0)return typeof e.cwd==="string"&&e.cwd.trim()!==""?[e.cwd]:[];if(!Array.isArray(e.workspace_roots))return[];return e.workspace_roots.filter((t)=>typeof t==="string"&&t.trim()!=="")}function h2(e){return typeof e==="string"&&e.trim()!==""?e:"."}var y2=new Map([["run_shell_command","auto"]]);function v2(e){return j(e,y2)}async function Js(){await N({agent:"gemini-cli",createDenyOutput:(e)=>({decision:"deny",reason:e,systemMessage:e}),isSupported:(e)=>e.hook_event_name===Gs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:v2(t)}),getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var b2=new Map([["run_terminal_command","auto"]]);function L2(e){return j(e,b2)}async function Ws(){await N({agent:"grok-build",createDenyOutput:(e)=>({decision:"deny",reason:e}),createAllowOutput:()=>({decision:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(e.toolInputTruncated===!0)return T(n,e.toolInput,t),{ok:!1};return{ok:!0,input:e.toolInput,route:L2(t)}},getContext:w2,getSessionId:(e)=>e.sessionId})}function w2(e,t,n,r){let o=Z(k2(e));if(!o)return T(r,t,n),null;let i=we(x2(e.cwd),[o]);if(!i)return T(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;return{configCwd:i,executionCwd:i}}function k2(e){let t=e.workspaceRoot===void 0?e.cwd:e.workspaceRoot;return typeof t==="string"&&t.trim()!==""?[t]:[]}function x2(e){return typeof e==="string"&&e.trim()!==""?e:"."}import{resolve as C2}from"node:path";var S2=new Map([["terminal","posix"]]);async function Ys(){await N({agent:"hermes-agent",createDenyOutput:(e)=>({action:"block",message:e}),isSupported:(e)=>e.hook_event_name===Bs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:j(t,S2)}),getContext:R2,getSessionId:(e)=>e.session_id})}function R2(e,t,n,r){let o=ae(e.cwd,t,n,r);if(!o)return null;if(!t||typeof t!=="object"||Array.isArray(t))return o;if(!Object.hasOwn(t,"workdir"))return o;let i=t.workdir;if(typeof i!=="string"||i.trim()==="")return T(r,t,n),null;let s=Z([C2(o.configCwd,i)]);if(!s)return T(r,t,n,i),null;return{...o,executionCwd:s}}var Zs=new Map([["Bash","posix"]]);function P2(e){return j(e,Zs)}async function Xs(){await N({agent:"kimi-code",createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Qr,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Qr,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:P2(t)}),getContext:(e,t,n,r)=>{let o=ae(e.cwd,t,n,r);if(!o)return null;let i=e.tool_input;if(!Zs.has(n)||!i||!Object.hasOwn(i,"cwd"))return o;let s=i.cwd;if(typeof s!=="string"||s.trim()==="")return T(r,t,n),null;let a=we(s,[o.configCwd]);if(!a)return T(r,t,n,s),null;return{configCwd:o.configCwd,executionCwd:a}},getSessionId:(e)=>e.session_id})}var D2={"antigravity-cli":Fs,"claude-code":qs,codex:Vs,"copilot-cli":zs,cursor:Ks,"gemini-cli":Js,"grok-build":Ws,"hermes-agent":Ys,"kimi-code":Xs},dt=Ns.map((e)=>({...e,run:D2[e.id]}));function Qs(e){let t=E({label:"hook",booleans:Object.fromEntries(dt.map((r)=>[r.id,[...r.flags,...r.legacyFlags]]))},e);if(t.errors.length>0)return;let n=dt.filter((r)=>t.flags[r.id]);return n.length===1?n[0]:void 0}function ea(e){return dt.find((t)=>t.legacyTopLevelFlags.some((n)=>n===e))}var A2=dt.map((e)=>({flags:e.flags.join(", "),description:e.description})),E2=dt.flatMap((e)=>e.flags.map((t)=>`cc-safety-net hook ${t}`)),ta={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...A2,{flags:"-h, --help",description:"Show this help"}],examples:E2};var na={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...X.map((e)=>({flags:e.flag,description:`Install ${D(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...X.map((e)=>`cc-safety-net install ${e.flag}`)]},ra={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...X.map((e)=>({flags:e.flag,description:`Uninstall ${D(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...X.map((e)=>`cc-safety-net uninstall ${e.flag}`)]},oa={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var ia={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],ut={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var sa={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var aa={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var Cn=[sa,xs,ia,Cs,ut,xn,na,oa,ra,ta,Ss,aa];function _2(e){return e.aliases??[]}function Sn(e){let t=e.toLowerCase();return Cn.find((n)=>n.name.toLowerCase()===t||_2(n).some((r)=>r.toLowerCase()===t))}import{basename as T2}from"node:path";function Rn(e=7,t=be()){let n=Date.now()-e*24*60*60*1000,r=[],o=new Set,i=0,s,a,l,c;if(t)He(t);let d={count:0},m=t?Ce(t,d):[];for(let u of m)for(let p of Fe(u,d)){if(p.decision==="allow")continue;let f=new Date(p.ts).getTime();if(f>=n){if(i++,o.add(p.sessionId??T2(u,".jsonl")),a===void 0||f<=a)s=p.ts,a=f;if(c===void 0||f>c)l=p.ts,c=f;I2(r,p,f)}}let g=r.map((u)=>({timestamp:u.ts,command:u.command,reason:u.reason,relativeTime:gr(new Date(u.ts))}));return{totalBlocked:i,sessionCount:o.size,recentEntries:g,oldestEntry:s,newestEntry:l,unreadable:d.count}}function I2(e,t,n){let r=e.findIndex((o)=>n>new Date(o.ts).getTime());if(r===-1){if(e.length<3)e.push(t);return}if(e.splice(r,0,t),e.length>3)e.pop()}import{dirname as $2}from"node:path";function la(e,t,n){let r;try{if(w(t)===null)return{path:e,exists:!1,valid:!1,ruleCount:0};r=me(t),r.errors.push(...W(e,n))}catch(o){if(!(o instanceof H))throw o;r={errors:[o.message],ruleNames:new Set}}return{path:e,exists:!0,valid:r.errors.length===0,ruleCount:r.ruleNames.size,...r.errors.length>0?{errors:r.errors}:{}}}function O2(e,t){return{source:t,name:e.name,command:e.command,subcommand:e.subcommand,blockArgs:[...e.block_args],reason:e.reason}}function ca(e,t){let n=t?.userConfigPath??ie(),r=t?.projectConfigPath??oe(e),o=$2(n),i=De({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),s=Ae({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),a=new Map(i.rulebooks.flatMap((l)=>l.rules.map((c)=>[c,l.source])));return{userConfig:la(n,s.userConfigTarget,s.userScope),projectConfig:la(r,s.projectConfigTarget,s.projectScope),effectiveRules:i.rules.map((l)=>O2(l,a.get(l.name)??"project")),shadowedRules:[]}}var F2=[{flag:S.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:S.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:S.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:S.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:S.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:S.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:S.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:S.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function da(){return[...F2.map((e)=>({name:e.flag.name,value:Vr(e.flag),isSet:zr(e.flag),legacyName:e.flag.legacyName,legacyValue:e.flag.legacyName?process.env[e.flag.legacyName]:void 0,legacyIsSet:e.flag.legacyName?process.env[e.flag.legacyName]!==void 0:void 0,description:e.description,defaultBehavior:e.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:process.env.CC_SAFETY_NET_HOME,isSet:process.env.CC_SAFETY_NET_HOME!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ua={error:0,warning:1,info:2},j2=["policy","config","audit"];function N2(e){return e.map((t)=>{if(t==="ownership")return"is not owned by the current user";if(t==="permissions")return"has unsafe permissions";if(t==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var H2=[{derive:(e)=>e.hooks.length>0&&e.hooks.every((t)=>!t.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(e)=>e.hooks.filter((t)=>t.inspectionStatus==="failed").map((t)=>{let n=D(t.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${n} inspection failed`,detail:`Doctor could not verify the ${n} integration configuration.`,fixHint:`Correct the reported ${n} configuration error, then run \`cc-safety-net doctor\` again.`,integration:t.platform}})},{derive:(e)=>e.userConfig.exists&&!e.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.userConfig.path}]:[]},{derive:(e)=>e.projectConfig.exists&&!e.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.projectConfig.path}]:[]},{derive:(e)=>e.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${e.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(e)=>e.v2Leftovers&&e.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${e.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(e)=>{let t=e.environment.find((n)=>n.name==="CC_SAFETY_NET_AUDIT_SCOPE");return qr(t?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...j2.map((e)=>({derive:(t)=>t.posture.directories.filter((n)=>n.kind===e&&n.status==="unsafe").map((n)=>({checkId:`posture.${e}-directory-unsafe`,severity:"error",title:`${e[0]?.toUpperCase()}${e.slice(1)} directory is unsafe`,detail:`The ${e} directory ${N2(n.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...n.path?{path:n.path}:{}}))})),{derive:(e)=>{let t=[...e.effectiveSafety.weakenedRuleOverrides].sort();return t.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${t.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${t.join(", ")}.`}]:[]}}];function pa(e){return H2.flatMap((t,n)=>t.derive(e).map((r,o)=>({finding:r,catalogOrder:n,occurrence:o}))).sort((t,n)=>ua[t.finding.severity]-ua[n.finding.severity]||t.catalogOrder-n.catalogOrder||t.occurrence-n.occurrence).map((t)=>t.finding)}function le(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var M2=(e)=>le()?`\x1B[32m${e}\x1B[0m`:e,U2=(e)=>le()?`\x1B[33m${e}\x1B[0m`:e,G2=(e)=>le()?`\x1B[34m${e}\x1B[0m`:e,B2=(e)=>le()?`\x1B[35m${e}\x1B[0m`:e,q2=(e)=>le()?`\x1B[36m${e}\x1B[0m`:e,V2=(e)=>le()?`\x1B[31m${e}\x1B[0m`:e,z2=(e)=>le()?`\x1B[2m${e}\x1B[0m`:e,K2=(e)=>le()?`\x1B[1m${e}\x1B[0m`:e,y={green:M2,yellow:U2,blue:G2,magenta:B2,cyan:q2,red:V2,dim:z2,bold:K2},J2="\x1B[0m",W2=[39,82,198,226,208,51,196,46,201,214,93,154,220,27,49,190,200,33,129,227,45,160,63,118,123,202];function Y2(e){let t=e;return()=>(t=(t*1664525+1013904223)%4294967296,t/4294967296)}function Z2(e){let t=[...W2],n=Y2(e);for(let r=t.length-1;r>0;r--){let o=Math.floor(n()*(r+1)),i=t[r];t[r]=t[o],t[o]=i}return t}function X2(e,t=0){if(!le())return"";let n=Z2(t);return`\x1B[38;5;${n[e%n.length]}m`}function fa(e,t,n=0){if(!le())return`"${e}"`;return`${X2(t,n)}"${e}"${J2}`}function Pn(e){return e==="default"?"built-in default":`${e} policy`}var Q2=new RegExp("\x1B\\[[0-9;]*m","g"),no=(e)=>e.replace(Q2,"").length;function Ve(e){let t=(e.headers??e.rows[0]??[]).map((s,a)=>{let l=Math.max(...e.rows.map((c)=>no(c[a]??"")));return Math.max(no(s),l)}),n=(s,a)=>s+" ".repeat(Math.max(0,a-no(s))),r=(s,a)=>a[0]+t.map((l)=>s.repeat(l+2)).join(a[1])+a[2],o=(s)=>`│ ${s.map((a,l)=>n(a,t[l]??0)).join(" │ ")} │`,i=e.headers?[` ${o(e.headers)}`,` ${r("─",["├","┼","┤"])}`]:[];return[` ${r("─",["┌","┬","┐"])}`,...i,...e.rows.map((s)=>` ${o(s)}`),` ${r("─",["└","┴","┘"])}`].join(`
|
|
7
|
+
`)}function ma(e){let t=[];t.push("Hook Integration"),t.push(ef(e));let n=[],r=[];for(let o of e){let i=D(o.platform);if(o.errors&&o.errors.length>0)for(let s of o.errors)if(o.configured)n.push({platform:i,message:s});else r.push({platform:i,message:s})}for(let o of n)t.push(` Warning (${o.platform}): ${o.message}`);for(let o of r)t.push(y.red(` Error (${o.platform}): ${o.message}`));return t.join(`
|
|
8
|
+
`)}function ef(e){let t=["Platform","Discovery","Configuration","Inspection"],n=e.map((r)=>{let o=D(r.platform);if(r.inspectionStatus==="not-inspected"){let l=y.dim("Not inspected");return[o,l,l,l]}let i=r.detected?y.green("Detected"):r.inspectionStatus==="failed"?y.red("Unknown"):y.dim("Not detected"),s=r.configured?y.green("Configured"):r.detected?y.yellow("Not configured"):r.inspectionStatus==="failed"?y.red("Unknown"):y.dim("Not applicable"),a=r.inspectionStatus==="verified"?y.green("Verified"):r.inspectionStatus==="failed"?y.red("Failed"):y.dim("Not applicable");return[o,i,s,a]});return Ve({headers:t,rows:n})}function ga(e){let n=["Guard Engine Verification",` Synthetic self-test: ${e.failed>0?y.red(`${e.passed}/${e.total} FAIL`):y.green(`${e.passed}/${e.total} passed`)}`],r=e.results.filter((o)=>!o.passed);if(r.length>0){n.push(""),n.push(y.red(" Failures:"));for(let o of r)n.push(y.red(` • ${o.description}`)),n.push(y.red(` expected ${o.expected}, got ${o.actual}`))}return n.join(`
|
|
9
|
+
`)}function tf(e){if(e.length===0)return" (no custom rules)";let t=["Source","Name","Command","Block Args"],n=e.map((r)=>[r.source,r.name,r.subcommand?`${r.command} ${r.subcommand}`:r.command,r.blockArgs.join(", ")]);return Ve({headers:t,rows:n})}function ha(e){let t=[];if(t.push("Configuration"),t.push(nf(e.userConfig,e.projectConfig)),t.push(""),e.effectiveRules.length>0)t.push(` Effective rules (${e.effectiveRules.length} total):`),t.push(tf(e.effectiveRules));else t.push(" Effective rules: (none - using built-in rules only)");for(let n of e.shadowedRules)t.push(""),t.push(` Note: Project rule "${n.name}" shadows user rule with same name`);return t.join(`
|
|
10
|
+
`)}function nf(e,t){let n=["Scope","Status"],r=(i)=>{if(!i.exists)return y.dim("N/A");if(!i.valid)return y.red(`Invalid (${i.errors?.[0]??"unknown error"})`);return y.green("Configured")},o=[["User",r(e)],["Project",r(t)]];return Ve({headers:n,rows:o})}function ya(e){let t=[];return t.push("Environment"),t.push(rf(e)),t.join(`
|
|
11
11
|
`)}function va(e){let t=e.effectiveSafety.policyScopes,n=["Effective Safety",` Selected preset: ${e.effectiveSafety.selectedPreset}${t?` (${Pn(t.levelScope)})`:""}`,` Effective: ${e.effectiveSafety.level}`],r=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[o,i]of r){let s=e.effectiveSafety.capabilities[o],a=s.enabled?y.green("ON"):y.dim("OFF"),l=s.sources.length>0?` (${s.sources.join(", ")})`:"";n.push(` ${i}: ${a} via ${s.source}${l}`)}if(t&&t.weakenings.length>0){n.push(" Project policy deltas:");for(let o of t.weakenings)n.push(` ${o}`)}n.push(` Stored rule customizations: ${e.effectiveSafety.ruleCounts.stored}`),n.push(` Effective rule customizations: ${e.effectiveSafety.ruleCounts.effective}`);for(let[o,i]of Object.entries(e.effectiveSafety.ruleOverrides))n.push(` ${o}: ${i}`);return n.join(`
|
|
12
12
|
`)}function ba(e){let t=["Findings"];if(e.length===0)return t.push(" No findings from inspected doctor facts."),t.join(`
|
|
13
13
|
`);for(let n of e){let r=`[${n.severity.toUpperCase()}] ${n.checkId}: ${F(n.title)}`,o=n.severity==="error"?y.red:n.severity==="warning"?y.yellow:y.blue;if(t.push(` ${o(r)}`),t.push(` ${F(n.detail)}`),n.path)t.push(` Path: ${F(n.path)}`);if(n.fixHint)t.push(` Fix: ${F(n.fixHint)}`)}return t.join(`
|
|
14
|
-
`)}function
|
|
15
|
-
`)}function
|
|
14
|
+
`)}function rf(e){let t=["Variable","Status","Legacy"],n=e.map((r)=>{let o=r.isSet?y.green("✓"):y.dim("✗"),i=r.legacyName&&r.legacyIsSet?`${r.legacyName} ${y.green("✓")}`:r.legacyName??"";return[r.name,o,i]});return Ve({headers:t,rows:n})}function La(e){let t=[];if(e.totalBlocked===0)t.push("Recent Activity"),t.push(" No blocked commands in the last 7 days"),t.push(" Tip: This is normal for new installations");else t.push(`Recent Activity · last 7 days (${e.totalBlocked} blocked / ${e.sessionCount} sessions)`),t.push(of(e.recentEntries));if(e.unreadable>0)t.push(` Warning: ${e.unreadable} audit log ${e.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return t.join(`
|
|
15
|
+
`)}function of(e){let t=["Time","Command"],n=e.map((r)=>{let o=F(r.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),i=o.length>40?`${o.slice(0,37)}...`:o;return[r.relativeTime,i]});return Ve({headers:t,rows:n})}function wa(e){let t=[];if(t.push("Update Check"),e.latestVersion===null&&!e.error)return t.push(Dn([["Status",y.dim("Skipped")],["Installed",e.currentVersion]])),t.join(`
|
|
16
16
|
`);if(e.error)return t.push(Dn([["Status",`${y.yellow("⚠")} Error`],["Installed",e.currentVersion],["Error",y.dim(e.error)]])),t.join(`
|
|
17
17
|
`);if(e.updateAvailable)return t.push(Dn([["Status",`${y.yellow("⚠")} Update Available`],["Current",e.currentVersion],["Latest",y.green(e.latestVersion??"")]])),t.push(""),t.push(" Run: bunx cc-safety-net@latest doctor"),t.push(" Or: npx cc-safety-net@latest doctor"),t.join(`
|
|
18
18
|
`);return t.push(Dn([["Status",`${y.green("✓")} Up to date`],["Version",e.currentVersion]])),t.join(`
|
|
19
|
-
`)}function Dn(e){return Ve({rows:e})}function ka(e){let t=[];return t.push("System Info"),t.push(
|
|
20
|
-
`)}function
|
|
19
|
+
`)}function Dn(e){return Ve({rows:e})}function ka(e){let t=[];return t.push("System Info"),t.push(sf(e)),t.join(`
|
|
20
|
+
`)}function sf(e){let t=["Component","Version"],n=(i)=>{if(i===null)return y.dim("not found");return i},o=[{label:"cc-safety-net",value:e.version},...wn.map((i)=>({label:D(i),value:e.versions[i]??null})),{label:"Node.js",value:e.nodeVersion},{label:"npm",value:e.npmVersion},{label:"Bun",value:e.bunVersion},{label:"Platform",value:e.platform}].map((i)=>[i.label,n(i.value)]);return Ve({headers:t,rows:o})}function xa(e){if(e.findings.length===0)return y.green(`
|
|
21
21
|
No findings from inspected doctor facts.`);let t={error:e.findings.filter((i)=>i.severity==="error").length,warning:e.findings.filter((i)=>i.severity==="warning").length,info:e.findings.filter((i)=>i.severity==="info").length},n=["error","warning","info"].filter((i)=>t[i]>0).map((i)=>`${t[i]} ${i}`),r=e.findings.length===1?"finding":"findings",o=`
|
|
22
|
-
${e.findings.length} ${r}: ${n.join(", ")}.`;if(t.error>0)return y.red(o);if(t.warning>0)return y.yellow(o);return y.blue(o)}import{lstatSync as
|
|
23
|
-
`)[0]?.trim()||null}async function qt(e=pt){let[t,n,r,o,i,s]=await Promise.all([Promise.all(X.map(async(a)=>[a.id,An(await e([...a.probeCommand]))])),e(["codex","plugin","list"],30000),e(["amp","plugins","list"],30000),e(["node","--version"]),e(["npm","--version"]),e(["bun","--version"])]);return{version:Da,versions:Object.fromEntries(t),codexPluginListOutput:n,ampPluginListOutput:r,nodeVersion:An(o),npmVersion:An(i),bunVersion:An(s),platform:`${process.platform} ${process.arch}`}}function so(e,t){if(t==="dev")return!1;let n=e.split(".").map(Number),r=t.split(".").map(Number),[o=0,i=0,s=0]=n,[a=0,l=0,c=0]=r;if(o!==a)return o>a;if(i!==l)return i>l;return s>c}async function Te(){let e=I(),t=new AbortController,n=setTimeout(()=>t.abort(),3000);try{let r=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:t.signal});if(!r.ok)return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${r.status}`};let o=await r.json(),i=so(o.version,e);return{currentVersion:e,latestVersion:o.version,updateAvailable:i}}catch(r){return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:r instanceof Error?r.message:"Network error"}}finally{clearTimeout(n)}}import*as Fa from"node:readline";var Ta=(e)=>`\x1B[${e}B`,
|
|
22
|
+
${e.findings.length} ${r}: ${n.join(", ")}.`;if(t.error>0)return y.red(o);if(t.warning>0)return y.yellow(o);return y.blue(o)}import{lstatSync as af}from"node:fs";import{dirname as ro}from"node:path";function oo(e,t){try{let n=af(t);if(n.isSymbolicLink())return{kind:e,path:t,status:"unsafe",issues:["symlink"]};if(!n.isDirectory())return{kind:e,path:t,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:e,path:t,status:"unknown",issues:[]};let r=[...n.uid!==process.getuid()?["ownership"]:[],...(n.mode&18)!==0?["permissions"]:[]];return{kind:e,path:t,status:r.length>0?"unsafe":"safe",issues:r}}catch(n){if(typeof n==="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return{kind:e,path:t,status:"not-applicable",issues:[]};return{kind:e,path:t,status:"unknown",issues:[]}}}function Ca(e){let t=be();return{directories:[oo("policy",ro(ro(e))),oo("config",ro(e)),...t?[oo("audit",t)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as lf}from"node:child_process";import{existsSync as Sa}from"node:fs";import{delimiter as cf,extname as df,join as uf}from"node:path";import{stripVTControlCharacters as Ra}from"node:util";var Da="2.3.3",pf=5000,ff="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function I(){return Da}function io(e,t){let n=e[t];if(n)return n;let r=Object.keys(e).find((o)=>o.toLowerCase()===t.toLowerCase()&&!!e[o]);return r?e[r]:n}function mf(e){return(io(e,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((t)=>t.length>0)}function gf(e,t){let n=df(e)?[e]:[...mf(t).map((r)=>`${e}${r}`),e];if(e.includes("/")||e.includes("\\"))return n.find((r)=>Sa(r))??e;return(io(t,"PATH")??"").split(cf).flatMap((r)=>n.map((o)=>uf(r,o))).find((r)=>Sa(r))??e}function Pa(e){if(!/[\s"&|<>^]/.test(e))return e;return`"${e.replace(/"/g,'""')}"`}function ze(e,t){let[n,...r]=e,o=t[ff]==="win32"?"win32":process.platform;if(!n||o!=="win32")return{cmd:n??"",args:r};let i=gf(n,t);if(!/\.(?:bat|cmd)$/i.test(i))return{cmd:i,args:r};return{cmd:io(t,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Pa(i),...r.map(Pa)].join(" ")]}}var pt=async(e,t=pf)=>{let n=await hf(e,{timeoutMs:t});if(n.code!==0)return null;return Ra(n.stdout).trim()||Ra(n.stderr).trim()||null};function hf(e,t){let[n,...r]=e;if(!n)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((o)=>{try{let i=ze([n,...r],process.env),s=lf(i.cmd,i.args,{stdio:["ignore","pipe","pipe"]}),a=!1,l="",c="";s.stdout.on("data",(g)=>{l+=g.toString()}),s.stderr.on("data",(g)=>{c+=g.toString()});let d=(g)=>{if(a)return;a=!0,clearTimeout(m),o(g)},m=setTimeout(()=>{s.kill(),d({code:null,stdout:l,stderr:c})},t.timeoutMs);s.on("close",(g)=>{d({code:g,stdout:l,stderr:c})}),s.on("error",()=>{d({code:null,stdout:l,stderr:c})})}catch{o({code:null,stdout:"",stderr:""})}})}function An(e){if(!e)return null;let t=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(e);if(t)return t[1]??null;let n=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(e);if(n)return n[1]??null;return e.split(`
|
|
23
|
+
`)[0]?.trim()||null}async function qt(e=pt){let[t,n,r,o,i,s]=await Promise.all([Promise.all(X.map(async(a)=>[a.id,An(await e([...a.probeCommand]))])),e(["codex","plugin","list"],30000),e(["amp","plugins","list"],30000),e(["node","--version"]),e(["npm","--version"]),e(["bun","--version"])]);return{version:Da,versions:Object.fromEntries(t),codexPluginListOutput:n,ampPluginListOutput:r,nodeVersion:An(o),npmVersion:An(i),bunVersion:An(s),platform:`${process.platform} ${process.arch}`}}function so(e,t){if(t==="dev")return!1;let n=e.split(".").map(Number),r=t.split(".").map(Number),[o=0,i=0,s=0]=n,[a=0,l=0,c=0]=r;if(o!==a)return o>a;if(i!==l)return i>l;return s>c}async function Te(){let e=I(),t=new AbortController,n=setTimeout(()=>t.abort(),3000);try{let r=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:t.signal});if(!r.ok)return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${r.status}`};let o=await r.json(),i=so(o.version,e);return{currentVersion:e,latestVersion:o.version,updateAvailable:i}}catch(r){return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:r instanceof Error?r.message:"Network error"}}finally{clearTimeout(n)}}import*as Fa from"node:readline";var Ta=(e)=>`\x1B[${e}B`,yf=(e)=>`\x1B[${e}A`;var Aa=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function vf(e){return new Promise((t)=>setTimeout(t,e))}function bf(e,t,n){if(!n)return t(e);if(n.aborted)return Promise.resolve();return new Promise((r,o)=>{let i=()=>n.removeEventListener("abort",s),s=()=>{i(),r()};n.addEventListener("abort",s,{once:!0}),t(e).then(()=>{i(),r()},(a)=>{i(),o(a)})})}function Vt(e,t){return e&&e>0?e:t}function En(e){return Math.max(0,Math.min(1,e))}function ft(e){return Math.max(0,Math.min(255,Math.round(e)))}function ao(e){return e<=0.0031308?12.92*e:1.055*e**0.4166666666666667-0.055}function Lf(e,t,n){let r=n*Math.PI/180,o=t*Math.cos(r),i=t*Math.sin(r),s=(e+0.3963377774*o+0.2158037573*i)**3,a=(e-0.1055613458*o-0.0638541728*i)**3,l=(e-0.0894841775*o-1.291485548*i)**3;return{blue:ft(ao(En(-0.0041960863*s-0.7034186147*a+1.707614701*l))*255),green:ft(ao(En(-1.2684380046*s+2.6097574011*a-0.3413193965*l))*255),red:ft(ao(En(4.0767416621*s-3.3077115913*a+0.2309699292*l))*255)}}function lo(e,t){let n=(t*e*180/Math.PI%360+360)%360;return Lf(0.72,0.15,n)}function Ia(e,t=0.1){let n=lo(t,e);return`\x1B[38;2;${n.red};${n.green};${n.blue}m`}function wf(e,t){return{blue:ft(e.blue+(255-e.blue)*t),green:ft(e.green+(255-e.green)*t),red:ft(e.red+(255-e.red)*t)}}function $a(e,t,n){let r=Math.imul(e+2654435769,2246822507)^Math.imul(t+3266489909,668265263)^Math.imul(n+374761393,2654435761),o=r^r>>>15,i=Math.imul(o,739982445),s=i^i>>>12,a=Math.imul(s,695872825);return((a^a>>>15)>>>0)/4294967296}function kf(e,t,n){let r=Math.floor($a(e,t,n)*Aa.length);return Aa[r]??"░"}function Ea(e){let t=En(e);return t*t*t*(t*(t*6-15)+10)}function xf(e){if(e.length===0)return"";let t=[],n=!1,r="";for(let o of e){let i=`${o.red};${o.green};${o.blue}`;if(o.bold!==n)t.push(o.bold?"\x1B[1m":"\x1B[22m"),n=o.bold;if(i!==r)t.push(`\x1B[38;2;${i}m`),r=i;t.push(o.character)}return`${t.join("")}\x1B[22m\x1B[39m`}function Cf(e,t,n,r,o){return e.map((i,s)=>({...lo(n,r+t+s/o),bold:!1,character:i}))}function Sf(e,t,n,r,o,i,s,a){let l=Math.max(1,r*0.75),c=Math.min(1,n/l),d=o*Ea(c),m=Math.max(0,(n-l)/Math.max(1,r-l)),g=(1-Ea(n/r))*a*2,u=0.35*Math.max(0,1-m*2),p=c>=1,f=Math.min(e.length,Math.ceil(d+2+1));return e.slice(0,f).map((b,L)=>{let h=lo(i,s+t+L/a+g),R=L+$a(t,L,7919)*2-1;if(R>d+2)return{...h,bold:!1,character:" "};let v=d-R,P=0.8*Math.exp(-(v*v)/12.5),ne=Math.min(0.9,P+u),un=!p&&R>d-4;return{...wf(h,ne),bold:ne>0.3,character:un?kf(t,L,n):b}})}function _a(e){return`\x1B[?2026h${e.map((t,n)=>`\x1B8${n>0?Ta(n):""}${xf(t)}`).join("")}\x1B[?2026l`}async function co(e,t={}){if(!e)return;let n=t.output??process.stdout,r=t.sleep??vf,o=Vt(t.frequency,0.1),i=t.seed??0,s=Vt(t.speed,40),a=Vt(t.spread,3),l=Vt(t.frameRate,60),c=Math.max(1,Math.floor(Vt(t.duration,12))),d=e.split(`
|
|
24
24
|
`).map((f)=>Array.from(f)),m=Math.max(...d.map((f)=>f.length)),g=1000*c*d.filter((f)=>f.length>0).length/s,u=m>0?Math.max(1,Math.ceil(g/(1000/l))):0,p=u>0?g/u:0;n.write(`\x1B[?25l${d.length>1?`${`
|
|
25
|
-
`.repeat(d.length-1)}${
|
|
25
|
+
`.repeat(d.length-1)}${yf(d.length-1)}`:""}\x1B7`);try{for(let f=1;f<=u;f+=1){if(t.signal?.aborted)break;n.write(_a(d.map((b,L)=>Sf(b,L,f,u,m,o,i,a)))),await bf(p,r,t.signal)}}finally{if(n.write(_a(d.map((f,b)=>Cf(f,b,o,i,a)))),n.write("\x1B8"),d.length>1)n.write(Ta(d.length-1));n.write(`
|
|
26
26
|
\x1B[0m\x1B[?25h`)}}var Oa=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
|
|
27
|
-
`);function
|
|
28
|
-
`).map((n)=>
|
|
29
|
-
`).find((n)=>n.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!t)return{platform:"codex",status:"n/a"};if(!t.includes("installed,"))return{platform:"codex",status:"n/a"};if(!t.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as Hn,readdirSync as
|
|
30
|
-
`)n++;continue}if(s==="/"&&a==="*"){n+=2;while(n<e.length-1){if(e[n]==="*"&&e[n+1]==="/"){n+=2;break}n++}continue}if(s===","){i=t.length,t+=s,n++;continue}if(s==="}"||s==="]"){if(i!==-1){let l=t.slice(i+1);if(/^\s*$/.test(l))t=t.slice(0,i)+l}i=-1,t+=s,n++;continue}if(!/\s/.test(s))i=-1;t+=s,n++}return t}function fo(e){if(!e?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(e)}function al(e,t){if(!e)return null;let n=e.match(/(\d+)\.(\d+)\.(\d+)/);if(!n)return null;let r=[Number(n[1]),Number(n[2]),Number(n[3])];for(let o=0;o<t.length;o++){let i=r[o]??0,s=t[o]??0;if(i!==s)return i>s}return!0}function
|
|
31
|
-
`)}function gl(e){let t=Un(e);if(!dl(t))return
|
|
32
|
-
`),{path:t,alreadyInstalled:!1};let n=pl(t),r=fl(n),o=r.filter(Mn);if(Ke(n.hooks)&&Array.isArray(n.hooks.preToolUse)&&o.length===1&&o[0]!==void 0&&
|
|
33
|
-
`)}function Rl(e){let t=Vn(e);if(!Ll(t))return
|
|
27
|
+
`);function Rf(e){return Boolean(e.isTTY)}async function zt(e={}){let t=e.output??process.stdout;if(!Rf(t))return;let n=e.input??process.stdin,r={duration:e.duration,frequency:e.frequency,output:t,seed:e.seed??Math.random()*8192,sleep:e.sleep,speed:e.speed,spread:e.spread};if(!n.isTTY||typeof n.setRawMode!=="function"){await co(Oa,r);return}let o=new AbortController,i=n.readableFlowing===!0,s=n.isRaw===!0,a=!1,l=(c,d)=>{if(d.ctrl&&d.name==="c")a=!0;if(a||d.name==="return"||d.name==="enter")o.abort()};Fa.emitKeypressEvents(n),n.on("keypress",l),n.setRawMode(!0),n.resume();try{await co(Oa,{...r,signal:o.signal})}finally{if(n.off("keypress",l),n.setRawMode(s),!i)n.pause()}if(!a)return;if(e.onInterrupt){e.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Pf}from"node:crypto";import{existsSync as Na}from"node:fs";import{dirname as _n,join as Ha}from"node:path";var Df="`cc-safety-net rule sync` is deprecated: rulebooks are live files that need no synchronization. This run only migrates the lock and cache an earlier version left behind.",Af="cache",Ef="rulebooks";function Ma(e={}){let t=U(e),n=x(t.filesystemScope,Ga(t.configDir)),r=w(t.lockTarget);if(console.log(Df),r===null&&!Na(n.path))return console.log(`No v2 lock or cache leftovers found in ${_n(t.configDir)}; nothing to migrate.`),0;let o=Of(r),i=q(t.configTarget);if(!i.config&&(w(t.configTarget)!==null||o.size>0))return console.error(`Cannot migrate: the rules config in ${_n(t.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let s=i.config?.rules??[];for(let a of s.flatMap((l)=>_f(l,o,t,n,e.global===!0)))console.log(a);return he(t.lockTarget),ja(n),console.log(`Removed the v2 lock and cache under ${_n(t.configDir)}.`),0}function Ua(e){return[...new Set([{cwd:e},{cwd:e,global:!0}].flatMap((t)=>{let n=U(t);return[n.lockPath,Ga(n.configDir)]}))].filter((t)=>Na(t))}function _f(e,t,n,r,o){if(!re(e))return[];let i=je(e).name,s=x(n.filesystemScope,Re(n.configDir,i)),a=w(s);if(a!==null&&Tf(a,i))return[];let l=t.get(e),c=l?If(l,i,r.path,n.filesystemScope):null;if(c===null)return[`Could not migrate ${e} from the v2 cache. Run \`cc-safety-net rule update ${e}${o?" --global":""}\` to vendor it.`];if(B(s,c),a!==null)return[`Restored ${e} from the v2 cache over an invalid file.`];return[`Vendored ${e} from the v2 cache.`]}function Tf(e,t){let n=_t(e);return!("problem"in n)&&n.rulebook.name===t}function If(e,t,n,r){let o=Ha(n,Ef,`${$f(e)}--${e.digest.replace("sha256:","").slice(0,12)}`,yn),i=w(x(r,o));if(i===null||Nf(i)!==e.digest)return null;let s=_t(i);if("problem"in s||s.rulebook.name!==t)return null;return i}function Ga(e){return Ha(_n(e),Af)}function $f(e){return([e.owner,e.repo,e.display_ref,e.name].every((r)=>typeof r==="string"&&r!=="")?`${e.owner}/${e.repo}#${e.display_ref}/${e.name}`:e.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function Of(e){let t=e===null?null:jf(e),n=Ba(t)&&Array.isArray(t.rulebooks)?t.rulebooks:[];return new Map(n.filter(Ff).map((r)=>[r.spec,r]))}function Ff(e){return Ba(e)&&typeof e.spec==="string"&&typeof e.digest==="string"}function Ba(e){return!!e&&typeof e==="object"}function jf(e){try{return JSON.parse(e)}catch{return null}}function Nf(e){return`sha256:${Pf("sha256").update(e).digest("hex")}`}var qa="\r\x1B[2K",Hf="\x1B[?25l",Mf="\x1B[39m",Uf="\x1B[?25h",Gf=100,Bf=0.55,qf=80,Va=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Vf(e){return new Promise((t)=>setTimeout(t,e))}async function Tn(e,t={}){let n=t.output??process.stdout;if(!n.isTTY)return e;let r=t.sleep??Vf,o=!1,i=e.then((a)=>(o=!0,a),(a)=>{throw o=!0,a});if(await Promise.race([i.then(()=>!0),r(Gf).then(()=>!1)]))return i;n.write(Hf);try{for(let a=0;!o;a+=1)n.write(`${qa}${Ia(a*Bf)}${Va[a%Va.length]}${Mf} ${t.loadingMessage??"Loading…"}`),await Promise.race([i,r(qf)]);return await i}finally{n.write(`${qa}${Uf}`)}}async function Kt(e,t,n,r={}){let o=t();if(e)await n();if(e&&o.ready)await Tn(o.ready,r);return o.finish()}import{homedir as Lg}from"node:os";import{stripVTControlCharacters as zf}from"node:util";var In="amp plugins list",Kf=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function za(e){if(!e.ampPluginListOutput)return{platform:"amp",status:"n/a"};let t=zf(e.ampPluginListOutput).split(`
|
|
28
|
+
`).map((n)=>Kf.exec(n)?.[1]).find((n)=>n!==void 0);if(!t)return{platform:"amp",status:"n/a"};if(t!=="active")return{platform:"amp",status:"disabled",method:In,configPath:In,errors:[`Amp personal plugin cc-safety-net is ${t}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:In,configPath:In}}import{existsSync as Jf,readFileSync as Wf}from"node:fs";var Yf=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Zf(e){if(!e||typeof e!=="object"||Array.isArray(e))return[];return Object.values(e).flatMap((t)=>{if(!t||typeof t!=="object"||Array.isArray(t))return[];let n=t,r=n.PreToolUse;if(!Array.isArray(r))return[];return r.flatMap((o)=>{if(!o||typeof o!=="object"||Array.isArray(o))return[];let i=o.hooks;if(!Array.isArray(i))return[];return i.flatMap((s)=>{if(!s||typeof s!=="object"||Array.isArray(s))return[];let a=s.command;if(typeof a!=="string"||!Yf.test(a))return[];return[{command:a,enabled:n.enabled!==!1}]})})})}function Ka(e){let t=Gt(e.homeDir);if(!Jf(t))return{platform:"antigravity-cli",status:"n/a",configPath:t};let n;try{n=Zf(JSON.parse(Wf(t,"utf-8")))}catch(r){return{platform:"antigravity-cli",status:"n/a",configPath:t,errors:[`Failed to parse Antigravity hooks config ${t}: ${r instanceof Error?r.message:String(r)}`]}}if(n.some((r)=>r.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:t};if(n.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:t};return{platform:"antigravity-cli",status:"n/a",configPath:t}}import{join as Ja}from"node:path";import{existsSync as Xf,lstatSync as Qf,readFileSync as em}from"node:fs";function ce(e,t=(n)=>n){if(!Xf(e))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(t(em(e,"utf-8")))}}catch{return{kind:"unreadable"}}}function _(e){try{return Qf(e)}catch{return}}function $n(e,t){let n=_(t);if(!n)return{platform:e,status:"n/a",configPath:t};if(!n.isSymbolicLink()&&n.isDirectory())return;return{platform:e,status:"n/a",configPath:t,errors:[`${t} is a symlink or not a directory; move or remove it before installing`]}}function k(e,t){return typeof e==="object"&&e!==null?e[t]:void 0}var uo="cc-safety-net@cc-marketplace";function Wa(e){return Ja(e,".claude","plugins","installed_plugins.json")}function Ya(e,t){let n=k(k(e,"plugins"),t);return Array.isArray(n)&&n.length>0}function On(e,t){let n=ce(Wa(e));return n.kind==="ok"&&Ya(n.value,t)}function po(e){let t=Wa(e),n=ce(t);if(n.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(n.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Ya(n.value,uo))return{platform:"claude-code",status:"n/a"};let r=Ja(e,".claude","settings.json"),o=ce(r);if(o.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(o.kind==="ok"&&k(k(o.value,"enabledPlugins"),uo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:r,errors:[`${uo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:t}}function Za(e){return po(e.homeDir)}function Xa(e){if(!e.codexPluginListOutput)return{platform:"codex",status:"n/a"};let t=e.codexPluginListOutput.split(`
|
|
29
|
+
`).find((n)=>n.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!t)return{platform:"codex",status:"n/a"};if(!t.includes("installed,"))return{platform:"codex",status:"n/a"};if(!t.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as Hn,readdirSync as tm,readFileSync as nm}from"node:fs";import{join as M}from"node:path";var de="cc-safety-net@cc-marketplace",Fn=["cc-marketplace","cc-safety-net"],Qa=["_direct","copilot-safety-net"],el=["cc-marketplace","safety-net"],tl="safety-net@cc-marketplace";function jn(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${n}([^a-z0-9-]|$)`,"m").test(e??"")}function nl(e){return jn(e,"cc-safety-net@cc-marketplace")}function rl(e){return jn(e,"cc-marketplace")}function ol(e){return jn(e,"copilot-safety-net")}function il(e){return jn(e,"safety-net@cc-marketplace")}function K(e){let t="",n=0,r=!1,o=!1,i=-1;while(n<e.length){let s=e[n],a=e[n+1];if(o){t+=s,o=!1,n++;continue}if(s==='"'&&!r){r=!0,i=-1,t+=s,n++;continue}if(s==='"'&&r){r=!1,t+=s,n++;continue}if(s==="\\"&&r){o=!0,t+=s,n++;continue}if(r){t+=s,n++;continue}if(s==="/"&&a==="/"){while(n<e.length&&e[n]!==`
|
|
30
|
+
`)n++;continue}if(s==="/"&&a==="*"){n+=2;while(n<e.length-1){if(e[n]==="*"&&e[n+1]==="/"){n+=2;break}n++}continue}if(s===","){i=t.length,t+=s,n++;continue}if(s==="}"||s==="]"){if(i!==-1){let l=t.slice(i+1);if(/^\s*$/.test(l))t=t.slice(0,i)+l}i=-1,t+=s,n++;continue}if(!/\s/.test(s))i=-1;t+=s,n++}return t}function fo(e){if(!e?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(e)}function al(e,t){if(!e)return null;let n=e.match(/(\d+)\.(\d+)\.(\d+)/);if(!n)return null;let r=[Number(n[1]),Number(n[2]),Number(n[3])];for(let o=0;o<t.length;o++){let i=r[o]??0,s=t[o]??0;if(i!==s)return i>s}return!0}function rm(e){return al(e,[0,0,422])}function om(e){return al(e,[1,0,8])}function Jt(e){return process.env.COPILOT_HOME||M(e,".copilot")}function mo(e){return(e.hooks?.preToolUse??[]).some((n)=>{if(n.type!=="command")return!1;return fo(n.command)||fo(n.bash)||fo(n.powershell)})}function Nn(e){return e===void 0||typeof e==="string"}function im(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e;if(t.disableAllHooks!==void 0&&typeof t.disableAllHooks!=="boolean")return!1;if(t.hooks===void 0)return!0;if(!t.hooks||typeof t.hooks!=="object"||Array.isArray(t.hooks))return!1;let n=t.hooks.preToolUse;if(n===void 0)return!0;return Array.isArray(n)&&n.every((r)=>r!==null&&typeof r==="object"&&!Array.isArray(r)&&Nn(r.type)&&Nn(r.command)&&Nn(r.bash)&&Nn(r.powershell))}function go(e,t){try{let n=JSON.parse(K(nm(e,"utf-8")));if(!im(n)){t?.push(`Invalid hook config ${e}: hooks.preToolUse must be an array of hook objects`);return}return n}catch(n){t?.push(`Failed to parse ${e}: ${n instanceof Error?n.message:String(n)}`);return}}function ll(e,t){try{return tm(e).filter((n)=>n.endsWith(".json")).sort((n,r)=>n.localeCompare(r))}catch(n){return t?.push(`Failed to read ${e}: ${n instanceof Error?n.message:String(n)}`),[]}}function sm(e,t){if(!Hn(e))return[];let n=[];for(let r of ll(e,t)){let o=M(e,r),i=go(o,t);if(i&&mo(i))n.push(o)}return n}function mt(e,t){if(!Hn(e))return;let n=go(e,t);if(!n)return;return{path:e,config:n}}function sl(e,t,n,r){if(t){e.push(`GitHub Copilot CLI ${t} does not support ${n}; requires ${r}+`);return}e.push(`GitHub Copilot CLI version unavailable; skipping ${n} because it requires ${r}+`)}function am(e){for(let t of e){if(t?.config.disableAllHooks===!0)return t.path;if(t?.config.disableAllHooks===!1)return}return}function lm(e,t,n,r){let o=Jt(e),i=M(t,".github","hooks"),s=M(o,"hooks"),a=M(t,".github","copilot"),l=M(t,".claude"),c=om(n),d=c===!0?r:void 0,m=[mt(M(a,"settings.local.json"),d),mt(M(a,"settings.json"),d),mt(M(l,"settings.local.json"),d),mt(M(l,"settings.json"),d)],g=[mt(M(o,"settings.json"),d),mt(M(o,"config.json"),d)];if(c!==!1){let v=am([...m,...g]);if(v){if(c===null)r.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${v} as active`);return{activeConfigPaths:[],disabledBy:v}}}let u=sm(i,r),p=rm(n),f=p===!0?r:void 0,b=Hn(s)?ll(s,f):[],L=[];for(let v of b){let P=M(s,v),ne=go(P,f);if(ne&&mo(ne))L.push(P)}if(p!==!0&&L.length>0)sl(r,n,`user hook files in ${s}`,"0.0.422"),L.length=0;let h=[];for(let v of[...m,...g]){if(!v)continue;if(!mo(v.config))continue;if(c===!0){h.push(v);continue}sl(r,n,"inline hook definitions in Copilot config files","1.0.8");break}let R=(v)=>v.filter((P)=>!!P&&h.includes(P)).map((P)=>P.path);return{activeConfigPaths:[...R(m),...u,...R(g),...L]}}function cl(e){let t=[],n=lm(e.homeDir,e.cwd,e.copilotCliVersion,t);if(n.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:n.disabledBy,configPaths:[n.disabledBy],errors:t.length>0?t:void 0};let r=Jt(e.homeDir),o=M(r,"installed-plugins",...Fn),i=Hn(o),s=M(r,"settings.json"),a=ce(s,K);if(i&&a.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(i&&a.kind==="ok"&&k(k(a.value,"enabledPlugins"),de)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:s,errors:[`${de} is installed but not enabled in Copilot CLI`]};if(i||n.activeConfigPaths.length>0){let l=i,c=n.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:l?"plugin config":"hook config",configPath:c??(l?o:void 0),configPaths:n.activeConfigPaths.length>0?n.activeConfigPaths:void 0,errors:t.length>0?t:void 0}}return{platform:"copilot-cli",status:"n/a",errors:t.length>0?t:void 0}}import{existsSync as vm,readFileSync as bm}from"node:fs";import{existsSync as dl,mkdirSync as um,readFileSync as pm}from"node:fs";import{dirname as fm,join as mm}from"node:path";import{renameSync as cm,writeFileSync as dm}from"node:fs";function O(e,t){let n=`${e}.${process.pid}.tmp`;dm(n,t),cm(n,e)}var Wt="npx -y cc-safety-net hook --cursor",ul=30;function Un(e){return mm(e,".cursor","hooks.json")}function Ke(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function ho(){return{command:Wt,timeout:ul,failClosed:!0}}function Mn(e){return Ke(e)&&e.command===Wt}function gm(e){return Object.keys(e).length===3&&e.command===Wt&&e.timeout===ul&&e.failClosed===!0}function hm(e){try{return JSON.parse(pm(e,"utf-8"))}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${e}: ${t.message}`);throw t}}function pl(e){let t=hm(e);if(!Ke(t))throw Error(`Cursor hooks config ${e} must be a JSON object`);if(t.version!==1)throw Error(`Cursor hooks config ${e} must set "version": 1`);if(t.hooks!==void 0&&!Ke(t.hooks))throw Error(`Cursor hooks config ${e} "hooks" must be an object`);let n=Ke(t.hooks)?t.hooks.preToolUse:void 0;if(n!==void 0&&!Array.isArray(n))throw Error(`Cursor hooks config ${e} "hooks.preToolUse" must be an array`);return t}function fl(e){let t=Ke(e.hooks)?e.hooks.preToolUse:void 0;return Array.isArray(t)?t:[]}function ym(e){if(!e.some(Mn))return[...e,ho()];return e.reduce((t,n)=>{if(!Mn(n))return t.result.push(n),t;if(!t.inserted)t.result.push(ho()),t.inserted=!0;return t},{result:[],inserted:!1}).result}function ml(e,t,n){let r=Ke(t.hooks)?t.hooks:{},o={...t,hooks:{...r,preToolUse:n}};O(e,`${JSON.stringify(o,null,2)}
|
|
31
|
+
`)}function gl(e){let t=Un(e);if(!dl(t))return um(fm(t),{recursive:!0}),O(t,`${JSON.stringify({version:1,hooks:{preToolUse:[ho()]}},null,2)}
|
|
32
|
+
`),{path:t,alreadyInstalled:!1};let n=pl(t),r=fl(n),o=r.filter(Mn);if(Ke(n.hooks)&&Array.isArray(n.hooks.preToolUse)&&o.length===1&&o[0]!==void 0&&gm(o[0]))return{path:t,alreadyInstalled:!0};return ml(t,n,ym(r)),{path:t,alreadyInstalled:!1}}function hl(e){let t=Un(e);if(!dl(t))return{path:t,alreadyInstalled:!1};let n=pl(t),r=fl(n),o=r.filter((i)=>!Mn(i));if(o.length===r.length)return{path:t,alreadyInstalled:!1};return ml(t,n,o),{path:t,alreadyInstalled:!0}}function Lm(e){if(!e||typeof e!=="object"||Array.isArray(e))return[];let t=e.hooks;if(!t||typeof t!=="object"||Array.isArray(t))return[];let n=t.preToolUse;if(!Array.isArray(n))return[];return n.filter((r)=>!!r&&typeof r==="object"&&!Array.isArray(r)&&r.command===Wt)}function wm(e){let t=[];if(e.length>1)t.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let n=e[0];if(n&&n.failClosed!==!0)t.push('Managed hook is missing "failClosed": true; reinstall to repair');if(n&&n.timeout!==30)t.push('Managed hook "timeout" is not 30; reinstall to repair');return t}function yl(e){let t=Un(e.homeDir);if(!vm(t))return{platform:"cursor",status:"n/a",configPath:t};let n;try{n=JSON.parse(bm(t,"utf-8"))}catch(i){return{platform:"cursor",status:"n/a",configPath:t,errors:[`Failed to parse Cursor hooks config ${t}: ${i instanceof Error?i.message:String(i)}`]}}let r=Lm(n);if(r.length===0)return{platform:"cursor",status:"n/a",configPath:t};let o=wm(r);return{platform:"cursor",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{existsSync as km}from"node:fs";import{join as yo}from"node:path";var vo="gemini-safety-net";function bo(e){let t=yo(e,".gemini","extensions"),n=yo(t,vo);if(!km(n))return{platform:"gemini-cli",status:"n/a"};let r=yo(t,"extension-enablement.json"),o=ce(r);if(o.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let i=o.kind==="ok"?k(k(o.value,vo),"overrides"):void 0;if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:r,errors:[`${vo} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:n}}function vl(e){return bo(e.homeDir)}import{existsSync as Rm,readFileSync as Pm}from"node:fs";import{existsSync as Ll,mkdirSync as xm,readFileSync as wl,rmSync as Cm}from"node:fs";import{dirname as Sm,join as bl}from"node:path";var Yt="npx -y cc-safety-net hook --grok-build",qn=30;function Vn(e){return bl(process.env.GROK_HOME??bl(e,".grok"),"hooks","cc-safety-net.json")}function Je(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Gn(){return{hooks:[{type:"command",command:Yt,timeout:qn}]}}function kl(e){return Je(e)&&e.command===Yt}function xl(e){return e.flatMap((t)=>{if(!Je(t)||!Array.isArray(t.hooks))return[t];let n=t.hooks.filter((r)=>!kl(r));if(n.length===t.hooks.length)return[t];return n.length===0?[]:[{...t,hooks:n}]})}function Cl(e){try{let t=JSON.parse(e);return Je(t)?t:null}catch{return null}}function Sl(e){let t=Je(e.hooks)?e.hooks.PreToolUse:void 0;return Array.isArray(t)?t:[]}function Bn(e,t,n){let r=Je(t.hooks)?t.hooks:{};O(e,`${JSON.stringify({...t,hooks:{...r,PreToolUse:n}},null,2)}
|
|
33
|
+
`)}function Rl(e){let t=Vn(e);if(!Ll(t))return xm(Sm(t),{recursive:!0}),Bn(t,{},[Gn()]),{path:t,alreadyInstalled:!1};let n=Cl(wl(t,"utf-8"));if(!n)return Bn(t,{},[Gn()]),{path:t,alreadyInstalled:!1};let r=Sl(n),o=r.filter((i)=>Je(i)&&Array.isArray(i.hooks)&&i.hooks.some(kl));if(o.length===1&&JSON.stringify(o[0])===JSON.stringify(Gn()))return{path:t,alreadyInstalled:!0};return Bn(t,n,[...xl(r),Gn()]),{path:t,alreadyInstalled:!1}}function Pl(e){let t=Vn(e);if(!Ll(t))return{path:t,alreadyInstalled:!1};let n=Cl(wl(t,"utf-8"));if(!n)return{path:t,alreadyInstalled:!1};let r=Sl(n),o=xl(r);if(JSON.stringify(o)===JSON.stringify(r))return{path:t,alreadyInstalled:!1};let i=Je(n.hooks)?n.hooks:{};if(o.length===0&&Object.keys(n).length===1&&Object.keys(i).length===1)return Cm(t),{path:t,alreadyInstalled:!0};return Bn(t,n,o),{path:t,alreadyInstalled:!0}}function Zt(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Dm(e){if(!Zt(e)||!Zt(e.hooks))return[];let t=e.hooks.PreToolUse;if(!Array.isArray(t))return[];return t.filter((n)=>Zt(n)&&Array.isArray(n.hooks)&&n.hooks.some((r)=>Zt(r)&&r.command===Yt))}function Am(e){let n=(Array.isArray(e.hooks)?e.hooks.filter(Zt):[]).find((r)=>r.command===Yt);return[...e.matcher===void 0||e.matcher===""||e.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...n?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...n?.timeout===qn?[]:[`Managed hook "timeout" is not ${qn}; reinstall to repair`]]}function Dl(e){let t=Vn(e.homeDir);if(!Rm(t))return{platform:"grok-build",status:"n/a",configPath:t};let n;try{n=JSON.parse(Pm(t,"utf-8"))}catch(i){return{platform:"grok-build",status:"n/a",configPath:t,errors:[`Failed to parse Grok Build hooks config ${t}: ${i instanceof Error?i.message:String(i)}`]}}let r=Dm(n)[0];if(!r)return{platform:"grok-build",status:"n/a",configPath:t};let o=Am(r);return{platform:"grok-build",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{readFileSync as jl}from"node:fs";import{join as Nl}from"node:path";var Q="cc-safety-net",Al="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent";function El(e){return`# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent
|
|
34
34
|
# version: ${e}
|
|
35
|
-
`}function
|
|
35
|
+
`}function Em(e){return`${El(e)}name: cc-safety-net
|
|
36
36
|
version: "${e}"
|
|
37
37
|
description: "Block destructive commands and secret-file access before Hermes runs a tool."
|
|
38
38
|
author: "cc-safety-net"
|
|
39
39
|
provides_hooks:
|
|
40
40
|
- pre_tool_call
|
|
41
|
-
`}function
|
|
41
|
+
`}function _m(e){return`${El(e)}"""CC Safety Net guard for Hermes Agent.
|
|
42
42
|
|
|
43
43
|
Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
|
|
44
44
|
adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
|
|
@@ -120,6 +120,10 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
120
120
|
)
|
|
121
121
|
|
|
122
122
|
try:
|
|
123
|
+
if os.name == "nt":
|
|
124
|
+
launch_options = {}
|
|
125
|
+
else:
|
|
126
|
+
launch_options = {"start_new_session": True}
|
|
123
127
|
process = subprocess.Popen(
|
|
124
128
|
[executable] + ANALYZER[1:],
|
|
125
129
|
stdin=subprocess.PIPE,
|
|
@@ -136,8 +140,9 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
136
140
|
# still the real Hermes working directory, which the analysis needs.
|
|
137
141
|
cwd=os.path.expanduser("~"),
|
|
138
142
|
# Own process group so the timeout below can kill the whole tree: npx's descendants
|
|
139
|
-
# outlive a kill aimed at npx alone and keep holding the pipes captured here.
|
|
140
|
-
|
|
143
|
+
# outlive a kill aimed at npx alone and keep holding the pipes captured here. Windows
|
|
144
|
+
# uses taskkill's process-tree traversal instead because sessions are POSIX-only.
|
|
145
|
+
**launch_options,
|
|
141
146
|
)
|
|
142
147
|
except OSError as error:
|
|
143
148
|
return _block("analysis could not start (%s)." % error)
|
|
@@ -146,12 +151,31 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
146
151
|
stdout, _ = process.communicate(payload, timeout=TIMEOUT_SECONDS)
|
|
147
152
|
except subprocess.TimeoutExpired:
|
|
148
153
|
try:
|
|
149
|
-
os.
|
|
150
|
-
|
|
154
|
+
if os.name == "nt":
|
|
155
|
+
system_root = os.environ.get("SystemRoot")
|
|
156
|
+
if not system_root:
|
|
157
|
+
raise OSError("SystemRoot is unavailable")
|
|
158
|
+
subprocess.run(
|
|
159
|
+
[
|
|
160
|
+
os.path.join(system_root, "System32", "taskkill.exe"),
|
|
161
|
+
"/PID",
|
|
162
|
+
str(process.pid),
|
|
163
|
+
"/T",
|
|
164
|
+
"/F",
|
|
165
|
+
],
|
|
166
|
+
stdin=subprocess.DEVNULL,
|
|
167
|
+
stdout=subprocess.DEVNULL,
|
|
168
|
+
stderr=subprocess.DEVNULL,
|
|
169
|
+
timeout=1,
|
|
170
|
+
check=False,
|
|
171
|
+
)
|
|
172
|
+
else:
|
|
173
|
+
os.killpg(process.pid, signal.SIGKILL)
|
|
174
|
+
except (OSError, subprocess.SubprocessError):
|
|
151
175
|
pass
|
|
152
176
|
try:
|
|
153
|
-
process.communicate(timeout=
|
|
154
|
-
except subprocess.
|
|
177
|
+
process.communicate(timeout=1)
|
|
178
|
+
except (OSError, subprocess.SubprocessError):
|
|
155
179
|
pass
|
|
156
180
|
return _block("analysis timed out after %ss." % TIMEOUT_SECONDS)
|
|
157
181
|
|
|
@@ -176,86 +200,86 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
176
200
|
|
|
177
201
|
def register(ctx):
|
|
178
202
|
ctx.register_hook("pre_tool_call", _pre_tool_call)
|
|
179
|
-
`}function Xt(e){return[{name:"__init__.py",content:
|
|
180
|
-
`)}function Do(e){let t={stdout:"",stderr:""};return e.stdout.setEncoding("utf-8"),e.stderr.setEncoding("utf-8"),e.stdout.on("data",(n)=>{t.stdout+=n}),e.stderr.on("data",(n)=>{t.stderr+=n}),t}function ue(e,t){return new Promise((n,r)=>{let o=ze([...e],process.env),i=
|
|
203
|
+
`}function Xt(e){return[{name:"__init__.py",content:_m(e)},{name:"plugin.yaml",content:Em(e)}]}import{mkdirSync as Tm,readdirSync as Im,readFileSync as $m,rmSync as Lo}from"node:fs";import{join as We}from"node:path";var Om="__pycache__";function wo(e){let t=process.env.HERMES_HOME?.trim();return t?t:We(e,".hermes")}function ko(e){return We(wo(e),"plugins",Q)}function xo(e){return e.startsWith(Al)}function Co(e,t){let n=ko(e),r=_(n);if(r&&(r.isSymbolicLink()||!r.isDirectory()))throw Error(`Refusing to ${t} ${n}: not a regular directory. Move or remove it and rerun ${t==="install"?"install":"uninstall"} --hermes-agent.`);return n}function _l(e,t){let n=_(e);if(!n)return;if(n.isSymbolicLink()||!n.isFile())throw Error(`Refusing to ${t} ${e}: not a regular file. Move or remove it.`);let r=$m(e,"utf-8");if(!xo(r))throw Error(`Refusing to ${t} unmanaged file at ${e}. Move or remove it.`);return r}function Tl(e){let t=Co(e,"install"),n=Xt(I());if(n.map((o)=>_l(We(t,o.name),"overwrite")).every((o,i)=>o===n[i]?.content))return{path:t,alreadyInstalled:!0};return Tm(t,{recursive:!0}),n.forEach((o)=>{O(We(t,o.name),o.content)}),{path:t,alreadyInstalled:!1}}function So(e){let t=Co(e,"remove");if(!_(t))return[];return Xt(I()).filter((n)=>_l(We(t,n.name),"remove")!==void 0)}function Il(e){let t=Co(e,"remove");if(!_(t))return{path:t,alreadyInstalled:!1};let n=So(e);if(n.forEach((r)=>{Lo(We(t,r.name))}),Lo(We(t,Om),{recursive:!0,force:!0}),Im(t).length===0)Lo(t,{recursive:!0});return{path:t,alreadyInstalled:n.length>0}}var zn="hermes-agent",$l=/^([^\s#][^:]*):/,Fm=/^\s+([A-Za-z_][\w-]*):/,Ol=/^\s+-\s*(.*)$/;function jm(e){return e.trim().replace(/^(["'])(.*)\1$/,"$2")}function Nm(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>$l.exec(i)?.[1]?.trim()==="plugins");if(n===-1)return[];let r=t.slice(n+1),o=r.findIndex((i)=>$l.test(i));return o===-1?r:r.slice(0,o)}function Fl(e,t){let n=Nm(e),r=n.findIndex((s)=>Fm.exec(s)?.[1]===t);if(r===-1)return[];let o=n.slice(r+1),i=o.findIndex((s)=>!Ol.test(s));return(i===-1?o:o.slice(0,i)).map((s)=>jm(Ol.exec(s)?.[1]??""))}function Hm(e){try{return jl(Nl(wo(e),"config.yaml"),"utf-8")}catch{return}}function Ro(e){let t=Hm(e)??"";return Fl(t,"enabled").includes(Q)&&!Fl(t,"disabled").includes(Q)}function Hl(e){return/^# version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function Mm(e,t){let n=_(e);if(!n)return{error:`${t.name} is missing from ${e}; run install --hermes-agent`};if(n.isSymbolicLink()||!n.isFile())return{error:`${e} is a symlink or not a regular file; move or remove it`};try{let r=jl(e,"utf-8");if(!xo(r))return{error:`Unmanaged ${t.name} occupies ${e}; move or remove it`};if(Hl(r)===I()&&r!==t.content)return{error:`Modified ${t.name} occupies ${e}; run install --hermes-agent to restore it`};return{content:r}}catch(r){return{error:`Failed to read ${e}: ${r instanceof Error?r.message:String(r)}`}}}function Ml(e){let t=ko(e.homeDir),n=$n(zn,t);if(n)return n;let r=Xt(I()).map((a)=>Mm(Nl(t,a.name),a)),o=r.flatMap((a)=>("error"in a)?[a.error]:[]);if(o.length>0)return{platform:zn,status:"n/a",configPath:t,errors:o};let i=r.some((a)=>("content"in a)&&Hl(a.content)!==I()),s=i?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Ro(e.homeDir))return{platform:zn,status:"disabled",method:"plugin directory",configPath:t,errors:[`${Q} is not enabled in Hermes; run \`hermes plugins enable ${Q}\``,...s]};return{platform:zn,status:"configured",method:"plugin directory",configPath:t,errors:i?s:void 0}}import{existsSync as Um,readFileSync as Gm}from"node:fs";import{join as Ul}from"node:path";var Bm=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function qm(e){return Ul(process.env.KIMI_CODE_HOME||Ul(e,".kimi-code"),"config.toml")}function Qt(e){let t=qm(e.homeDir);if(!Um(t))return{platform:"kimi-code",status:"n/a",configPath:t};try{if(!Bm.test(Gm(t,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:t}}catch(n){return{platform:"kimi-code",status:"n/a",configPath:t,errors:[`Failed to read ${t}: ${n instanceof Error?n.message:String(n)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:t}}import{readFileSync as Zl}from"node:fs";import{join as tn}from"node:path";var A="cc-safety-net",ee="index.js",gt="openclaw.plugin.json",ht="package.json";var Kn="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as Km,lstatSync as Jm,readdirSync as Wm,readFileSync as Ym}from"node:fs";import{dirname as ql,join as Ie}from"node:path";import{fileURLToPath as Zm}from"node:url";import{spawn as Vm}from"node:child_process";function zm(e){return e.join(" ")}function Po(e,t,n){return[`Failed to run ${zm(e)}${t===null?"":` (exit ${t})`}.`,n.trim()].filter(Boolean).join(`
|
|
204
|
+
`)}function Do(e){let t={stdout:"",stderr:""};return e.stdout.setEncoding("utf-8"),e.stderr.setEncoding("utf-8"),e.stdout.on("data",(n)=>{t.stdout+=n}),e.stderr.on("data",(n)=>{t.stderr+=n}),t}function ue(e,t){return new Promise((n,r)=>{let o=ze([...e],process.env),i=Vm(o.cmd,o.args,{stdio:["ignore","pipe","pipe"]}),s=Do(i),a=()=>[s.stdout,s.stderr].filter(Boolean).join(`
|
|
181
205
|
`),l=t?.timeoutMs??120000,c=setTimeout(()=>{i.kill(),r(Error(Po(e,null,`Timed out after ${l}ms.
|
|
182
206
|
${a()}`.trim())))},l);i.on("error",(d)=>{clearTimeout(c),r(Error(Po(e,null,`${d.message}
|
|
183
|
-
${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(Po(e,d,a())));return}n(t?.stdoutOnly?s.stdout:a())})})}async function Ao(e){for(let t of e)await ue(t)}async function Gl(e){for(let t of e)try{await ue(t)}catch(n){console.warn(n instanceof Error?n.message:String(n))}}var Bl=Ie("openclaw",A),
|
|
207
|
+
${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(Po(e,d,a())));return}n(t?.stdoutOnly?s.stdout:a())})})}async function Ao(e){for(let t of e)await ue(t)}async function Gl(e){for(let t of e)try{await ue(t)}catch(n){console.warn(n instanceof Error?n.message:String(n))}}var Bl=Ie("openclaw",A),Xm=[ee,gt,ht];function Eo(e,t){if(e==="~")return t;if(e.startsWith("~/")||e.startsWith("~\\"))return Ie(t,e.slice(2));return e}function Vl(e){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return Eo(t,e);let n=process.env.OPENCLAW_CONFIG_PATH?.trim();return n?ql(Eo(n,e)):Ie(e,".openclaw")}function zl(e){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?Eo(t,e):Ie(Vl(e),"openclaw.json")}function _o(e){return Ie(Vl(e),"extensions",A)}function Qm(e){let t=Wm(e);if(t.length===0)return!0;if(t.some((o)=>!Xm.includes(o)))return!1;let n=Ie(e,ee),r=_(n);return r!==void 0&&!r.isSymbolicLink()&&r.isFile()&&Ym(n,"utf-8").startsWith(Kn)}function To(e){let t=_o(e),n=_(t);if(!n)return;if(!n.isSymbolicLink()&&n.isDirectory()&&Qm(t))return;throw Error(`Refusing to modify ${t}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Kl(){let e=ql(Zm(import.meta.url));return[Ie(e,"..",Bl),Ie(e,"..","..","..","dist",Bl)]}function Io(e=Kl()){return e.find((t)=>Km(t)&&Jm(t).isDirectory())}function eg(e=Kl()){let t=Io(e);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function Jl(e=eg()){return[["openclaw","plugins","install",e,"--force"],["openclaw","plugins","enable",A]]}function tg(e){let t=(()=>{try{return JSON.parse(e)}catch{return}})(),n=k(k(t,"plugin"),"status");return typeof n==="string"?n:void 0}async function Wl(){let e=tg(await ue(["openclaw","plugins","inspect",A,"--runtime","--json"],{stdoutOnly:!0}));if(e==="loaded")return;throw Error(`${e===void 0?`The ${A} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${A} plugin with status "${e}".`} Run \`openclaw plugins inspect ${A} --runtime\` for details.`)}var Jn="openclaw",en=`run \`openclaw plugins enable ${A}\``;function yt(e,t){let n=tn(e,t),r=_(n);if(!r)return{error:`${t} is missing from ${n}; run install --openclaw`};if(r.isSymbolicLink()||!r.isFile())return{error:`${n} is a symlink or not a regular file; move or remove it`};try{return{content:Zl(n,"utf-8")}}catch(o){return{error:`Failed to read ${n}: ${o instanceof Error?o.message:String(o)}`}}}function Xl(e){try{return JSON.parse(K(e))}catch{return}}function ng(e){let t=yt(e,gt);if("error"in t)return t.error;if(k(Xl(t.content),"id")===A)return;return`${tn(e,gt)} is not a valid ${A} manifest; run install --openclaw`}function rg(e){let t=yt(e,ht);if("error"in t)return t.error;let n=k(k(Xl(t.content),"openclaw"),"extensions");if(Array.isArray(n)&&n.includes(`./${ee}`))return;return`${tn(e,ht)} does not point OpenClaw at ${ee}; run install --openclaw`}function Yl(e){return Array.isArray(e)?e.filter((t)=>typeof t==="string"):[]}function og(e){let t=zl(e);if(!_(t))return`${A} is not enabled; ${en}`;let n=(()=>{try{return JSON.parse(K(Zl(t,"utf-8")))}catch{return}})();if(n===void 0)return`Failed to read ${t}; fix it, then ${en}`;let r=k(n,"plugins");if(k(r,"enabled")===!1)return`plugins.enabled is false in ${t}; no OpenClaw plugin loads`;let o=k(k(k(r,"entries"),A),"enabled");if(Yl(k(r,"deny")).includes(A)||o===!1)return`${A} is disabled in ${t}; ${en}`;let i=Yl(k(r,"allow"));if(i.length>0&&!i.includes(A))return`plugins.allow in ${t} does not list ${A}; add it, then ${en}`;if(i.includes(A)||o===!0)return;return`${A} is not enabled; ${en}`}function Ql(e){return/^\/\/ version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function ig(e,t,n){if(n===void 0)return[];let r=yt(n,ee);if("error"in r||Ql(r.content)!==t)return[];return[ee,gt,ht].flatMap((o)=>{let i=yt(e,o),s=yt(n,o);if("error"in i||"error"in s||i.content===s.content)return[];return[`Modified ${o} occupies ${tn(e,o)}; run install --openclaw to restore it`]})}function ec(e){let t=_o(e.homeDir),n=$n(Jn,t);if(n)return n;let r=yt(t,ee),i=["error"in r?r.error:r.content.startsWith(Kn)?void 0:`Unmanaged ${ee} occupies ${tn(t,ee)}; move or remove it`,ng(t),rg(t)].filter((d)=>d!==void 0),s="content"in r?Ql(r.content):void 0,a=i.length>0?i:ig(t,s,Io());if(a.length>0)return{platform:Jn,status:"n/a",configPath:t,errors:a};let l=s===I()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],c=og(e.homeDir);if(c)return{platform:Jn,status:"disabled",method:"plugin directory",configPath:t,errors:[c,...l]};return{platform:Jn,status:"configured",method:"plugin directory",configPath:t,errors:l.length>0?l:void 0}}import{existsSync as hg,readFileSync as yg}from"node:fs";import{join as vg}from"node:path";import{existsSync as $o,readFileSync as ic,rmSync as ag}from"node:fs";import{join as ke}from"node:path";import{pathToFileURL as lg}from"node:url";function tc(e){return e!==void 0&&/\s/.test(e)}function sg(e,t,n){let r=t+1,o=!1;while(r<e.length){let i=e[r];if(o){o=!1,r++;continue}if(i==="\\"){o=!0,r++;continue}if(i==='"')return r+1;r++}throw Error(n)}function Wn(e,t,n){let r=e[t],o=r==="["?"]":"}",i=0,s=t;while(s<e.length){let a=n.skipComment?.(e,s)??s;if(a!==s){s=a;continue}if(e[s]==='"'){s=sg(e,s,n.stringError);continue}if(e[s]===r)i++;if(e[s]===o){if(i--,i===0)return s}s++}throw Error(n.bracketError)}function nc(e,t){let n=e.lastIndexOf(`
|
|
184
208
|
`,t)+1;return/^[ \t]*/.exec(e.slice(n))?.[0]??""}function Yn(e,t){let{start:n,end:r,end:o}=t;while(tc(e[o]))o++;if(e[o]===","){if(r=o+1,e[r]===`
|
|
185
209
|
`)r++;return`${e.slice(0,n)}${e.slice(r)}`}o=t.start-1;while(tc(e[o]))o--;if(e[o]===","){n=o;let i=e.lastIndexOf(`
|
|
186
|
-
`,n-1);if(i!==-1&&/^\s*$/.test(e.slice(i+1,n)))n=i}return`${e.slice(0,n)}${e.slice(r)}`}var Zn="cc-safety-net",sc=`${Zn}@latest`,ac=["opencode.json","opencode.jsonc"],rc="CCSafetyNetPlugin";function Xn(e){return ke(process.env.XDG_CONFIG_HOME||ke(e,".config"),"opencode")}function
|
|
187
|
-
`,t+2);return n===-1?e.length:n+1}if(e[t]==="/"&&e[t+1]==="*"){let n=e.indexOf("*/",t+2);return n===-1?e.length:n+2}return t}function oc(e,t){let n=t;while(n<e.length){if(/\s/.test(e[n]??"")){n++;continue}let r=Qn(e,n);if(r===n)return n;n=r}return n}function dc(e,t){let n=t+1,r=!1;while(n<e.length){if(r){r=!1,n++;continue}if(e[n]==="\\"){r=!0,n++;continue}if(e[n]==='"')return n+1;n++}throw Error("Unterminated string in OpenCode config")}function uc(e,t,n){return JSON.parse(e.slice(t,n))}function
|
|
188
|
-
`));return{path:n??sg(e),alreadyInstalled:!1}}function mc(e){let t=[],n=Xn(e.homeDir),r=["opencode.json","opencode.jsonc"];for(let o of r){let i=gg(n,o);if(fg(i))try{let s=mg(i,"utf-8"),a=K(s);if((JSON.parse(a).plugin??[]).some((m)=>m.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:i,errors:t.length>0?t:void 0}}catch(s){t.push(`Failed to parse ${o}: ${s instanceof Error?s.message:String(s)}`)}}return{platform:"opencode",status:"n/a",errors:t.length>0?t:void 0}}import{join as hg}from"node:path";function Fo(e){return hg(e,".pi","agent","settings.json")}function jo(e){if(typeof e!=="string")return!1;return e==="npm:cc-safety-net"||e.startsWith("npm:cc-safety-net@")}function gc(e){let t=Fo(e.homeDir),n=ce(t);if(n.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(n.kind==="missing")return{platform:"pi",status:"n/a"};let r=k(n.value,"packages");if(!Array.isArray(r))return{platform:"pi",status:"n/a"};let o=r.find((a)=>jo(typeof a==="string"?a:k(a,"source")));if(o===void 0)return{platform:"pi",status:"n/a"};let i=k(o,"extensions");if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:t,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:t}}var vg={amp:za,"antigravity-cli":Ka,"claude-code":Za,codex:Xa,"copilot-cli":cl,cursor:yl,"gemini-cli":vl,"grok-build":Dl,"hermes-agent":Ml,"kimi-code":Qt,openclaw:ec,opencode:mc,pi:gc};function vt(e,t){let n={...t,cwd:e,homeDir:t?.homeDir??yg()};return wn.map((r)=>bg(vg[r](n)))}function bg(e){if(e.status==="not-inspected")return{platform:e.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:e.platform,detected:e.status!=="n/a",configured:e.status==="configured",inspectionStatus:e.status!=="n/a"?"verified":e.errors&&e.errors.length>0?"failed":"not-applicable",method:e.method,configPath:e.configPath,configPaths:e.configPaths,errors:e.errors}}import{tmpdir as Lg}from"node:os";import{join as wg}from"node:path";var kg=Object.freeze([{command:"git reset --hard",description:"git reset --hard",expectBlocked:!0},{command:"rm -rf /",description:"rm -rf /",expectBlocked:!0},{command:"rm -rf ./node_modules",description:"rm in cwd (safe)",expectBlocked:!1}]),xg=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),Cg={strict:!1,paranoidRm:!1,paranoidInterpreters:!1,worktreeMode:!1,effectiveLevel:"standard",capabilities:{fail_closed:{enabled:!1,source:"preset",sources:[]},paranoid_rm:{enabled:!1,source:"preset",sources:[]},paranoid_interpreters:{enabled:!1,source:"preset",sources:[]}}};function hc(){let e=wg(Lg(),"cc-safety-net-self-test"),t=kg.map((n)=>{let r=bn(st("self-test",{command:n.command},{kind:"command",shell:"auto"},{configCwd:e,executionCwd:e},n.command),{guard:{dependencies:{loadPolicySnapshot:()=>xg,getModes:()=>Cg,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),o=n.expectBlocked?"blocked":"allowed",i=r.decision.kind==="deny"?"blocked":"allowed";return{command:n.command,description:n.description,expected:o,actual:i,passed:o===i,reason:r.decision.kind==="deny"?r.decision.reason:void 0,ruleId:r.decision.kind==="deny"?r.decision.ruleId:void 0}});return{passed:t.filter((n)=>n.passed).length,failed:t.filter((n)=>!n.passed).length,total:t.length,results:t}}function No(e){let t=E({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},e);if(fe(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function yc(e={}){let t=await Kt(!e.json,()=>{let n=Sg(e);return{ready:n,finish:()=>n}},()=>zt(),{loadingMessage:"Checking system status…"});if(e.json)console.log(JSON.stringify(t,null,2));else Rg(t);return t.engineSelfTest.failed>0||t.findings.some((n)=>n.severity==="error")?1:0}async function Sg(e){let t=e.cwd??process.cwd(),n=await qt(),r=vt(t,{ampPluginListOutput:n.ampPluginListOutput,codexPluginListOutput:n.codexPluginListOutput,copilotCliVersion:n.versions["copilot-cli"]}),o=ca(t),i=da(),s=z({cwd:t}),a=s.policy,l=ye(a),c=Ue(a,l.capabilities),d=Rn(7),m=Ua(t),g=e.skipUpdateCheck?{currentVersion:I(),latestVersion:null,updateAvailable:!1}:await Te(),u={hooks:r,engineSelfTest:hc(),userConfig:o.userConfig,projectConfig:o.projectConfig,configState:Ht(s),effectiveRules:o.effectiveRules,shadowedRules:o.shadowedRules,environment:i,effectiveSafety:{selectedPreset:a.safety.level??"standard",level:l.effectiveLevel,capabilities:l.capabilities,ruleOverrides:a.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(c).filter(([,p])=>p.source==="rule_override"&&p.override==="off"&&p.inheritedEnabled&&p.changesInherited).map(([p])=>p),ruleCounts:{stored:Object.keys(a.destructiveCommandRuleOverrides).length,effective:Object.values(c).filter((p)=>p.changesInherited).length},...s.policyScopes?{policyScopes:s.policyScopes}:{}},...m.length>0?{v2Leftovers:m}:{},posture:Ca(o.userConfig.path),activity:d,update:g,system:n};return{...u,findings:pa(u)}}function Rg(e){console.log(),console.log(ma(e.hooks)),console.log(),console.log(ga(e.engineSelfTest)),console.log(),console.log(ha(e)),console.log(),console.log(ya(e.environment)),console.log(),console.log(va(e)),console.log(),console.log(ba(e.findings)),console.log(),console.log(La(e.activity)),console.log(),console.log(ka(e.system)),console.log(),console.log(wa(e.update)),console.log(xa(e))}import{existsSync as Pg}from"node:fs";var Dg=/^[A-Za-z0-9_@%+=:,./-]+$/,vc="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Ho(e){let t=E({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},e);if(fe(t.errors))return console.error(vc),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!Pg(t.values.cwd))return console.error(`Error: --cwd path does not exist: ${t.values.cwd}`),null;let n=t.positionals.length===1?t.positionals[0]:t.positionals.map((r)=>Dg.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!n)return console.error("Error: No command provided"),console.error(vc),null;return{json:t.flags.json,cwd:t.values.cwd,command:n}}function bc(e){if(e)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function Lc(e,t){let r=t-18;return[`${e.dtl}${e.dh.repeat(t)}${e.dtr}`,`${e.dv} Command Analysis${" ".repeat(r)}${e.dv}`,`${e.dbl}${e.dh.repeat(t)}${e.dbr}`]}function Mo(e){return JSON.stringify(e)}function wc(e,t=0){return`[${e.map((r,o)=>fa(r,o,t)).join(",")}]`}function nn(e,t,n=70){let r=e.split(" "),o=[],i="";for(let s of r)if(i&&i.length+s.length+1>n)o.push(i),i=s;else i=i?`${i} ${s}`:s;if(i)o.push(i);return o.map((s,a)=>a===0?s:`${t}${s}`)}function kc(e,t,n){let r=[];switch(e.type){case"parse":return null;case"env-strip":return r.push(""),r.push(`STEP ${t} ${n.h} Strip environment variables`),r.push(` Removed: ${e.envVars.map((o)=>`${o}=<redacted>`).join(", ")}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"leading-tokens-stripped":return r.push(""),r.push(`STEP ${t} ${n.h} Strip wrappers`),r.push(` Removed: ${e.removed.join(", ")}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"shell-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Detect shell wrapper`),r.push(` Wrapper: ${e.wrapper} -c`),r.push(` Inner: ${e.innerCommand}`),{lines:r,incrementStep:!0};case"interpreter":{if(r.push(""),r.push(`STEP ${t} ${n.h} Detect interpreter`),r.push(` Interpreter: ${e.interpreter}`),r.push(` Code: ${e.codeArg}`),e.paranoidBlocked)r.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:r,incrementStep:!0}}case"busybox":return r.push(""),r.push(`STEP ${t} ${n.h} Busybox wrapper`),r.push(` Subcommand: ${e.subcommand}`),{lines:r,incrementStep:!0};case"transparent-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Transparent wrapper`),r.push(` Wrapper: ${e.wrapper}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(r.push(""),r.push(`STEP ${t} ${n.h} Match rules`),r.push(` Rule: ${e.rule}()`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}case"worktree-relaxation":return r.push(""),r.push(`STEP ${t} ${n.h} Worktree relaxation`),r.push(` Mode: ${S.worktree.name}`),r.push(` Git cwd: ${e.gitCwd}`),r.push(" Result: Allowed local discard in linked worktree"),{lines:r,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(e.embeddedCommandFound)return r.push(""),r.push(`STEP ${t} ${n.h} Fallback scan`),r.push(` Found: ${e.embeddedCommandFound}`),{lines:r,incrementStep:!0};return null}case"custom-rules-check":{if(e.rulesChecked){if(r.push(""),r.push(`STEP ${t} ${n.h} Custom rules`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(e.matched)return r.push(""),r.push(`STEP ${t} ${n.h} Dangerous text check`),r.push(` Token: ${e.token}`),r.push(" Result: MATCHED"),{lines:r,incrementStep:!0};return null}case"strict-unparseable":return r.push(""),r.push(`STEP ${t} ${n.h} Strict mode check`),r.push(` Command: ${e.rawCommand}`),r.push(" Result: ✗ UNPARSEABLE"),{lines:r,incrementStep:!0};case"segment-skipped":return null;case"error":return r.push(""),r.push(`ERROR: ${e.message}`),{lines:r,incrementStep:!1};default:return e}}function Uo(e,t){let n=bc(t?.asciiOnly??!1),r=58,o=[],i=1;o.push(...Lc(n,58)),o.push("");let s=e.trace.steps.find((p)=>p.type==="error");if(s&&s.type==="error"){o.push("ERROR"),o.push(` ${s.message}`),o.push(""),o.push("RESULT"),o.push(` Status: ${e.result==="blocked"?y.red("BLOCKED"):y.green("ALLOWED")}`),o.push(""),o.push("CONFIG");let p=e.configSource??"none";return o.push(` Path: ${p}`),o.join(`
|
|
210
|
+
`,n-1);if(i!==-1&&/^\s*$/.test(e.slice(i+1,n)))n=i}return`${e.slice(0,n)}${e.slice(r)}`}var Zn="cc-safety-net",sc=`${Zn}@latest`,ac=["opencode.json","opencode.jsonc"],rc="CCSafetyNetPlugin";function Xn(e){return ke(process.env.XDG_CONFIG_HOME||ke(e,".config"),"opencode")}function cg(e){return ke(Xn(e),ac[0])}function dg(e){return ac.map((t)=>ke(Xn(e),t))}function lc(e){return ke(process.env.XDG_CACHE_HOME||ke(e,".cache"),"opencode","packages",sc)}function Oo(e){ag(lc(e),{recursive:!0,force:!0})}async function cc(e){let t=ke(lc(e),"node_modules",Zn),n=ke(t,"package.json");if(!$o(n))throw Error(`The OpenCode plugin cache at ${t} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${sc}\` for details.`);let r=k(JSON.parse(ic(n,"utf-8")),"main");if(typeof r!=="string")throw Error(`The cached OpenCode plugin at ${t} declares no "main" entry.`);let o=ke(t,r);if(typeof(await import(lg(o).href))[rc]==="function")return;throw Error(`The cached OpenCode plugin at ${o} does not export a callable ${rc}, so OpenCode would load nothing and fail open.`)}function Qn(e,t){if(e[t]==="/"&&e[t+1]==="/"){let n=e.indexOf(`
|
|
211
|
+
`,t+2);return n===-1?e.length:n+1}if(e[t]==="/"&&e[t+1]==="*"){let n=e.indexOf("*/",t+2);return n===-1?e.length:n+2}return t}function oc(e,t){let n=t;while(n<e.length){if(/\s/.test(e[n]??"")){n++;continue}let r=Qn(e,n);if(r===n)return n;n=r}return n}function dc(e,t){let n=t+1,r=!1;while(n<e.length){if(r){r=!1,n++;continue}if(e[n]==="\\"){r=!0,n++;continue}if(e[n]==='"')return n+1;n++}throw Error("Unterminated string in OpenCode config")}function uc(e,t,n){return JSON.parse(e.slice(t,n))}function ug(e,t){return Wn(e,t,{skipComment:Qn,stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"})}function pg(e){let t=0,n=0;while(n<e.length){let r=Qn(e,n);if(r!==n){n=r;continue}if(e[n]==='"'){let o=dc(e,n);if(t===1&&uc(e,n,o)==="plugin"){let i=oc(e,o),s=oc(e,i+1);if(e[i]===":"&&e[s]==="[")return{start:s,end:ug(e,s)}}n=o;continue}if(e[n]==="{"||e[n]==="[")t++;if(e[n]==="}"||e[n]==="]")t--;n++}return}function fg(e,t){let n=[],r=t.start+1;while(r<t.end){let o=Qn(e,r);if(o!==r){r=o;continue}if(e[r]==='"'){let i=dc(e,r),s=uc(e,r,i);if(typeof s==="string"&&s.includes(Zn))n.push({start:r,end:i});r=i;continue}r++}return n}function pc(e,t){try{return JSON.parse(K(e))}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${t}: ${n.message}`);throw n}}function mg(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e.plugin;if(!Array.isArray(t))return!1;return t.some((n)=>typeof n==="string"&&n.includes(Zn))}function gg(e,t){let n=pg(e);if(!n)throw Error(`Failed to locate OpenCode plugin array in ${t}`);let r=[...fg(e,n)].reverse().reduce(Yn,e);return pc(r,t),r}function fc(e){Oo(e);let t=dg(e),n=t.find((o)=>$o(o)),r=[];for(let o of t){if(!$o(o))continue;try{let i=ic(o,"utf-8");if(!mg(pc(i,o)))continue;return O(o,gg(i,o)),{path:o,alreadyInstalled:!0}}catch(i){r.push(i instanceof Error?i.message:String(i))}}if(r.length>0)throw Error(r.join(`
|
|
212
|
+
`));return{path:n??cg(e),alreadyInstalled:!1}}function mc(e){let t=[],n=Xn(e.homeDir),r=["opencode.json","opencode.jsonc"];for(let o of r){let i=vg(n,o);if(hg(i))try{let s=yg(i,"utf-8"),a=K(s);if((JSON.parse(a).plugin??[]).some((m)=>m.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:i,errors:t.length>0?t:void 0}}catch(s){t.push(`Failed to parse ${o}: ${s instanceof Error?s.message:String(s)}`)}}return{platform:"opencode",status:"n/a",errors:t.length>0?t:void 0}}import{join as bg}from"node:path";function Fo(e){return bg(e,".pi","agent","settings.json")}function jo(e){if(typeof e!=="string")return!1;return e==="npm:cc-safety-net"||e.startsWith("npm:cc-safety-net@")}function gc(e){let t=Fo(e.homeDir),n=ce(t);if(n.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(n.kind==="missing")return{platform:"pi",status:"n/a"};let r=k(n.value,"packages");if(!Array.isArray(r))return{platform:"pi",status:"n/a"};let o=r.find((a)=>jo(typeof a==="string"?a:k(a,"source")));if(o===void 0)return{platform:"pi",status:"n/a"};let i=k(o,"extensions");if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:t,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:t}}var wg={amp:za,"antigravity-cli":Ka,"claude-code":Za,codex:Xa,"copilot-cli":cl,cursor:yl,"gemini-cli":vl,"grok-build":Dl,"hermes-agent":Ml,"kimi-code":Qt,openclaw:ec,opencode:mc,pi:gc};function vt(e,t){let n={...t,cwd:e,homeDir:t?.homeDir??Lg()};return wn.map((r)=>kg(wg[r](n)))}function kg(e){if(e.status==="not-inspected")return{platform:e.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:e.platform,detected:e.status!=="n/a",configured:e.status==="configured",inspectionStatus:e.status!=="n/a"?"verified":e.errors&&e.errors.length>0?"failed":"not-applicable",method:e.method,configPath:e.configPath,configPaths:e.configPaths,errors:e.errors}}import{tmpdir as xg}from"node:os";import{join as Cg}from"node:path";var Sg=Object.freeze([{command:"git reset --hard",description:"git reset --hard",expectBlocked:!0},{command:"rm -rf /",description:"rm -rf /",expectBlocked:!0},{command:"rm -rf ./node_modules",description:"rm in cwd (safe)",expectBlocked:!1}]),Rg=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),Pg={strict:!1,paranoidRm:!1,paranoidInterpreters:!1,worktreeMode:!1,effectiveLevel:"standard",capabilities:{fail_closed:{enabled:!1,source:"preset",sources:[]},paranoid_rm:{enabled:!1,source:"preset",sources:[]},paranoid_interpreters:{enabled:!1,source:"preset",sources:[]}}};function hc(){let e=Cg(xg(),"cc-safety-net-self-test"),t=Sg.map((n)=>{let r=bn(st("self-test",{command:n.command},{kind:"command",shell:"auto"},{configCwd:e,executionCwd:e},n.command),{guard:{dependencies:{loadPolicySnapshot:()=>Rg,getModes:()=>Pg,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),o=n.expectBlocked?"blocked":"allowed",i=r.decision.kind==="deny"?"blocked":"allowed";return{command:n.command,description:n.description,expected:o,actual:i,passed:o===i,reason:r.decision.kind==="deny"?r.decision.reason:void 0,ruleId:r.decision.kind==="deny"?r.decision.ruleId:void 0}});return{passed:t.filter((n)=>n.passed).length,failed:t.filter((n)=>!n.passed).length,total:t.length,results:t}}function No(e){let t=E({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},e);if(fe(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function yc(e={}){let t=await Kt(!e.json,()=>{let n=Dg(e);return{ready:n,finish:()=>n}},()=>zt(),{loadingMessage:"Checking system status…"});if(e.json)console.log(JSON.stringify(t,null,2));else Ag(t);return t.engineSelfTest.failed>0||t.findings.some((n)=>n.severity==="error")?1:0}async function Dg(e){let t=e.cwd??process.cwd(),n=await qt(),r=vt(t,{ampPluginListOutput:n.ampPluginListOutput,codexPluginListOutput:n.codexPluginListOutput,copilotCliVersion:n.versions["copilot-cli"]}),o=ca(t),i=da(),s=z({cwd:t}),a=s.policy,l=ye(a),c=Ue(a,l.capabilities),d=Rn(7),m=Ua(t),g=e.skipUpdateCheck?{currentVersion:I(),latestVersion:null,updateAvailable:!1}:await Te(),u={hooks:r,engineSelfTest:hc(),userConfig:o.userConfig,projectConfig:o.projectConfig,configState:Ht(s),effectiveRules:o.effectiveRules,shadowedRules:o.shadowedRules,environment:i,effectiveSafety:{selectedPreset:a.safety.level??"standard",level:l.effectiveLevel,capabilities:l.capabilities,ruleOverrides:a.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(c).filter(([,p])=>p.source==="rule_override"&&p.override==="off"&&p.inheritedEnabled&&p.changesInherited).map(([p])=>p),ruleCounts:{stored:Object.keys(a.destructiveCommandRuleOverrides).length,effective:Object.values(c).filter((p)=>p.changesInherited).length},...s.policyScopes?{policyScopes:s.policyScopes}:{}},...m.length>0?{v2Leftovers:m}:{},posture:Ca(o.userConfig.path),activity:d,update:g,system:n};return{...u,findings:pa(u)}}function Ag(e){console.log(),console.log(ma(e.hooks)),console.log(),console.log(ga(e.engineSelfTest)),console.log(),console.log(ha(e)),console.log(),console.log(ya(e.environment)),console.log(),console.log(va(e)),console.log(),console.log(ba(e.findings)),console.log(),console.log(La(e.activity)),console.log(),console.log(ka(e.system)),console.log(),console.log(wa(e.update)),console.log(xa(e))}import{existsSync as Eg}from"node:fs";var _g=/^[A-Za-z0-9_@%+=:,./-]+$/,vc="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Ho(e){let t=E({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},e);if(fe(t.errors))return console.error(vc),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!Eg(t.values.cwd))return console.error(`Error: --cwd path does not exist: ${t.values.cwd}`),null;let n=t.positionals.length===1?t.positionals[0]:t.positionals.map((r)=>_g.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!n)return console.error("Error: No command provided"),console.error(vc),null;return{json:t.flags.json,cwd:t.values.cwd,command:n}}function bc(e){if(e)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function Lc(e,t){let r=t-18;return[`${e.dtl}${e.dh.repeat(t)}${e.dtr}`,`${e.dv} Command Analysis${" ".repeat(r)}${e.dv}`,`${e.dbl}${e.dh.repeat(t)}${e.dbr}`]}function Mo(e){return JSON.stringify(e)}function wc(e,t=0){return`[${e.map((r,o)=>fa(r,o,t)).join(",")}]`}function nn(e,t,n=70){let r=e.split(" "),o=[],i="";for(let s of r)if(i&&i.length+s.length+1>n)o.push(i),i=s;else i=i?`${i} ${s}`:s;if(i)o.push(i);return o.map((s,a)=>a===0?s:`${t}${s}`)}function kc(e,t,n){let r=[];switch(e.type){case"parse":return null;case"env-strip":return r.push(""),r.push(`STEP ${t} ${n.h} Strip environment variables`),r.push(` Removed: ${e.envVars.map((o)=>`${o}=<redacted>`).join(", ")}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"leading-tokens-stripped":return r.push(""),r.push(`STEP ${t} ${n.h} Strip wrappers`),r.push(` Removed: ${e.removed.join(", ")}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"shell-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Detect shell wrapper`),r.push(` Wrapper: ${e.wrapper} -c`),r.push(` Inner: ${e.innerCommand}`),{lines:r,incrementStep:!0};case"interpreter":{if(r.push(""),r.push(`STEP ${t} ${n.h} Detect interpreter`),r.push(` Interpreter: ${e.interpreter}`),r.push(` Code: ${e.codeArg}`),e.paranoidBlocked)r.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:r,incrementStep:!0}}case"busybox":return r.push(""),r.push(`STEP ${t} ${n.h} Busybox wrapper`),r.push(` Subcommand: ${e.subcommand}`),{lines:r,incrementStep:!0};case"transparent-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Transparent wrapper`),r.push(` Wrapper: ${e.wrapper}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(r.push(""),r.push(`STEP ${t} ${n.h} Match rules`),r.push(` Rule: ${e.rule}()`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}case"worktree-relaxation":return r.push(""),r.push(`STEP ${t} ${n.h} Worktree relaxation`),r.push(` Mode: ${S.worktree.name}`),r.push(` Git cwd: ${e.gitCwd}`),r.push(" Result: Allowed local discard in linked worktree"),{lines:r,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(e.embeddedCommandFound)return r.push(""),r.push(`STEP ${t} ${n.h} Fallback scan`),r.push(` Found: ${e.embeddedCommandFound}`),{lines:r,incrementStep:!0};return null}case"custom-rules-check":{if(e.rulesChecked){if(r.push(""),r.push(`STEP ${t} ${n.h} Custom rules`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(e.matched)return r.push(""),r.push(`STEP ${t} ${n.h} Dangerous text check`),r.push(` Token: ${e.token}`),r.push(" Result: MATCHED"),{lines:r,incrementStep:!0};return null}case"strict-unparseable":return r.push(""),r.push(`STEP ${t} ${n.h} Strict mode check`),r.push(` Command: ${e.rawCommand}`),r.push(" Result: ✗ UNPARSEABLE"),{lines:r,incrementStep:!0};case"segment-skipped":return null;case"error":return r.push(""),r.push(`ERROR: ${e.message}`),{lines:r,incrementStep:!1};default:return e}}function Uo(e,t){let n=bc(t?.asciiOnly??!1),r=58,o=[],i=1;o.push(...Lc(n,58)),o.push("");let s=e.trace.steps.find((p)=>p.type==="error");if(s&&s.type==="error"){o.push("ERROR"),o.push(` ${s.message}`),o.push(""),o.push("RESULT"),o.push(` Status: ${e.result==="blocked"?y.red("BLOCKED"):y.green("ALLOWED")}`),o.push(""),o.push("CONFIG");let p=e.configSource??"none";return o.push(` Path: ${p}`),o.join(`
|
|
189
213
|
`)}let a=e.trace.steps.find((p)=>p.type==="parse");if(a&&a.type==="parse"){o.push("INPUT"),o.push(` ${a.input}`),o.push(""),o.push(`STEP ${i} ${n.h} Split shell commands`),i++;for(let p=0;p<a.segments.length;p++){let f=a.segments[p];if(f){let b=Math.random();o.push(` Segment ${p+1}: ${wc(f,b)}`)}}}let l=e.trace.segments,c=l.length>1;for(let p of l){if(c){o.push("");let h="";if(a&&a.type==="parse"){let mr=a.segments[p.index];if(mr)h=mr.join(" ")}let R=54,v=h,P=` Segment ${p.index+1}: `,ne=" ";if(h){if(P.length+h.length+ne.length>R){let bu=R-P.length-ne.length;v=`${h.substring(0,bu-1)}…`}}let un=h?`${P}${v}${ne}`:` Segment ${p.index+1} `,yu=h?`${P}${y.cyan(v)}${ne}`:un,pi=58-un.length,fi=Math.floor(pi/2),vu=pi-fi;o.push(`${n.sh.repeat(fi)}${yu}${n.sh.repeat(vu)}`)}if(p.steps.find((h)=>h.type==="segment-skipped")){o.push(""),o.push(" (skipped — prior segment blocked)");continue}let b=!1,L=!1;for(let h of p.steps){let R=kc(h,i,n);if(R){if(L=!0,h.type==="recurse"){o.push("");let v=" RECURSING ",P=58-v.length-4;o.push(` ${n.tl}${n.h}${v}${n.h.repeat(P)}`),o.push(` ${n.v}`),b=!0;continue}for(let v of R.lines)if(b)o.push(` ${n.v} ${v}`);else o.push(v);if(R.incrementStep)i++}}if(b)o.push(` ${n.v}`),o.push(` ${n.bl}${n.h.repeat(56)}`),b=!1;if(!L)o.push(""),o.push(` ${y.green("✓")} Allowed (no matching rules)`)}if(o.push(""),o.push("RESULT"),e.result==="blocked"){if(o.push(` Status: ${y.red("BLOCKED")}`),e.customRule){if(o.push(` Rule: ${e.customRule.id}`),e.customRule.rulebook)o.push(` Rulebook: ${e.customRule.rulebook.name} ${e.customRule.rulebook.version}`);if(e.customRule.source)o.push(` Source: ${e.customRule.source}`);if(e.customRule.override)o.push(` Override: reason ${e.customRule.override.reason}`)}if(e.reason){let p=nn(e.reason," ");o.push(` Reason: ${p[0]}`);for(let f=1;f<p.length;f++)o.push(p[f]??"")}}else o.push(` Status: ${y.green("ALLOWED")}`);o.push(""),o.push("CONFIG");let d=e.configSource??"none",m=e.configValid?"":" (invalid)";o.push(` Path: ${d}${m}`);let g=e.safetyPresetScope;o.push(` Safety preset: ${e.selectedPreset??"standard"}${g?` (${Pn(g)})`:""}`),o.push(` Effective capabilities: ${e.effectiveLevel}`);let u=Object.entries(e.destructiveCommandRuleOverrides??{});if(o.push(` Rule customizations: ${u.length}`),e.ruleActivation)o.push(` Rule activation: ${e.ruleActivation.id} — ${e.ruleActivation.enabled?"on":"off"} via ${e.ruleActivation.source}`);return o.join(`
|
|
190
214
|
`)}function Go(e){return JSON.stringify(e,null,2)}function xc(e){return new Promise((t)=>{process.stdout.write(`${e}
|
|
191
|
-
`,()=>t())})}async function Cc(e){let t=Ho(e);if(!t)return 1;try{let n=at(t.command,{cwd:t.cwd}),r=!!process.env.NO_COLOR||!process.stdout.isTTY;return await xc(t.json?Go(n):Uo(n,{asciiOnly:r})),0}catch(n){if(!(n instanceof Gr)&&!(n instanceof Me)&&!(n instanceof Le))throw n;if(t.json)return await xc(JSON.stringify({error:n.message})),1;return console.error(n.message),1}}var Sc="2.3.
|
|
192
|
-
`))}function Bo(){let e
|
|
193
|
-
`))}function Pc(){console.log(Sc)}function rn(e,t=console.log){let n=Sn(e);if(!n)return!1;if(n.name.toLowerCase()!==e.toLowerCase())return!1;return bt(n,t),!0}import{existsSync as ti,readFileSync as bd}from"node:fs";import{homedir as
|
|
194
|
-
`)}var Ac=["global-hook","plugin"];function
|
|
215
|
+
`,()=>t())})}async function Cc(e){let t=Ho(e);if(!t)return 1;try{let n=at(t.command,{cwd:t.cwd}),r=!!process.env.NO_COLOR||!process.stdout.isTTY;return await xc(t.json?Go(n):Uo(n,{asciiOnly:r})),0}catch(n){if(!(n instanceof Gr)&&!(n instanceof Me)&&!(n instanceof Le))throw n;if(t.json)return await xc(JSON.stringify({error:n.message})),1;return console.error(n.message),1}}var Sc="2.3.3",te=" ",Ye="cc-safety-net";function Rc(e){return e.argument?`${e.flags} ${e.argument}`:e.flags}function Tg(e){return Math.max(...e.map((t)=>Rc(t).length))}function Ig(e){return Math.max(...e.map((t)=>t.usage.length))}function $g(e){return Math.max(...e.map((t)=>`${Ye} ${t.usage}`.length))}function Og(e,t){let n=`${Ye} ${e.usage}`;return`${te}${n.padEnd(t+2)}${e.description}`}function xe(e,t){return`${te}${e.padEnd(Math.max(40,e.length+2))}${t}`}function bt(e,t=console.log){let n=[];if(n.push(`${Ye} ${e.name}`),n.push(""),n.push(`${te}${e.description}`),n.push(""),n.push("USAGE:"),n.push(`${te}${Ye} ${e.usage}`),n.push(""),e.subcommands&&e.subcommands.length>0){n.push("SUBCOMMANDS:");let r=Ig(e.subcommands);for(let o of e.subcommands)n.push(`${te}${o.usage.padEnd(r+2)}${o.description}`);n.push("")}if(e.options.length>0){n.push("OPTIONS:");let r=Tg(e.options);for(let o of e.options){let i=Rc(o),s=o.default?`${o.description} (default: ${o.default})`:o.description;n.push(`${te}${i.padEnd(r+2)}${s}`)}n.push("")}if(e.examples&&e.examples.length>0){n.push("EXAMPLES:");for(let r of e.examples)n.push(`${te}${r}`)}t(n.join(`
|
|
216
|
+
`))}function Bo(){let e=$g(Cn),t=[];t.push(`${Ye} v${Sc}`),t.push(""),t.push("Blocks destructive commands and secret access."),t.push(""),t.push("COMMANDS:");for(let n of Cn)t.push(Og(n,e));t.push(""),t.push("GLOBAL OPTIONS:"),t.push(`${te}-h, --help Show help (use with command for command-specific help)`),t.push(`${te}-V, --version Show version`),t.push(""),t.push("HELP:"),t.push(`${te}${Ye} help <command> Show help for a specific command`),t.push(`${te}${Ye} <command> --help Show help for a specific command`),t.push(""),t.push("ENVIRONMENT VARIABLES:"),t.push(xe(`${S.level.name}=standard|strict|paranoid`,"Set session safety level")),t.push(xe(`${S.worktree.name}=1`,"Allow local git discards in linked worktrees")),t.push(xe(`${S.debug.name}=1`,"Print diagnostic messages to stderr")),t.push(xe(`${S.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),t.push(xe("CC_SAFETY_NET_HOME","Override rule config home directory")),t.push(""),t.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),t.push(xe(`${S.strict.name}=1`,"Force safety.overrides.fail_closed on")),t.push(xe(`${S.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),t.push(xe(`${S.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),t.push(xe(`${S.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),t.push(""),t.push("Documentation: https://ccsafetynet.com/docs"),console.log(t.join(`
|
|
217
|
+
`))}function Pc(){console.log(Sc)}function rn(e,t=console.log){let n=Sn(e);if(!n)return!1;if(n.name.toLowerCase()!==e.toLowerCase())return!1;return bt(n,t),!0}import{existsSync as ti,readFileSync as bd}from"node:fs";import{homedir as Th,tmpdir as Ih}from"node:os";import{join as Qo}from"node:path";import*as $e from"node:readline";function Fg(e){return e==="install"?"Install":"Uninstall"}function jg(e){return e==="install"?"Installing":"Uninstalling"}function Ng(e){return e==="install"?"into":"from"}function Ec(e){return e?.available===!0}function Hg(e,t){let n=new Set(t);return e.filter((r)=>n.has(r.target)).map((r)=>r.target)}function Dc(e,t,n){if(e.length===0||e.every((r)=>!r.available))return t;return Array.from({length:e.length},(r,o)=>o+1).map((r)=>(t+r*n+e.length)%e.length).find((r)=>Ec(e[r]))}function Mg(e,t,n){if(n.ctrl&&n.name==="c")return"interrupt";if(n.name==="escape"||t==="q")return"abort";if(e==="install"&&(t==="u"||t==="U"))return"update";if(n.name==="up"||t==="k")return"up";if(n.name==="down"||t==="j")return"down";if(n.name==="space"||t===" ")return"toggle";if(n.name==="return"||n.name==="enter")return"confirm";return null}function Ug(e){return{cursor:e.findIndex((t)=>t.available),selected:[]}}function Gg(e,t,n){if(n==="confirm"||n==="update"||n==="abort"||n==="interrupt")return{state:e,done:n};if(n==="up")return{state:{...e,cursor:Dc(t,e.cursor,-1)}};if(n==="down")return{state:{...e,cursor:Dc(t,e.cursor,1)}};let r=t[e.cursor];if(!Ec(r))return{state:e};let o=e.selected.includes(r.target)?e.selected.filter((i)=>i!==r.target):Hg(t,[...e.selected,r.target]);return{state:{...e,selected:o}}}var _c="◉",Tc="◯",Ic=">",$c=" ";function Bg(e,t,n,r={}){let o=r.color!==!1,i=o?y.dim:(l)=>l,s=o?y.green:(l)=>l,a=o?y.bold:(l)=>l;return["",`${Fg(e)} CC Safety Net ${Ng(e)}:`,"",...t.map((l,c)=>{let d=n.selected.includes(l.target),m=c===n.cursor,g=d?_c:Tc,u=m?Ic:$c,p=l.available?"":` (${l.unavailableReason??"not installed"})`,f=`${g} ${l.label}${p}`,b=!l.available?i(f):d?s(f):m?a(f):f;return`${u} ${b}`}),"",e==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":t.some((l)=>l.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${e}. q/Esc: close`].join(`
|
|
218
|
+
`)}var Ac=["global-hook","plugin"];function qg(e,t,n={}){let r=n.color!==!1?y.bold:(i)=>i;return["","Install the Kimi Code integration as:","",...[`Global hook — ${t?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((i,s)=>{let a=s===e,l=`${a?_c:Tc} ${i}`;return`${a?Ic:$c} ${a?r(l):l}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
195
219
|
`)}function Oc(e){let{input:t,output:n}=e;$e.emitKeypressEvents(t);let r=t.isRaw===!0;t.setRawMode(!0),t.resume();let o=0,i=()=>{if(o===0)return;$e.moveCursor(n,0,-o),$e.cursorTo(n,0),$e.clearScreenDown(n)},s=()=>{i();let a=e.render();n.write(`${a}
|
|
196
220
|
`),o=a.split(`
|
|
197
|
-
`).length};return new Promise((a)=>{let l=(d)=>{t.off("keypress",c),t.setRawMode(r),t.pause(),i(),a(d)};function c(d,m){e.onKey(d,m,{finish:l,draw:s})}t.on("keypress",c),s()})}function Fc(e={}){let t=0;return Oc({input:e.input??process.stdin,output:e.output??process.stdout,render:()=>
|
|
198
|
-
`);return}a.draw()}})}import{existsSync as Hc,lstatSync as
|
|
199
|
-
`)})}),o.on("close",(l)=>{clearTimeout(a),r({status:s?null:l,errorCode:s?"ETIMEDOUT":void 0,stdout:i.stdout,stderr:i.stderr})})})};var Lt="cc-safety-net.ts",Nc=G("amp",Xe);function
|
|
221
|
+
`).length};return new Promise((a)=>{let l=(d)=>{t.off("keypress",c),t.setRawMode(r),t.pause(),i(),a(d)};function c(d,m){e.onKey(d,m,{finish:l,draw:s})}t.on("keypress",c),s()})}function Fc(e={}){let t=0;return Oc({input:e.input??process.stdin,output:e.output??process.stdout,render:()=>qg(t,e.globalHookInstalled===!0),onKey:(n,r,o)=>{if(r.ctrl&&r.name==="c"){o.finish(null),(e.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(r.name==="escape"||n==="q")return o.finish(null);if(r.name==="return"||r.name==="enter")return o.finish(Ac[t]);if(r.name==="up"||r.name==="down"||n==="k"||n==="j")t=(t+1)%Ac.length,o.draw()}})}function qo(e=process.stdin,t=process.stdout){return Boolean(e.isTTY&&t.isTTY&&typeof e.setRawMode==="function")}function jc(e,t,n={}){let r=n.output??process.stdout,o=Ug(t);return Oc({input:n.input??process.stdin,output:r,render:()=>Bg(e,t,o),onKey:(i,s,a)=>{let l=Mg(e,i,s);if(!l)return;let c=Gg(o,t,l);if(o=c.state,c.done==="interrupt"){a.finish(null),(n.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(c.done==="abort")return a.finish(null);if(c.done==="update")return a.finish("update");if(c.done==="confirm"){if(o.selected.length===0){r.write("\x07"),a.draw();return}a.finish([...o.selected]),r.write(`${jg(e)} selected integrations...
|
|
222
|
+
`);return}a.draw()}})}import{existsSync as Hc,lstatSync as zg,mkdirSync as Kg,mkdtempSync as Jg,readdirSync as Wg,readFileSync as wt,rmSync as tr}from"node:fs";import{tmpdir as Yg}from"node:os";import{basename as Zg,dirname as Xg,join as G}from"node:path";import{fileURLToPath as Qg}from"node:url";var Vo="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",Ze="cc-safety-net",Xe="cc-safety-net/index.ts";import{spawn as Vg}from"node:child_process";var zo=(e,t)=>{let n=ze([...e],process.env);return new Promise((r)=>{let o=Vg(n.cmd,n.args,{cwd:t,stdio:["ignore","pipe","pipe"]}),i=Do(o),s=!1,a=setTimeout(()=>{s=!0,o.kill()},120000);o.on("error",(l)=>{clearTimeout(a),r({status:null,errorCode:l.code,stdout:i.stdout,stderr:[l.message,i.stderr].filter(Boolean).join(`
|
|
223
|
+
`)})}),o.on("close",(l)=>{clearTimeout(a),r({status:s?null:l,errorCode:s?"ETIMEDOUT":void 0,stdout:i.stdout,stderr:i.stderr})})})};var Lt="cc-safety-net.ts",Nc=G("amp",Xe);function eh(e){return G(e,".config","amp","plugins","cc-safety-net.ts")}function th(){let e=Xg(Qg(import.meta.url));return[G(e,"..",Nc),G(e,"..","..","..","dist",Nc)]}function nh(e=th()){let t=e.find((n)=>Hc(n)&&zg(n).isFile());if(!t)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return t}function Mc(e){try{return JSON.parse(e)}catch{return}}function nr(e){return e.subarray(0,Buffer.byteLength(Vo)).toString("utf-8")===Vo}async function on(e,t,n){let r=await e(t,n);if(r.status===0)return r;throw Error([`Failed to run ${t.join(" ")}${r.status===null?"":` (exit ${r.status})`}.`,[r.stdout,r.stderr].filter(Boolean).join(`
|
|
200
224
|
`).trim()].filter(Boolean).join(`
|
|
201
225
|
`))}async function Uc(e){let t=await e(["amp","plugins","repositories","--json"]);if(t.status===null)throw Error(`${t.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${t.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
|
|
202
226
|
${t.stderr}`.trim());if(t.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${t.status}). Sign in with "amp login" and rerun install --amp.
|
|
203
227
|
${[t.stdout,t.stderr].filter(Boolean).join(`
|
|
204
|
-
`)}`.trim());let n=Mc(t.stdout),r=(Array.isArray(n)?n:[]).filter((o)=>k(o,"scope")==="user"&&k(o,"exists")===!0&&k(o,"viewerCanWrite")===!0).map((o)=>k(o,"cloneRef")).find((o)=>typeof o==="string"&&o.length>0);if(!r)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return r}async function Gc(e,t){let n=
|
|
205
|
-
`}async function Kc(e,t=
|
|
206
|
-
`)}function Qc(e){let t=Gt(e);if(
|
|
228
|
+
`)}`.trim());let n=Mc(t.stdout),r=(Array.isArray(n)?n:[]).filter((o)=>k(o,"scope")==="user"&&k(o,"exists")===!0&&k(o,"viewerCanWrite")===!0).map((o)=>k(o,"cloneRef")).find((o)=>typeof o==="string"&&o.length>0);if(!r)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return r}async function Gc(e,t){let n=Jg(G(Yg(),"cc-safety-net-amp-"));try{return await on(e,["amp","clone","user-plugins",n]),await t(n)}finally{tr(n,{recursive:!0,force:!0})}}function Ko(e){return`rerun ${e==="overwrite"?"install":"uninstall"} --amp`}function Bc(e,t,n){let r=G(e,t),o=_(r);if(!o)return;if(o.isSymbolicLink()||!o.isFile())throw Error(`Refusing to ${n} ${t} in your Amp personal plugins repository: not a regular file. Remove it there and ${Ko(n)}.`);let i=wt(r);if(nr(i))return i;throw Error(`Refusing to ${n} unmanaged file ${t} in your Amp personal plugins repository. Remove it there and ${Ko(n)}.`)}function qc(e,t){let n=G(e,Ze),r=_(n);if(!r)return;if(r.isSymbolicLink()||!r.isDirectory())throw Error(`Refusing to ${t} ${Ze} in your Amp personal plugins repository: not a regular directory. Remove it there and ${Ko(t)}.`);return Bc(e,Xe,t)}function rh(e){let t=G(e,Lt),n=_(t);if(!n||n.isSymbolicLink()||!n.isFile())return;let r=wt(t);return nr(r)?r:void 0}async function Vc(e,t,n,r){if(await on(e,n,t),(await on(e,["git","status","--porcelain"],t)).stdout.trim()==="")return!1;return await on(e,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",r],t),await on(e,["git","push","origin","HEAD"],t),!0}function er(e,t){oh(e,t),ih(e,t)}function zc(e,t){if(t==="keep")return;throw Error(`Local Amp plugin ${e} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function oh(e,t){let n=eh(e),r=_(n);if(!r)return;if(!r.isSymbolicLink()&&r.isFile()&&nr(wt(n))){tr(n);return}zc(n,t)}function ih(e,t){let n=G(e,".config","amp","plugins",Ze),r=_(n);if(!r)return;if(!r.isSymbolicLink()&&r.isDirectory()&&sh(n)){tr(n,{recursive:!0});return}zc(n,t)}function sh(e){let t=Zg(Xe);if(Wg(e).join("\x00")!==t)return!1;let n=G(e,t),r=_(n);return!!r&&!r.isSymbolicLink()&&r.isFile()&&nr(wt(n))}function ah(){let e=ve();if(!Hc(e))return"";let t=Mc(wt(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(Y(t))};
|
|
229
|
+
`}async function Kc(e,t=nh(),n=zo){let r=Buffer.concat([wt(t),Buffer.from(ah(),"utf-8")]),o=await Uc(n);return Gc(n,async(i)=>{let s=`${o}/${Ze}`,a=qc(i,"overwrite"),l=Bc(i,Lt,"overwrite");if(a?.equals(r)&&!l)return er(e,"fail"),{path:s,alreadyInstalled:!0};if(Kg(G(i,Ze),{recursive:!0}),O(G(i,Xe),r),l)tr(G(i,Lt));let c=await Vc(n,i,["git","add","--",Xe,...l?[Lt]:[]],`chore: update cc-safety-net plugin to v${I()}`);return er(e,"fail"),{path:s,alreadyInstalled:!c}})}async function Jc(e,t=zo){let n=await Uc(t);return Gc(t,async(r)=>{let o=qc(r,"remove"),i=rh(r),s=`${n}/${i&&!o?Lt:Ze}`;if(!o&&!i)return er(e,"keep"),{path:s,alreadyInstalled:!1};return await Vc(t,r,["git","rm","--",...o?[Xe]:[],...i?[Lt]:[]],`chore: remove cc-safety-net plugin v${I()}`),er(e,"keep"),{path:s,alreadyInstalled:!0}})}import{existsSync as Wc,mkdirSync as lh,readFileSync as ch}from"node:fs";import{dirname as dh}from"node:path";var Jo="npx -y cc-safety-net hook --agy-cli",Qe="cc-safety-net";function et(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function or(){return{PreToolUse:[{hooks:[{type:"command",command:Jo,timeout:30}]}]}}function Yc(e){try{let t=JSON.parse(ch(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))throw Error("Antigravity hooks config must be a JSON object");return t}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${e}: ${t.message}`);throw t}}function Zc(e){let t=e[Qe];if(t===void 0){let r=or();return e[Qe]=r,{definition:r,preToolUse:r.PreToolUse??[]}}if(!et(t))throw Error(`Antigravity hooks config entry "${Qe}" must be an object`);let n=Array.isArray(t.PreToolUse)?t.PreToolUse:[];return t.PreToolUse=n,{definition:t,preToolUse:n}}function Xc(e){if(!Array.isArray(e.PreToolUse))return!1;return e.PreToolUse.some((t)=>et(t)&&Array.isArray(t.hooks)&&t.hooks.some((n)=>et(n)&&n.command===Jo))}function uh(e){return Object.values(e).some((t)=>et(t)&&t.enabled!==!1&&Xc(t))}function ph(e){if(e[Qe]===void 0)return!1;let t=Zc(e);if(t.definition.enabled!==!1||!Xc(t.definition))return!1;return t.definition.enabled=!0,!0}function fh(e){if(e[Qe]===void 0){e[Qe]=or();return}let t=Zc(e);t.definition.enabled=!0,t.preToolUse.push(or().PreToolUse?.[0]??{hooks:[]})}function mh(e){let t=!1;for(let n of Object.values(e)){if(!et(n)||!Array.isArray(n.PreToolUse))continue;n.PreToolUse=n.PreToolUse.flatMap((r)=>{if(!et(r)||!Array.isArray(r.hooks))return[r];let o=r.hooks.filter((i)=>!et(i)||i.command!==Jo);if(o.length!==r.hooks.length)t=!0;return o.length===0?[]:[{...r,hooks:o}]})}return t}function rr(e,t){O(e,`${JSON.stringify(t,null,2)}
|
|
230
|
+
`)}function Qc(e){let t=Gt(e);if(lh(dh(t),{recursive:!0}),!Wc(t))return rr(t,{[Qe]:or()}),{path:t,alreadyInstalled:!1};let n=Yc(t);if(uh(n))return{path:t,alreadyInstalled:!0};if(ph(n))return rr(t,n),{path:t,alreadyInstalled:!1};return fh(n),rr(t,n),{path:t,alreadyInstalled:!1}}function ed(e){let t=Gt(e);if(!Wc(t))return{path:t,alreadyInstalled:!1};let n=Yc(t);if(!mh(n))return{path:t,alreadyInstalled:!1};return rr(t,n),{path:t,alreadyInstalled:!0}}import{existsSync as gh,readdirSync as hh,rmSync as yh}from"node:fs";import{join as vh}from"node:path";function td(e,t=process.platform,n){if(!gh(e))return;let r=t==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);hh(e).filter((o)=>o!==n&&r.test(o)).forEach((o)=>{yh(vh(e,o),{recursive:!0,force:!0})})}import{spawn as bh}from"node:child_process";var pe=X.map((e)=>({target:e.id,flag:e.flag,label:D(e.id),probeCommand:e.probeCommand}));function Wo(e){let t=new Set(e);return pe.map((n)=>n.target).filter((n)=>t.has(n))}async function nd(e,t){for(let n of e)await t(n)}var Lh=5000;function Yo(e){return new Promise((t)=>{let n=ze([...e],process.env),r=bh(n.cmd,n.args,{env:process.env,stdio:"ignore"}),o=!1,i=(a)=>{if(o)return;o=!0,clearTimeout(s),t(a)},s=setTimeout(()=>{r.kill(),i(!1)},Lh);r.on("error",()=>i(!1)),r.on("close",(a)=>i(a===0))})}function rd(e=Yo,t={}){let n=new Set(t.configuredTargets??[]);return Promise.all(pe.map(async(r)=>({target:r.target,flag:r.flag,label:r.label,...id(t.action,await e(r.probeCommand),n.has(r.target))})))}function od(e,t){let n=new Set(t.configuredTargets??[]);return e.map((r)=>({...r,...id(t.action,r.available,n.has(r.target))}))}function id(e,t,n){if(e==="uninstall")return n?{available:!0}:{available:!1,unavailableReason:"not installed"};if(e==="install"&&n)return{available:!1,unavailableReason:"already installed"};if(!t)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as sd,readdirSync as wh,rmSync as kh}from"node:fs";import{join as kt}from"node:path";function ir(e,t=process.platform){let n=kt(process.env.npm_config_cache||(t==="win32"?kt(process.env.LOCALAPPDATA||kt(e,"AppData","Local"),"npm-cache"):kt(e,".npm")),"_npx");if(!sd(n))return;wh(n).filter((r)=>sd(kt(n,r,"node_modules","cc-safety-net"))).forEach((r)=>{kh(kt(n,r),{recursive:!0,force:!0})})}import{existsSync as ld,mkdirSync as xh,readFileSync as cd}from"node:fs";import{dirname as Ch,join as ad}from"node:path";var sn="npx -y cc-safety-net hook --kimi-code",Zo=`[[hooks]]
|
|
207
231
|
event = "PreToolUse"
|
|
208
|
-
command = "${sn}"`,Xo=`{ event = "PreToolUse", command = "${sn}" }`;function dd(e){return ad(process.env.KIMI_CODE_HOME??ad(e,".kimi-code"),"config.toml")}function
|
|
232
|
+
command = "${sn}"`,Xo=`{ event = "PreToolUse", command = "${sn}" }`;function dd(e){return ad(process.env.KIMI_CODE_HOME??ad(e,".kimi-code"),"config.toml")}function Sh(e){return e.split(`
|
|
209
233
|
`).reduce((n,r)=>{if(/^\s*\[/.test(r))return n.activeTable=!0,n.lines.push(r),n;if(!n.activeTable&&/^\s*hooks\s*=\s*\[\s*]\s*(?:#.*)?$/.test(r))return n;return n.lines.push(r),n},{activeTable:!1,lines:[]}).lines.join(`
|
|
210
|
-
`)}function
|
|
211
|
-
`,t+1);return n===-1?e.length:n+1}function
|
|
212
|
-
`,n),o=r===-1?e.length:r,i=e.slice(n,o);if(/^\s*\[/.test(i))t=!0;if(!t){let s=/^(\s*)hooks\s*=\s*\[/.exec(i);if(s){let a=n+s[0].lastIndexOf("[");return{start:a,end:
|
|
213
|
-
${o}${Xo}${e.slice(t.end)}`}function
|
|
234
|
+
`)}function Rh(e,t){if(e[t]!=="#")return t;let n=e.indexOf(`
|
|
235
|
+
`,t+1);return n===-1?e.length:n+1}function Ph(e,t){return Wn(e,t,{skipComment:Rh,stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"})}function ud(e){let t=!1,n=0;while(n<e.length){let r=e.indexOf(`
|
|
236
|
+
`,n),o=r===-1?e.length:r,i=e.slice(n,o);if(/^\s*\[/.test(i))t=!0;if(!t){let s=/^(\s*)hooks\s*=\s*\[/.exec(i);if(s){let a=n+s[0].lastIndexOf("[");return{start:a,end:Ph(e,a)}}}n=r===-1?e.length:r+1}return}function Dh(e,t){let n=e.slice(0,t.end).trimEnd(),r=nc(e,t.end),o=r===""?" ":`${r} `,i=!n.endsWith("[")&&!n.endsWith(",");return`${n}${i?",":""}
|
|
237
|
+
${o}${Xo}${e.slice(t.end)}`}function Ah(e){let t=ud(e);if(t&&e.slice(t.start+1,t.end).trim())return Dh(e,t);let n=Sh(e).trimEnd();if(n==="")return`${Zo}
|
|
214
238
|
`;return`${n}
|
|
215
239
|
|
|
216
240
|
${Zo}
|
|
217
|
-
`}function
|
|
218
|
-
`),{path:t,alreadyInstalled:!1};let n=cd(t,"utf-8");if(n.includes(sn))return{path:t,alreadyInstalled:!0};return O(t,
|
|
219
|
-
`;return O(t,o),{path:t,alreadyInstalled:!0}}var ei="safety-net@cc-marketplace",md=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gd=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function ni(e){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(e??"")}function Ld(e){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(e??"")}function
|
|
220
|
-
`)},opencode:{beforeInstall:Oo,installCommands:[["opencode","plugin","-g","-f","cc-safety-net@latest"]]},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function ar(){return process.env.HOME??
|
|
221
|
-
`),`Enabled ${de} plugin in ${t}`}function
|
|
222
|
-
`),`Enabled npm:cc-safety-net extensions in ${t}`}function hd(e,t){let n=E({label:t,booleans:Object.fromEntries(pe.map((i)=>[i.target,[i.flag]]))},e),r=n.errors[0];if(r)throw Error(r);let o=pe.filter((i)=>n.flags[i.target]).map((i)=>i.target);if(o.length!==1)throw Error(`Choose exactly one ${t} target: ${pe.map((i)=>i.flag).join(", ")}`);return o[0]}async function xd(e=ar(),t=pt){let[n,r,o]=await Promise.all([t(["amp","plugins","list"],30000),t(["codex","plugin","list"],30000),t(["copilot","--binary-version"])]);return{codexPluginListOutput:r,hooks:vt(process.cwd(),{homeDir:e,ampPluginListOutput:n,codexPluginListOutput:r,copilotCliVersion:o})}}async function
|
|
223
|
-
`)}async function xt(e){let t=wd[e];if(!t.uninstallCommands)throw Error(`${D(e)} uninstall is not supported`);return await Ao(t.uninstallCommands),`Uninstalled ${D(e)} integration`}function
|
|
224
|
-
Removing the plugin files anyway; ${Q} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function sr(e,t,n,r=!1){let o=
|
|
225
|
-
`)}var
|
|
226
|
-
`),uninstall:()=>xt("copilot-cli")},cursor:{install:(e,t)=>Oe("install","cursor",e,t),uninstall:(e)=>Oe("uninstall","cursor",e)},"gemini-cli":{install:(e,t)=>tt("gemini-cli",e,t),uninstall:()=>xt("gemini-cli")},"grok-build":{install:(e,t)=>Oe("install","grok-build",e,t),uninstall:(e)=>Oe("uninstall","grok-build",e)},"hermes-agent":{install:(e,t)=>{if(!t)ir(e);return sr("install","hermes-agent",e,t)},uninstall:(e)=>sr("uninstall","hermes-agent",e)},"kimi-code":{install:(e,t)=>Oe("install","kimi-code",e,t),uninstall:(e)=>Oe("uninstall","kimi-code",e)},openclaw:{install:async(e,t)=>{let n=await tt("openclaw",e,t);return await Wl(),n},uninstall:(e)=>(To(e),xt("openclaw"))},opencode:{install:async(e,t)=>{let n=await tt("opencode",e,t);return await cc(e),n},uninstall:(e)=>
|
|
241
|
+
`}function Eh(e){return e.split(/(?=^\s*\[)/m).filter((n)=>!/^\s*\[\[hooks]]\s*$/m.test(n)||!n.includes(sn)).join("").trimEnd()}function _h(e,t){let n=e.indexOf(Xo,t.start);if(n===-1||n>t.end)return e;return Yn(e,{start:n,end:n+Xo.length})}function pd(e){let t=dd(e);if(xh(Ch(t),{recursive:!0}),!ld(t))return O(t,`${Zo}
|
|
242
|
+
`),{path:t,alreadyInstalled:!1};let n=cd(t,"utf-8");if(n.includes(sn))return{path:t,alreadyInstalled:!0};return O(t,Ah(n)),{path:t,alreadyInstalled:!1}}function fd(e){let t=dd(e);if(!ld(t))return{path:t,alreadyInstalled:!1};let n=cd(t,"utf-8");if(!n.includes(sn))return{path:t,alreadyInstalled:!1};let r=ud(n),o=r?_h(n,r):`${Eh(n)}
|
|
243
|
+
`;return O(t,o),{path:t,alreadyInstalled:!0}}var ei="safety-net@cc-marketplace",md=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gd=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function ni(e){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(e??"")}function Ld(e){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(e??"")}function $h(e){return/^Marketplace `cc-marketplace`\s*$/m.test(e??"")}var wd={"claude-code":{installCommands:(e)=>{let t=On(e,"cc-safety-net@cc-marketplace");return{commands:[...t?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...po(e).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:On(e,ei)?[["claude","plugin","uninstall",ei]]:[],update:t}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(e,t)=>{let n=t??await ue(["codex","plugin","list"]),r=Ld(n);return{commands:[r||$h(n)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:ni(n)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:r}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:"Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."},"copilot-cli":{installCommands:async()=>{let e=await ue(["copilot","plugin","list"]),t=[...ol(e)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...il(e)?[["copilot","plugin","uninstall",tl]]:[]];if(nl(e))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",de]],cleanupCommands:t,update:!0};return{commands:[rl(await ue(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",de]],cleanupCommands:t}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(e)=>{let t=bo(e);if(t.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(t.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:To,installCommands:()=>({commands:Jl()}),uninstallCommands:[["openclaw","plugins","uninstall",A,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
|
|
244
|
+
`)},opencode:{beforeInstall:Oo,installCommands:[["opencode","plugin","-g","-f","cc-safety-net@latest"]]},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function ar(){return process.env.HOME??Th()}function kd(e,t=(n)=>n){try{let n=JSON.parse(t(bd(e,"utf-8")));if(!n||typeof n!=="object"||Array.isArray(n))throw Error(`Settings file ${e} must be a JSON object`);return n}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse ${e}: ${n.message}`);throw n}}function Oh(e){let t=Qo(Jt(e),"settings.json");if(!ti(t))return;let n=kd(t,K),r=n.enabledPlugins;if(!r||typeof r!=="object"||Array.isArray(r))return;if(r[de]!==!1)return;let o=bd(t,"utf-8"),i=o.replace(new RegExp(`("${de}"\\s*:\\s*)false`),"$1true");return r[de]=!0,O(t,i!==o?i:`${JSON.stringify(n,null,2)}
|
|
245
|
+
`),`Enabled ${de} plugin in ${t}`}function Fh(e){let t=Fo(e);if(!ti(t))return;let n=kd(t);if(!Array.isArray(n.packages))return;let r=n.packages.find((o)=>!!o&&typeof o==="object"&&!Array.isArray(o)&&jo(o.source)&&("extensions"in o));if(!r)return;return delete r.extensions,O(t,`${JSON.stringify(n,null,2)}
|
|
246
|
+
`),`Enabled npm:cc-safety-net extensions in ${t}`}function hd(e,t){let n=E({label:t,booleans:Object.fromEntries(pe.map((i)=>[i.target,[i.flag]]))},e),r=n.errors[0];if(r)throw Error(r);let o=pe.filter((i)=>n.flags[i.target]).map((i)=>i.target);if(o.length!==1)throw Error(`Choose exactly one ${t} target: ${pe.map((i)=>i.flag).join(", ")}`);return o[0]}async function xd(e=ar(),t=pt){let[n,r,o]=await Promise.all([t(["amp","plugins","list"],30000),t(["codex","plugin","list"],30000),t(["copilot","--binary-version"])]);return{codexPluginListOutput:r,hooks:vt(process.cwd(),{homeDir:e,ampPluginListOutput:n,codexPluginListOutput:r,copilotCliVersion:o})}}async function jh(e,t=pt){let n=await xd(ar(),t);return n.hooks.filter((r)=>e==="install"?r.configured:r.detected||r.inspectionStatus==="not-inspected").filter((r)=>r.platform!=="codex"||!ni(n.codexPluginListOutput)||Ld(n.codexPluginListOutput)).map((r)=>r.platform)}function Nh(e,t,n){if(t.length>0)return{finish:async()=>[hd(t,e)]};if(!n.selectTargets&&!qo(n.input,n.output))return{finish:async()=>[hd(t,e)]};let r=n.detectConfiguredTargets??(()=>jh(e,n.fetchVersion)),o=Promise.all([rd(n.probeTargets),r()]);return{ready:o,finish:async()=>{let[i,s]=await o,a=od(i,{action:e,configuredTargets:s}),l=n.selectTargets?await n.selectTargets(e,vd(e,a)):await jc(e,vd(e,a),{input:n.input,output:n.output});if(l==="update")return l;if(!l||l.length===0)return null;return Wo(l)}}}async function tt(e,t,n=!1,r){let o=wd[e];o.beforeInstall?.(t);let i=typeof o.installCommands==="function"?await o.installCommands(t,r):{commands:o.installCommands};return await Ao(i.commands),await Gl(i.cleanupCommands??[]),[`${i.update||n?"Updated":"Installed"} ${D(e)} integration`,o.postInstallMessage].filter(Boolean).join(`
|
|
247
|
+
`)}async function xt(e){let t=wd[e];if(!t.uninstallCommands)throw Error(`${D(e)} uninstall is not supported`);return await Ao(t.uninstallCommands),`Uninstalled ${D(e)} integration`}function Hh(e){let t=fc(e);return t.alreadyInstalled?`Uninstalled OpenCode plugin from ${t.path}`:`OpenCode plugin not installed in ${t.path}`}var Mh={"antigravity-cli":{install:Qc,uninstall:ed},cursor:{install:gl,uninstall:hl},"grok-build":{install:Rl,uninstall:Pl},"kimi-code":{install:pd,uninstall:fd}};function Oe(e,t,n,r=!1){if(e==="install"&&!r)ir(n);let o=Mh[t][e](n),i=D(t),s=e!=="install"?"Uninstalled":r?"Updated":"Installed";return e==="install"&&o.alreadyInstalled?r?`${i} hook up to date in ${o.path}`:`${i} hook already installed in ${o.path}`:e==="uninstall"&&!o.alreadyInstalled?`${i} hook not installed in ${o.path}`:`${s} ${i} hook ${e==="install"?"in":"from"} ${o.path}`}var Uh={amp:{install:Kc,uninstall:Jc,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:Tl,uninstall:Il,afterInstall:async(e)=>{let t=Ro(e);return await ue(["hermes","plugins","enable",Q,"--no-allow-tool-override"]),!t},beforeUninstall:async(e)=>{So(e);try{await ue(["hermes","plugins","disable",Q])}catch(t){console.warn(`${t instanceof Error?t.message:String(t)}
|
|
248
|
+
Removing the plugin files anyway; ${Q} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function sr(e,t,n,r=!1){let o=Uh[t];if(e==="uninstall")await o.beforeUninstall?.(n);let i=e==="install"?await o.install(n):await o.uninstall(n),s=e==="install"&&await o.afterInstall?.(n),a=D(t),l=!s&&(e==="install"&&i.alreadyInstalled||e==="uninstall"&&!i.alreadyInstalled);return[l?e==="install"?`${a} plugin ${r?"up to date":"already installed"} at ${i.path}`:`${a} plugin not installed at ${i.path}`:`${e!=="install"?"Uninstalled":r?"Updated":"Installed"} ${a} plugin ${e==="install"?"at":"from"} ${i.path}`,l?void 0:o.restartNote].filter(Boolean).join(`
|
|
249
|
+
`)}var Gh={amp:{install:(e,t)=>sr("install","amp",e,t),uninstall:(e)=>sr("uninstall","amp",e)},"antigravity-cli":{install:(e,t)=>Oe("install","antigravity-cli",e,t),uninstall:(e)=>Oe("uninstall","antigravity-cli",e)},"claude-code":{install:(e,t)=>tt("claude-code",e,t),uninstall:()=>xt("claude-code")},codex:{install:(e,t,n)=>tt("codex",e,t,n),uninstall:()=>xt("codex")},"copilot-cli":{install:async(e,t)=>[await tt("copilot-cli",e,t),Oh(e)].filter(Boolean).join(`
|
|
250
|
+
`),uninstall:()=>xt("copilot-cli")},cursor:{install:(e,t)=>Oe("install","cursor",e,t),uninstall:(e)=>Oe("uninstall","cursor",e)},"gemini-cli":{install:(e,t)=>tt("gemini-cli",e,t),uninstall:()=>xt("gemini-cli")},"grok-build":{install:(e,t)=>Oe("install","grok-build",e,t),uninstall:(e)=>Oe("uninstall","grok-build",e)},"hermes-agent":{install:(e,t)=>{if(!t)ir(e);return sr("install","hermes-agent",e,t)},uninstall:(e)=>sr("uninstall","hermes-agent",e)},"kimi-code":{install:(e,t)=>Oe("install","kimi-code",e,t),uninstall:(e)=>Oe("uninstall","kimi-code",e)},openclaw:{install:async(e,t)=>{let n=await tt("openclaw",e,t);return await Wl(),n},uninstall:(e)=>(To(e),xt("openclaw"))},opencode:{install:async(e,t)=>{let n=await tt("opencode",e,t);return await cc(e),n},uninstall:(e)=>Hh(e)},pi:{install:async(e,t)=>[await tt("pi",e,t),Fh(e)].filter(Boolean).join(`
|
|
227
251
|
`),uninstall:()=>xt("pi")}},yd=["Install CC Safety Net as a native Kimi Code plugin:",""," 1. Start Kimi Code and run: /plugins install https://github.com/kenryu42/cc-safety-net"," Confirm the trust prompt; it defaults to cancel."," 2. Run /reload, or start a new session.","","Note: Kimi Code hooks are fail-open. When the hook process cannot start, crashes, or times","out, Kimi Code allows the tool call."].join(`
|
|
228
|
-
`);function
|
|
252
|
+
`);function Bh(e){if(Qt({homeDir:e,cwd:process.cwd()}).status!=="configured")return yd;return[yd,"",y.red(["CAUTION: the global Kimi Code hook is installed and will run alongside the plugin.","After the plugin is active, remove it with: cc-safety-net uninstall --kimi-code"].join(`
|
|
229
253
|
`))].join(`
|
|
230
|
-
`)}function vd(e,t){return t.map((n)=>e==="install"&&n.target==="kimi-code"&&n.unavailableReason==="already installed"?{...n,available:!0,unavailableReason:void 0,label:`${n.label} (global hook installed)`}:n)}function
|
|
254
|
+
`)}function vd(e,t){return t.map((n)=>e==="install"&&n.target==="kimi-code"&&n.unavailableReason==="already installed"?{...n,available:!0,unavailableReason:void 0,label:`${n.label} (global hook installed)`}:n)}function qh(e,t){if(e.selectKimiInstallMethod)return e.selectKimiInstallMethod();if(!qo(e.input,e.output))return Promise.resolve("global-hook");return Fc({input:e.input,output:e.output,globalHookInstalled:Qt({homeDir:t,cwd:process.cwd()}).status==="configured"})}async function Cd(e,t,n,r=!1,o){return Gh[t][e](n,r,o)}function Vh(e){let t=E({label:"update"},e).errors[0];if(t)throw Error(t)}async function zh(e,t=pt){let n=await xd(e,t),r=Qo(Jt(e),"installed-plugins");return{targets:Wo([...n.hooks.filter((i)=>i.platform!=="copilot-cli"&&i.detected).map((i)=>i.platform),...[Fn,el,Qa].flatMap((i)=>ti(Qo(r,...i))?["copilot-cli"]:[]),...On(e,ei)?["claude-code"]:[],...ni(n.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:n.codexPluginListOutput}}async function Kh(e){let t=ar(),n=e.output??process.stdout,r=(e.scriptPath??process.argv[1]??"").split(/[\\/]/),o=r.find((u)=>/^bunx-\d+-/.test(u)),i=o!==void 0||r.includes("_npx")?null:(e.checkLatestVersion??Te)(),s=async()=>{let u=i&&await i;if(u?.updateAvailable)n.write(`
|
|
231
255
|
Update available: cc-safety-net ${u.currentVersion} → ${u.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
|
|
232
|
-
`)},a=
|
|
233
|
-
`)}),await s(),g.some((u)=>u.failed)?1:0}function ri(e,t={}){return Promise.resolve().then(()=>
|
|
234
|
-
`),0;if(r==="update")return(n.runUpdate??(()=>ri([],{fetchVersion:n.fetchVersion,input:n.input,output:n.output,showBanner:!1})))();let o=ar(),i=n.output??process.stdout;return await nd(r,async(s)=>{if(s==="kimi-code"&&e==="install"){let l=await
|
|
235
|
-
`);return}if(l==="plugin"){i.write(`${
|
|
256
|
+
`)},a=zh(t,e.fetchVersion??pt).then(async(u)=>{let p=new Set(u.targets);return{targets:u.targets,codexPluginListOutput:u.codexPluginListOutput,available:new Map(await Promise.all(pe.filter((f)=>p.has(f.target)&&md.has(f.target)).map(async(f)=>[f.target,await Yo(f.probeCommand)])))}}),l=await Kt(e.showBanner??!0,()=>({ready:a,finish:()=>a}),()=>zt({input:e.input??process.stdin,output:n}),{loadingMessage:"Checking installed integrations…",output:n}),c=await Promise.resolve().then(()=>(td(Ih(),process.platform,o),null)).catch((u)=>an(u));if(l.targets.length===0){if(n.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),c!==null)console.error(c);return await s(),c===null?0:1}let d=l.targets.some((u)=>gd.has(u))?await Promise.resolve().then(()=>(ir(t),null)).catch((u)=>an(u)):null,m=await Tn(Promise.all(l.targets.map((u)=>{if(md.has(u)&&!l.available.get(u))return Promise.resolve({message:`${D(u)} not found; skipped`,failed:!1});if(d!==null&&gd.has(u))return Promise.resolve({message:d,failed:!0});return Cd("install",u,t,!0,l.codexPluginListOutput).then((p)=>({message:p,failed:!1}),(p)=>({message:an(p),failed:!0}))})),{loadingMessage:`Updating ${l.targets.length} integration${l.targets.length===1?"":"s"}…`,output:n}),g=c===null?m:[...m,{message:c,failed:!0}];return g.forEach((u)=>{u.failed?console.error(u.message):n.write(`${u.message}
|
|
257
|
+
`)}),await s(),g.some((u)=>u.failed)?1:0}function ri(e,t={}){return Promise.resolve().then(()=>Vh(e)).then(()=>Kh(t)).catch((n)=>(console.error(an(n)),1))}async function ln(e,t,n={}){try{let r=await Kt(!0,()=>Nh(e,t,n),()=>zt({input:n.input??process.stdin,output:n.output??process.stdout}),{loadingMessage:e==="install"?"Checking available integrations…":"Checking installed integrations…",output:n.output??process.stdout});if(!r)return(n.output??process.stdout).write(`Cancelled: nothing was ${e}ed.
|
|
258
|
+
`),0;if(r==="update")return(n.runUpdate??(()=>ri([],{fetchVersion:n.fetchVersion,input:n.input,output:n.output,showBanner:!1})))();let o=ar(),i=n.output??process.stdout;return await nd(r,async(s)=>{if(s==="kimi-code"&&e==="install"){let l=await qh(n,o);if(l===null){i.write(`Cancelled: Kimi Code integration was not installed.
|
|
259
|
+
`);return}if(l==="plugin"){i.write(`${Bh(o)}
|
|
236
260
|
`);return}}let a=await Tn(Cd(e,s,o),{loadingMessage:`${e==="install"?"Installing":"Uninstalling"} ${D(s)} integration…`,output:i});i.write(`${a}
|
|
237
261
|
`)}),0}catch(r){return console.error(an(r)),1}}function an(e){let t=e instanceof Error?e.message:String(e),n=typeof e==="object"&&e!==null&&"code"in e?e.code:null;if(n==="EACCES"||n==="EPERM")return`${t}
|
|
238
262
|
Check file permissions for the target config file and parent directory.`;if(n==="ENOENT")return`${t}
|
|
239
263
|
Check that the target config path and parent directory exist.`;if(n==="ENOTDIR")return`${t}
|
|
240
|
-
Check that every parent path component is a directory.`;return t}import{mkdirSync as Vh}from"node:fs";import{dirname as zh}from"node:path";import{createInterface as Kh}from"node:readline";var Sd=new Set(["check","apply"]),Rd="(unset)";async function Dd(e,t={}){let n=E({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},e),r=n.positionals[0],o=[...n.errors,...r&&!Sd.has(r)?[`Unknown policy subcommand: ${r}`]:[],...r&&Sd.has(r)&&!n.positionals[1]?[`policy ${r} requires a file`]:[],...n.positionals.slice(2).map((u)=>`Unexpected policy argument: ${u}`)];if(o.length>0){for(let u of o)console.error(u);return 1}let i=n.positionals[1];if(!r||!i)return bt(xn,console.error),1;let s=n.flags.global?ve():se(t.cwd??process.cwd()),a=_e(i),l=[...a.errors,...Ee(a.value).map((u)=>`${i}: ${u}`),...!n.flags.global&&Yh(a.value)&&a.value.audit!==void 0?[`${i}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(l.length>0){for(let u of l)console.error(u);return 1}let c=Y(a.value);if(console.log(`Scope: ${n.flags.global?"user":"project"} (${s})`),console.log(`Proposal: ${i}`),n.flags.global)Pd(Y(_e(s).value),c,!0);if(!n.flags.global){let u=lt().baseline;console.log("Effective policy (user + project merged):"),Pd(Ge(u,Be(_e(s).value).policy).policy,Ge(u,Be(a.value).policy).policy,!1)}if(r==="check")return 0;let d=t.input??process.stdin,m=t.output??process.stdout;if(!d.isTTY||!m.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${i}${n.flags.global?" --global":""}`),1;if(!await Jh(`Apply this policy to ${s}? [y/N] `,d,m))return console.log("Cancelled; nothing was written."),0;return Wh(s,a.value,c,n.flags.global),console.log(`Policy applied: ${s}`),0}function Jh(e,t,n){let r=Kh({input:t,output:n,terminal:!1});return new Promise((o)=>{r.once("close",()=>o(!1)),r.question(e,(i)=>{o(/^y(es)?$/i.test(i.trim())),r.close()})})}function Wh(e,t,n,r){if(r){cn(n);return}Vh(zh(e),{recursive:!0}),J(e,jt(t,n))}function Pd(e,t,n){let r=Ft(e,t,n);if(r.length===0){console.log("No changes.");return}console.log(`Changes (${r.length}):`);for(let o of r)console.log(` ${o.field}: ${o.before??Rd} -> ${o.after??Rd}`)}function Yh(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}import{join as Ty}from"node:path";var Ad="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function lr(e,t){if(!e.ok){$d(e);return}Td(e,t)}function _d(e,t,n){if(e.ok)console.log(n);if(!e.add){lr(e,`Added rulebook source: ${t}`);return}if(!e.ok){$d(e);return}if(e.add.added.length>0)console.log(`Added ${e.add.added.length} ${e.add.added.length===1?"rulebook":"rulebooks"} from ${e.add.source} at ${e.add.ref}:`),e.add.added.forEach((r)=>{console.log(` - ${r}`)});if(e.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${e.add.source} at ${e.add.ref}: ${e.add.alreadyConfigured.join(", ")}`);if(e.add.commits.length>0)console.log(`Vendored at ${e.add.commits.map((r)=>r.slice(0,7)).join(", ")}.`);Td(e,"Rule config updated.")}function Td(e,t){for(let n of e.changes??[])console.log(n);console.log(t),console.log(""),Zh(e.entries)}function Zh(e){if(e.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${e.length}):`);for(let t of e)console.log(` - ${t.name} ${t.version} (${Xh(t.ruleCount)})`),console.log(` Source: ${t.spec}`)}function Xh(e){return`${e} ${e===1?"rule":"rules"}`}function Id(e){nt("Active sources",e.rulebooks,(t)=>[`[${t.source}] ${t.name} ${t.version}`,` Source: ${t.spec}`]),nt("Active rules",e.rules,(t)=>[`[${ey(e,t.name)}] ${t.name}`,...Qh(t),` Reason: ${t.reason}`]),nt("Disabled rules",Ed(e,"off"),(t)=>[t.key]),nt("Reason overrides",Ed(e,"reason"),(t)=>[t.key,` Reason: ${t.value.reason}`]),nt("Transparent wrappers",e.transparent_wrappers,(t)=>[t]),nt("Issues",e.errors,(t)=>[t]),nt("Warnings",e.warnings,(t)=>[t])}function nt(e,t,n){if(t.length===0){console.log(`${e}: (none)`);return}console.log(`${e} (${t.length}):`);for(let r of t){let[o,...i]=n(r);console.log(` - ${o}`);for(let s of i)console.log(` ${s}`)}}function Qh(e){if(!e.match)return[` Command: ${e.subcommand?`${e.command} ${e.subcommand}`:e.command}`,` Block args: ${e.block_args.join(", ")}`];return[` Command: ${[e.command,...e.match.command_path].join(" ")}`,...e.match.any_args?[` Any args: ${e.match.any_args.join(", ")}`]:[],...e.match.exclude_args?[` Exclude args: ${e.match.exclude_args.join(", ")}`]:[]]}function ey(e,t){return e.rulebooks.find((n)=>n.rules.includes(t))?.source??"project"}function Ed(e,t){return Object.entries({...e.userConfig?.overrides??{},...e.projectConfig?.overrides??{}}).filter((n)=>{if(t==="off")return n[1]==="off";return!!n[1]&&typeof n[1]==="object"}).map(([n,r])=>({key:n,value:r}))}function $d(e){for(let t of e.errors)console.error(t)}import{dirname as Od,join as cr}from"node:path";var ty=".safety-net.json",ny="~/.cc-safety-net/config.json";async function Hd(e){return[await Fd({legacyPath:Nd({cwd:e.cwd}),configPath:oe(e.cwd),defaultRulebookName:"project-rules",migratedFrom:ty,cleanup:e.cleanup,syncOptions:{cwd:e.cwd}}),await Fd({legacyPath:It(),configPath:ie(),defaultRulebookName:"user-rules",migratedFrom:ny,cleanup:e.cleanup,syncOptions:{cwd:e.cwd,global:!0}})].every((n)=>n)?0:1}async function Fd(e){let t=U(e.syncOptions),n=x(t.filesystemScope,e.legacyPath),r=w(n);if(r===null)return console.log(`No legacy config found at ${e.legacyPath}`),!0;let o=oy(r);if(!o.ok){for(let g of o.errors)console.error(g);return!1}let i=q(t.configTarget);if(i.errors.length>0){for(let g of i.errors)console.error(g);return!1}let s=i.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},a=iy(Od(e.configPath),s.rules,e.defaultRulebookName,e.migratedFrom,t.filesystemScope),l=cr(Od(e.configPath),a,"rulebook.json"),c=x(t.filesystemScope,l),d=[jd(t.configTarget),jd(c)],m=await ry(e,t.configTarget,c,a,o.config.rules,s.rules.includes(a)?s.rules:[...s.rules,a],s.overrides??{},s.transparent_wrappers??[]);if(!m.ok){ly(d);for(let g of m.errors)console.error(g);return!1}if(!e.cleanup)return console.log(`Migrated legacy config at ${e.legacyPath}. Legacy file is no longer used.`),!0;if(!ay(t.configTarget,c,a,e.migratedFrom,o.config.rules))return console.error(`Migration cleanup verification failed for ${e.legacyPath}`),!1;return he(n),console.log(`Deleted legacy config at ${e.legacyPath}`),!0}async function ry(e,t,n,r,o,i,s,a){try{return J(t,{version:1,rules:i,overrides:s,transparent_wrappers:a}),J(n,sy(r,e.migratedFrom,o)),await Tt(e.syncOptions)}catch(l){return{ok:!1,errors:[l instanceof Error?l.message:String(l)]}}}function oy(e){try{let t=JSON.parse(e),n=Lr(t);if(n.errors.length>0)return{ok:!1,errors:n.errors};return{ok:!0,config:{version:1,rules:t.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function iy(e,t,n,r,o){let i=t.find((s)=>cy(x(o,cr(e,s,"rulebook.json")))===r);if(i)return i;if(w(x(o,cr(e,n,"rulebook.json")))===null)return n;for(let s=2;;s++){let a=`${n}-${s}`;if(w(x(o,cr(e,a,"rulebook.json")))===null)return a}}function sy(e,t,n){return{rulebook_version:1,name:e,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:t,allowed_commands:[...new Set(n.map((r)=>r.command))],rules:n,tests:n.map((r)=>({command:[r.command,r.subcommand,r.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:r.name}))}}function ay(e,t,n,r,o){if(!q(e).config?.rules.includes(n))return!1;try{let s=w(t);if(s===null)return!1;let a=JSON.parse(s);return a.migrated_from===r&&JSON.stringify(a.rules)===JSON.stringify(o)}catch{return!1}}function jd(e){return{target:e,content:w(e)}}function ly(e){for(let t of e){if(t.content===null){he(t.target);continue}B(t.target,t.content)}}function cy(e){let t=w(e);if(t===null)return null;try{let n=JSON.parse(t);return typeof n.migrated_from==="string"?n.migrated_from:null}catch{return null}}import{mkdir as dy,readFile as uy,writeFile as py}from"node:fs/promises";import{dirname as fy,join as my}from"node:path";var gy=86400000,hy=604800000;async function Ud(e=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=Mr();if(!t)return null;let n=my(t,".cc-safety-net","update-check.json"),r=await yy(n,e);if(!r.lastCheck||e-r.lastCheck>gy){let s=await Te();if(r.lastCheck=e,s.latestVersion)r.latestVersion=s.latestVersion;if(!await Md(n,r))return null;if(s.error)return null}let o=r.latestVersion,i=I();if(!o||!so(o,i))return null;if(r.notifiedVersion===o&&r.notifiedAt!==void 0&&e-r.notifiedAt<hy)return null;if(r.notifiedVersion=o,r.notifiedAt=e,!await Md(n,r))return null;return`UPDATE_AVAILABLE: cc-safety-net v${o} is available (running v${i}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function yy(e,t){let n=await uy(e,"utf8").then((i)=>JSON.parse(i)).catch(()=>{return});if(!n||typeof n!=="object"||Array.isArray(n))return{};let r=n,o=(i)=>typeof i==="number"&&Number.isFinite(i)&&i<=t?i:void 0;return{lastCheck:o(r.lastCheck),latestVersion:typeof r.latestVersion==="string"?r.latestVersion:void 0,notifiedVersion:typeof r.notifiedVersion==="string"?r.notifiedVersion:void 0,notifiedAt:o(r.notifiedAt)}}async function Md(e,t){return dy(fy(e),{recursive:!0,mode:448}).then(()=>py(e,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as vy,resolve as oi}from"node:path";var Gd="CC Safety Net Config",by="═".repeat(Gd.length),Ly="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",wy=new Set(["rule.json","rule.lock","cache"]);function Bd(e={}){try{return ky(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}function ky(e){let t=e.cwd??process.cwd(),n=e.userConfigPath??ie(),r=e.projectConfigPath??oe(t),o=e.legacyUserConfigPath??It(),i=e.legacyProjectConfigPath??Ai(t),s=oi(t,Pt),a=Ae({cwd:t,userConfigPath:n,projectConfigPath:r}),l=Ae({cwd:t}),c=x(a.userScope,n),d=x(a.projectScope,r),m=e.legacyUserConfigPath?St(e.legacyUserConfigPath,"user policy"):x(l.userScope,o),g=e.legacyProjectConfigPath?St(e.legacyProjectConfigPath,"project policy"):x(l.projectScope,i),u=!1,p=!1,f=[],b=[],L=xy(x(l.projectScope,s));if(Sy(),w(c)!==null){let h=me(c);if(h.errors.push(...W(n,a.userScope)),f.push({scope:"User",path:n,result:h,schema:"rules",target:c}),h.errors.length>0)u=!0}if(w(m)!==null)if(p=!0,w(c)!==null)b.push(dr("user","cleanup"));else{let h=wr(m);if(f.push({scope:"User",path:o,result:h,schema:"legacy",inactive:!0,target:m}),b.push(dr("user",h.errors.length>0?"fix-or-delete":"migrate")),h.errors.length>0)u=!0}if(w(d)!==null){let h=me(d);if(h.errors.push(...W(r,a.projectScope)),f.push({scope:"Project",path:oi(r),result:h,schema:"rules",target:d}),h.errors.length>0)u=!0;if(w(g)!==null)p=!0,b.push(dr("project","cleanup"))}else if(w(g)!==null){p=!0,u=!0;let h=wr(g);f.push({scope:"Project",path:oi(i),result:h,schema:"legacy",inactive:!0,target:g}),b.push(dr("project",h.errors.length>0?"fix-or-delete":"migrate"))}if(L?.result.errors.length)u=!0;if(f.length===0&&!L)return console.log(`
|
|
241
|
-
No config files found. Using built-in rules only.`),0;for(let h of f)if(h.inactive)
|
|
242
|
-
Added $schema to ${h.scope.toLowerCase()} config.`);
|
|
243
|
-
${y.red(h)}`);if(L)if(L.result.errors.length>0)
|
|
264
|
+
Check that every parent path component is a directory.`;return t}import{mkdirSync as Jh}from"node:fs";import{dirname as Wh}from"node:path";import{createInterface as Yh}from"node:readline";var Sd=new Set(["check","apply"]),Rd="(unset)";async function Dd(e,t={}){let n=E({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},e),r=n.positionals[0],o=[...n.errors,...r&&!Sd.has(r)?[`Unknown policy subcommand: ${r}`]:[],...r&&Sd.has(r)&&!n.positionals[1]?[`policy ${r} requires a file`]:[],...n.positionals.slice(2).map((u)=>`Unexpected policy argument: ${u}`)];if(o.length>0){for(let u of o)console.error(u);return 1}let i=n.positionals[1];if(!r||!i)return bt(xn,console.error),1;let s=n.flags.global?ve():se(t.cwd??process.cwd()),a=_e(i),l=[...a.errors,...Ee(a.value).map((u)=>`${i}: ${u}`),...!n.flags.global&&Qh(a.value)&&a.value.audit!==void 0?[`${i}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(l.length>0){for(let u of l)console.error(u);return 1}let c=Y(a.value);if(console.log(`Scope: ${n.flags.global?"user":"project"} (${s})`),console.log(`Proposal: ${i}`),n.flags.global)Pd(Y(_e(s).value),c,!0);if(!n.flags.global){let u=lt().baseline;console.log("Effective policy (user + project merged):"),Pd(Ge(u,Be(_e(s).value).policy).policy,Ge(u,Be(a.value).policy).policy,!1)}if(r==="check")return 0;let d=t.input??process.stdin,m=t.output??process.stdout;if(!d.isTTY||!m.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${i}${n.flags.global?" --global":""}`),1;if(!await Zh(`Apply this policy to ${s}? [y/N] `,d,m))return console.log("Cancelled; nothing was written."),0;return Xh(s,a.value,c,n.flags.global),console.log(`Policy applied: ${s}`),0}function Zh(e,t,n){let r=Yh({input:t,output:n,terminal:!1});return new Promise((o)=>{r.once("close",()=>o(!1)),r.question(e,(i)=>{o(/^y(es)?$/i.test(i.trim())),r.close()})})}function Xh(e,t,n,r){if(r){cn(n);return}Jh(Wh(e),{recursive:!0}),J(e,jt(t,n))}function Pd(e,t,n){let r=Ft(e,t,n);if(r.length===0){console.log("No changes.");return}console.log(`Changes (${r.length}):`);for(let o of r)console.log(` ${o.field}: ${o.before??Rd} -> ${o.after??Rd}`)}function Qh(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}import{join as Oy}from"node:path";var Ad="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function lr(e,t){if(!e.ok){$d(e);return}Td(e,t)}function _d(e,t,n){if(e.ok)console.log(n);if(!e.add){lr(e,`Added rulebook source: ${t}`);return}if(!e.ok){$d(e);return}if(e.add.added.length>0)console.log(`Added ${e.add.added.length} ${e.add.added.length===1?"rulebook":"rulebooks"} from ${e.add.source} at ${e.add.ref}:`),e.add.added.forEach((r)=>{console.log(` - ${r}`)});if(e.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${e.add.source} at ${e.add.ref}: ${e.add.alreadyConfigured.join(", ")}`);if(e.add.commits.length>0)console.log(`Vendored at ${e.add.commits.map((r)=>r.slice(0,7)).join(", ")}.`);Td(e,"Rule config updated.")}function Td(e,t){for(let n of e.changes??[])console.log(n);console.log(t),console.log(""),ey(e.entries)}function ey(e){if(e.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${e.length}):`);for(let t of e)console.log(` - ${t.name} ${t.version} (${ty(t.ruleCount)})`),console.log(` Source: ${t.spec}`)}function ty(e){return`${e} ${e===1?"rule":"rules"}`}function Id(e){nt("Active sources",e.rulebooks,(t)=>[`[${t.source}] ${t.name} ${t.version}`,` Source: ${t.spec}`]),nt("Active rules",e.rules,(t)=>[`[${ry(e,t.name)}] ${t.name}`,...ny(t),` Reason: ${t.reason}`]),nt("Disabled rules",Ed(e,"off"),(t)=>[t.key]),nt("Reason overrides",Ed(e,"reason"),(t)=>[t.key,` Reason: ${t.value.reason}`]),nt("Transparent wrappers",e.transparent_wrappers,(t)=>[t]),nt("Issues",e.errors,(t)=>[t]),nt("Warnings",e.warnings,(t)=>[t])}function nt(e,t,n){if(t.length===0){console.log(`${e}: (none)`);return}console.log(`${e} (${t.length}):`);for(let r of t){let[o,...i]=n(r);console.log(` - ${o}`);for(let s of i)console.log(` ${s}`)}}function ny(e){if(!e.match)return[` Command: ${e.subcommand?`${e.command} ${e.subcommand}`:e.command}`,` Block args: ${e.block_args.join(", ")}`];return[` Command: ${[e.command,...e.match.command_path].join(" ")}`,...e.match.any_args?[` Any args: ${e.match.any_args.join(", ")}`]:[],...e.match.exclude_args?[` Exclude args: ${e.match.exclude_args.join(", ")}`]:[]]}function ry(e,t){return e.rulebooks.find((n)=>n.rules.includes(t))?.source??"project"}function Ed(e,t){return Object.entries({...e.userConfig?.overrides??{},...e.projectConfig?.overrides??{}}).filter((n)=>{if(t==="off")return n[1]==="off";return!!n[1]&&typeof n[1]==="object"}).map(([n,r])=>({key:n,value:r}))}function $d(e){for(let t of e.errors)console.error(t)}import{dirname as Od,join as cr}from"node:path";var oy=".safety-net.json",iy="~/.cc-safety-net/config.json";async function Hd(e){return[await Fd({legacyPath:Nd({cwd:e.cwd}),configPath:oe(e.cwd),defaultRulebookName:"project-rules",migratedFrom:oy,cleanup:e.cleanup,syncOptions:{cwd:e.cwd}}),await Fd({legacyPath:It(),configPath:ie(),defaultRulebookName:"user-rules",migratedFrom:iy,cleanup:e.cleanup,syncOptions:{cwd:e.cwd,global:!0}})].every((n)=>n)?0:1}async function Fd(e){let t=U(e.syncOptions),n=x(t.filesystemScope,e.legacyPath),r=w(n);if(r===null)return console.log(`No legacy config found at ${e.legacyPath}`),!0;let o=ay(r);if(!o.ok){for(let g of o.errors)console.error(g);return!1}let i=q(t.configTarget);if(i.errors.length>0){for(let g of i.errors)console.error(g);return!1}let s=i.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},a=ly(Od(e.configPath),s.rules,e.defaultRulebookName,e.migratedFrom,t.filesystemScope),l=cr(Od(e.configPath),a,"rulebook.json"),c=x(t.filesystemScope,l),d=[jd(t.configTarget),jd(c)],m=await sy(e,t.configTarget,c,a,o.config.rules,s.rules.includes(a)?s.rules:[...s.rules,a],s.overrides??{},s.transparent_wrappers??[]);if(!m.ok){uy(d);for(let g of m.errors)console.error(g);return!1}if(!e.cleanup)return console.log(`Migrated legacy config at ${e.legacyPath}. Legacy file is no longer used.`),!0;if(!dy(t.configTarget,c,a,e.migratedFrom,o.config.rules))return console.error(`Migration cleanup verification failed for ${e.legacyPath}`),!1;return he(n),console.log(`Deleted legacy config at ${e.legacyPath}`),!0}async function sy(e,t,n,r,o,i,s,a){try{return J(t,{version:1,rules:i,overrides:s,transparent_wrappers:a}),J(n,cy(r,e.migratedFrom,o)),await Tt(e.syncOptions)}catch(l){return{ok:!1,errors:[l instanceof Error?l.message:String(l)]}}}function ay(e){try{let t=JSON.parse(e),n=Lr(t);if(n.errors.length>0)return{ok:!1,errors:n.errors};return{ok:!0,config:{version:1,rules:t.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function ly(e,t,n,r,o){let i=t.find((s)=>py(x(o,cr(e,s,"rulebook.json")))===r);if(i)return i;if(w(x(o,cr(e,n,"rulebook.json")))===null)return n;for(let s=2;;s++){let a=`${n}-${s}`;if(w(x(o,cr(e,a,"rulebook.json")))===null)return a}}function cy(e,t,n){return{rulebook_version:1,name:e,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:t,allowed_commands:[...new Set(n.map((r)=>r.command))],rules:n,tests:n.map((r)=>({command:[r.command,r.subcommand,r.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:r.name}))}}function dy(e,t,n,r,o){if(!q(e).config?.rules.includes(n))return!1;try{let s=w(t);if(s===null)return!1;let a=JSON.parse(s);return a.migrated_from===r&&JSON.stringify(a.rules)===JSON.stringify(o)}catch{return!1}}function jd(e){return{target:e,content:w(e)}}function uy(e){for(let t of e){if(t.content===null){he(t.target);continue}B(t.target,t.content)}}function py(e){let t=w(e);if(t===null)return null;try{let n=JSON.parse(t);return typeof n.migrated_from==="string"?n.migrated_from:null}catch{return null}}import{mkdir as fy,readFile as my,writeFile as gy}from"node:fs/promises";import{dirname as hy,join as yy}from"node:path";var vy=86400000,by=604800000;async function Ud(e=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=Mr();if(!t)return null;let n=yy(t,".cc-safety-net","update-check.json"),r=await Ly(n,e);if(!r.lastCheck||e-r.lastCheck>vy){let s=await Te();if(r.lastCheck=e,s.latestVersion)r.latestVersion=s.latestVersion;if(!await Md(n,r))return null;if(s.error)return null}let o=r.latestVersion,i=I();if(!o||!so(o,i))return null;if(r.notifiedVersion===o&&r.notifiedAt!==void 0&&e-r.notifiedAt<by)return null;if(r.notifiedVersion=o,r.notifiedAt=e,!await Md(n,r))return null;return`UPDATE_AVAILABLE: cc-safety-net v${o} is available (running v${i}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function Ly(e,t){let n=await my(e,"utf8").then((i)=>JSON.parse(i)).catch(()=>{return});if(!n||typeof n!=="object"||Array.isArray(n))return{};let r=n,o=(i)=>typeof i==="number"&&Number.isFinite(i)&&i<=t?i:void 0;return{lastCheck:o(r.lastCheck),latestVersion:typeof r.latestVersion==="string"?r.latestVersion:void 0,notifiedVersion:typeof r.notifiedVersion==="string"?r.notifiedVersion:void 0,notifiedAt:o(r.notifiedAt)}}async function Md(e,t){return fy(hy(e),{recursive:!0,mode:448}).then(()=>gy(e,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as wy,resolve as oi}from"node:path";var Gd="CC Safety Net Config",ky="═".repeat(Gd.length),xy="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Cy=new Set(["rule.json","rule.lock","cache"]);function Bd(e={}){try{return Sy(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}function Sy(e){let t=e.cwd??process.cwd(),n=e.userConfigPath??ie(),r=e.projectConfigPath??oe(t),o=e.legacyUserConfigPath??It(),i=e.legacyProjectConfigPath??Ai(t),s=oi(t,Pt),a=Ae({cwd:t,userConfigPath:n,projectConfigPath:r}),l=Ae({cwd:t}),c=x(a.userScope,n),d=x(a.projectScope,r),m=e.legacyUserConfigPath?St(e.legacyUserConfigPath,"user policy"):x(l.userScope,o),g=e.legacyProjectConfigPath?St(e.legacyProjectConfigPath,"project policy"):x(l.projectScope,i),u=!1,p=!1,f=[],b=[],L=Ry(x(l.projectScope,s));if(Dy(),w(c)!==null){let h=me(c);if(h.errors.push(...W(n,a.userScope)),f.push({scope:"User",path:n,result:h,schema:"rules",target:c}),h.errors.length>0)u=!0}if(w(m)!==null)if(p=!0,w(c)!==null)b.push(dr("user","cleanup"));else{let h=wr(m);if(f.push({scope:"User",path:o,result:h,schema:"legacy",inactive:!0,target:m}),b.push(dr("user",h.errors.length>0?"fix-or-delete":"migrate")),h.errors.length>0)u=!0}if(w(d)!==null){let h=me(d);if(h.errors.push(...W(r,a.projectScope)),f.push({scope:"Project",path:oi(r),result:h,schema:"rules",target:d}),h.errors.length>0)u=!0;if(w(g)!==null)p=!0,b.push(dr("project","cleanup"))}else if(w(g)!==null){p=!0,u=!0;let h=wr(g);f.push({scope:"Project",path:oi(i),result:h,schema:"legacy",inactive:!0,target:g}),b.push(dr("project",h.errors.length>0?"fix-or-delete":"migrate"))}if(L?.result.errors.length)u=!0;if(f.length===0&&!L)return console.log(`
|
|
265
|
+
No config files found. Using built-in rules only.`),0;for(let h of f)if(h.inactive)Ey(h.scope,h.path,h.result);else if(h.result.errors.length>0)_y(h.scope,h.path,h.result.errors);else{if(h.schema==="rules"&&$y(h.target))console.log(`
|
|
266
|
+
Added $schema to ${h.scope.toLowerCase()} config.`);Ay(h.scope,h.path,h.result,h.schema)}for(let h of b)console.error(`
|
|
267
|
+
${y.red(h)}`);if(L)if(L.result.errors.length>0)Iy(L.path,L.result.errors);else Ty(L.path,L.result);if(u)return console.error(`
|
|
244
268
|
Config validation failed.`),1;return console.log(p?`
|
|
245
269
|
Configs valid with warnings.`:`
|
|
246
|
-
All configs valid.`),0}function dr(e,t){let n=`legacy ${e} config`;if(t==="cleanup")return`Warning: Legacy ${e} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(t==="migrate")return`Warning: Legacy ${e} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${e} config is no longer supported. Fix or delete the ${n}, then run \`npx -y cc-safety-net rule migrate\`.`}function
|
|
247
|
-
✓ ${e} config: ${t}`),console.log(` Schema: ${r==="rules"?"rulebook sources":"legacy inline rules"}`),n.ruleNames.size>0){console.log(` ${r==="rules"?"Sources":"Rules"}:`);let o=1;for(let i of n.ruleNames)console.log(` ${o}. ${i}`),o++}else console.log(` ${r==="rules"?"Sources":"Rules"}: (none)`)}function
|
|
248
|
-
✗ Legacy ${e.toLowerCase()} config: ${t}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),n.errors.length>0){console.error(" Errors:");let r=1;for(let o of n.errors)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++;return}if(n.ruleNames.size>0){console.error(" Rules:");let r=1;for(let o of n.ruleNames)console.error(` ${r}. ${o}`),r++;return}console.error(" Rules: (none)")}function
|
|
249
|
-
✓ GitHub source rules: ${e}`),console.log(" Rulebooks:");let n=1;for(let r of t.ruleNames)console.log(` ${n}. ${r}`),n++}function
|
|
250
|
-
✗ ${e}: ${t}`),console.error(" Errors:");let r=1;for(let o of n)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++}function
|
|
251
|
-
`))}import{spawn as fu}from"node:child_process";import{randomBytes as
|
|
270
|
+
All configs valid.`),0}function dr(e,t){let n=`legacy ${e} config`;if(t==="cleanup")return`Warning: Legacy ${e} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(t==="migrate")return`Warning: Legacy ${e} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${e} config is no longer supported. Fix or delete the ${n}, then run \`npx -y cc-safety-net rule migrate\`.`}function Ry(e){if(it(e)===null)return null;let t=Py(e);if(t.ruleNames.size===0&&t.errors.length===0)return null;return{path:e.path,result:t}}function Py(e){let t=[],n=new Set,r=(it(e)??[]).filter((o)=>!Cy.has(o.name)).sort((o,i)=>o.name.localeCompare(i.name));if(r.length===0)return{errors:t,ruleNames:n};for(let o of r){if(!Pe.test(o.name)){t.push(`rulebook directory names must match ${Pe}: ${o.name}`);continue}if(o.kind!=="directory"){t.push(`${o.name} must be a rulebook directory`);continue}let i=x(e.scope,wy(e.path,o.name,"rulebook.json")),s=w(i);if(s===null){t.push(`${o.name}/rulebook.json is required`);continue}try{let a;try{a=JSON.parse(s)}catch{t.push(`${o.name}/rulebook.json: invalid JSON`);continue}let l=Dt(a);if(l.name!==o.name){t.push(`rulebook name "${l.name}" must match folder "${o.name}"`);continue}let c=fn(l);if(c.length>0){t.push(...c.map((d)=>`${o.name}/rulebook.json: ${d}`));continue}n.add(o.name)}catch(a){t.push(a instanceof Error?`${o.name}/rulebook.json: ${a.message}`:`${o.name}/rulebook.json: ${String(a)}`)}}return{errors:t,ruleNames:n}}function Dy(){console.log(Gd),console.log(ky)}function Ay(e,t,n,r){if(console.log(`
|
|
271
|
+
✓ ${e} config: ${t}`),console.log(` Schema: ${r==="rules"?"rulebook sources":"legacy inline rules"}`),n.ruleNames.size>0){console.log(` ${r==="rules"?"Sources":"Rules"}:`);let o=1;for(let i of n.ruleNames)console.log(` ${o}. ${i}`),o++}else console.log(` ${r==="rules"?"Sources":"Rules"}: (none)`)}function Ey(e,t,n){if(console.error(`
|
|
272
|
+
✗ Legacy ${e.toLowerCase()} config: ${t}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),n.errors.length>0){console.error(" Errors:");let r=1;for(let o of n.errors)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++;return}if(n.ruleNames.size>0){console.error(" Rules:");let r=1;for(let o of n.ruleNames)console.error(` ${r}. ${o}`),r++;return}console.error(" Rules: (none)")}function _y(e,t,n){qd(`${e} config`,t,n)}function Ty(e,t){console.log(`
|
|
273
|
+
✓ GitHub source rules: ${e}`),console.log(" Rulebooks:");let n=1;for(let r of t.ruleNames)console.log(` ${n}. ${r}`),n++}function Iy(e,t){qd("GitHub source rules",e,t)}function qd(e,t,n){console.error(`
|
|
274
|
+
✗ ${e}: ${t}`),console.error(" Errors:");let r=1;for(let o of n)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++}function $y(e){try{let t=w(e);if(t===null)return!1;let n=JSON.parse(t);if(n.$schema)return!1;return B(e,JSON.stringify({$schema:xy,...n},null,2)),!0}catch(t){if(t instanceof H)throw t;return!1}}var Vd=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),Fy=new Set(["add","remove","list"]),jy="cc-safety-net/rulebooks";async function zd(e){try{return await Ny(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}async function Ny(e){let t=My(e),n=t.help?Hy(t.positionals):null;if(n)return bt(n),0;if(t.errors.length>0){for(let s of t.errors)console.error(s);return 1}let r=t.positionals[0];if(!r)return bt(ut,console.error),1;let o=t.positionals[1],i={global:t.global};if(r==="init"){let s=U(i);qy(s.configTarget);let a=Oy(s.configDir,"example-rules","rulebook.json"),l=x(s.filesystemScope,a);if(t.example&&w(l)===null)jr(l,"example-rules");let c=W(s.configPath,s.filesystemScope);for(let d of c)console.error(d);if(c.length>0)return 1;return console.log("Rule config initialized."),0}if(r==="add"){let s=Kd(t);if(!s)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let a=U(i),l=await Ir(s,{...i,ref:t.ref,rulebooks:t.only.length>0?t.only:void 0});return _d(l,s,`Scope: ${t.global?"user":"project"} (${a.configDir})`),l.ok?0:1}if(r==="remove"){if(!o)return console.error("rule remove requires a source"),1;let s=await Or(o,{...i,deleteSource:t.deleteSource});return lr(s,`Removed rulebook source: ${o}`),s.ok?0:1}if(r==="update"){let s=await Tt({...i,only:o,refresh:!0});return lr(s,"Rule config updated."),s.ok?0:1}if(r==="sync")return Ma({global:t.global});if(r==="list"){let s=De();return Id(s),s.errors.length>0?1:0}if(r==="wrapper")return Vy(t);if(r==="migrate")return Hd({cleanup:t.cleanup,cwd:process.cwd()});if(r==="doc"){console.log(Ad);let s=await Ud();if(s)console.error(s);return 0}if(r==="verify")return Bd();return 1}function Hy(e){if(e.length===0)return ut;let t=ut.subcommands.filter((r)=>r.usage.split(" ")[0]===e[0]);if(t.length===0)return null;if(e.length===1&&t.length>1)return{name:`rule ${e[0]}`,description:`Subcommands of rule ${e[0]}`,usage:`rule ${e[0]} <subcommand>`,subcommands:t,options:[]};let n=e.length===1?t[0]:t.find((r)=>r.usage.split(" ")[1]===e[1]);if(!n)return null;return{name:`rule ${e[0]}`,description:n.description,usage:`rule ${n.usage}`,options:e[0]==="add"?eo:[],examples:e[0]==="add"?to:void 0}}function My(e){let t=E({label:"rule",booleans:{global:["-g","--global"],check:["--check"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"]},lists:{only:["--only"]},positionals:"list"},e),n={...t.flags,ref:t.values.ref,only:t.lists.only??[],help:t.help,positionals:t.positionals,errors:t.errors};return Uy(n),n}function Uy(e){let[t]=e.positionals;if(t&&!Vd.has(t))e.errors.push(`Unknown rule subcommand: ${t}`);if(e.deleteSource&&t!=="remove")if(t&&Vd.has(t))e.errors.push(`Unknown option for rule ${t}: --delete-source`);else e.errors.push("--delete-source is only valid with 'rule remove'");if(e.check&&t)e.errors.push(Ct(t,"--check"));if(e.cleanup&&t!=="migrate")e.errors.push(Ct(t,"--cleanup"));if(e.example&&t!=="init")e.errors.push(Ct(t,"--example"));if(e.ref&&t!=="add")e.errors.push(Ct(t,"--ref"));if(e.only.length>0&&t!=="add")e.errors.push(Ct(t,"--only"));if(t==="add")Gy(e);if(t==="migrate"){if(e.global)e.errors.push(Ct(t,"--global"));if(e.positionals.length>1)e.errors.push(`Unexpected rule migrate argument: ${e.positionals[1]}`)}else if(t==="wrapper")By(e);else if(e.positionals.length>2)e.errors.push(`Unexpected rule argument: ${e.positionals[2]}`);if(t==="list"&&e.global)e.errors.push("Unknown option for rule list: --global")}function Kd(e){if(e.positionals[1])return e.positionals[1];if(e.ref||e.only.length>0)return jy;return}function Gy(e){let t=Kd(e);if(!t)return;if((e.ref||e.only.length>0)&&!Se(t)){if(e.ref)e.errors.push(`--ref can only select a ref for an owner/repo source: ${t}`);if(e.only.length>0)e.errors.push("--only can only select rulebooks from an owner/repo source");return}if(e.ref&&!Ne(e.ref))e.errors.push(`--ref must use valid path segments: ${e.ref}`);let n=e.only.filter((r)=>!Pe.test(r));if(n.length>0)e.errors.push(`Invalid rulebook names: ${n.join(", ")}`)}function Ct(e,t){return e?`Unknown option for rule ${e}: ${t}`:`Unknown option for rule: ${t}`}function By(e){let t=e.positionals[1],n=e.positionals[2];if(!t){e.errors.push("rule wrapper requires add, remove, or list");return}if(!Fy.has(t)){e.errors.push(`Unknown rule wrapper action: ${t}`);return}if(t==="list"){if(n)e.errors.push(`Unexpected rule wrapper argument: ${n}`);return}if(!n){e.errors.push(`rule wrapper ${t} requires a command`);return}if(e.positionals.length>3)e.errors.push(`Unexpected rule wrapper argument: ${e.positionals[3]}`)}function qy(e){if(w(e)===null){Fr(e);return}let t=q(e);if(!t.config)return;J(e,{version:1,rules:t.config.rules,overrides:t.config.overrides??{},transparent_wrappers:t.config.transparent_wrappers??[]})}async function Vy(e){let t=e.positionals[1],n=e.positionals[2],r=U({global:e.global}).configTarget;if(t==="list"){let a=q(r);if(a.errors.length>0){for(let l of a.errors)console.error(l);return 1}return zy(a.config?.transparent_wrappers??[]),0}if(!n||!Ur.test(n))return console.error("transparent wrapper must match command pattern"),1;if(Br(n))return console.error(`reserved command "${n}" cannot be a wrapper`),1;let o=q(r);if(o.errors.length>0){for(let a of o.errors)console.error(a);return 1}let i=o.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},s=t==="add"?[...new Set([...i.transparent_wrappers??[],n])]:(i.transparent_wrappers??[]).filter((a)=>a!==n);return J(r,{version:1,rules:i.rules,overrides:i.overrides??{},transparent_wrappers:s}),console.log(t==="add"?`Added transparent wrapper: ${n}`:`Removed transparent wrapper: ${n}`),0}function zy(e){if(e.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${e.length}):`);for(let t of e)console.log(` - ${t}`)}import{homedir as ai}from"node:os";import{sep as Qy}from"node:path";import{existsSync as Ky,readFileSync as Jy}from"node:fs";import{homedir as Wy}from"node:os";import{join as Yy}from"node:path";async function Zy(e){if(e.isTTY)return null;return(await Wr(e).catch(()=>null))?.trim()||null}function Xy(){if(process.env.CLAUDE_SETTINGS_PATH)return process.env.CLAUDE_SETTINGS_PATH;return Yy(Wy(),".claude","settings.json")}function ii(){let e=Xy();if(!Ky(e))return!1;try{let t=Jy(e,"utf-8"),n=JSON.parse(t);if(!n.enabledPlugins)return!1;let r="cc-safety-net@cc-marketplace";if(!(r in n.enabledPlugins))return!1;return n.enabledPlugins[r]===!0}catch(t){if(Nt(S.debug))console.error(`CC Safety Net debug: failed to read Claude settings: ${e}: ${t instanceof Error?t.message:String(t)}`);return!1}}async function si(e=process.stdin){let t=ii(),n;if(!t)n="\uD83D\uDEE1️ CC Safety Net ❌";else{let o=z({cwd:process.cwd()}),i=o.policy,s=ye(i),a=Object.values(Ue(i,s.capabilities)).some((d)=>d.changesInherited),l={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[a?"custom":s.effectiveLevel],c=(o.policyScopes?.weakenings.length??0)>0?"\uD83D\uDD3B":"";n=`\uD83D\uDEE1️ CC Safety Net ${l}${s.worktreeMode?"\uD83C\uDF33":""}${c}${o.state==="degraded"?"⚠️":""}`}let r=await Zy(e);if(r&&!r.startsWith("{"))console.log(`${r} | ${n}`);else console.log(n)}function Jd(){let e=z({cwd:process.cwd()}),t=e.policy,n=ye(t),r=!!process.env.NO_COLOR||!process.stdout.isTTY,o=Math.min(process.stdout.columns||80,100),i=r?"ok":"✔",s=r?"OFF":"✘",a=(p,f)=>{let b=` ${p.padEnd(13)}${f}`;return(b.length>o?`${b.slice(0,o-1)}…`:b).replaceAll(s,y.red(s))},l=Object.values(Ue(t,n.capabilities)).some((p)=>p.changesInherited),c=(p)=>p===ai()||p.startsWith(`${ai()}${Qy}`)?`~${p.slice(ai().length)}`:p,d={ready:y.green,degraded:y.yellow}[e.state],m=e.policyScopes?.weakenings??[],g=[...ii()?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...e.diagnostics],u=r?"-":"·";console.log([`${r?"":"\uD83D\uDEE1️ "}CC Safety Net — ${d(e.state)}`,"",a("Protection",`destructive ${t.destructiveCommandProtectionEnabled?i:s} secrets ${t.secretProtection.enabled?i:s}`),a("Level",l?`${n.effectiveLevel} (customised)`:n.effectiveLevel),a("Rules",t.rules.length===0?"none active":`${t.rules.length} active`),a("Policy",c(ve())),...e.policyScopes?[a("Project",c(se()))]:[],...n.worktreeMode?[a("Worktree","relaxations active")]:[],"",...m.length===0?[]:[" Project policy",...m.flatMap((p)=>nn(p," ",o-6).map((f,b)=>b===0?` ${f}`:f)),""],...g.length===0?[" Everything configured is active."]:[" Not active",...g.flatMap((p)=>nn(p," ",o-6).map((f,b)=>b===0?` ${u} ${f}`:f)),""," Full report: cc-safety-net doctor"]].join(`
|
|
275
|
+
`))}import{spawn as fu}from"node:child_process";import{randomBytes as d0}from"node:crypto";import{existsSync as u0}from"node:fs";import{createServer as p0}from"node:http";import{Writable as f0}from"node:stream";import{homedir as e0}from"node:os";var ur=500;function t0(e){let t=e.filter((o)=>o.decision!=="allow"),n=e.filter((o)=>o.decision==="allow"),r=Math.min(t.length,Math.max(ur-n.length,Math.ceil(ur/2)));return[...t.slice(0,r),...n.slice(0,ur-r)]}function Wd(e,t=be()){if(t)He(t);let n=(f)=>new Date(f.getFullYear(),f.getMonth(),f.getDate()).getTime(),r=n(new Date),o=new Date(r);o.setDate(o.getDate()-(e-1));let i=o.getTime(),s=[],a={count:0};for(let f of t?Ce(t,a):[])for(let b of Fe(f,a)){if(!b||typeof b.ts!=="string"||typeof b.command!=="string")continue;let L=new Date(b.ts).getTime();if(!Number.isFinite(L))continue;if(L>=i)s.push(b)}s.sort((f,b)=>new Date(b.ts).getTime()-new Date(f.ts).getTime());let l=Array.from({length:e},()=>0),c=Array.from({length:e},()=>0),d={},m={},g={},u=0,p=0;for(let f of s){let b=f.agent||"unknown";d[b]=(d[b]??0)+1;let L=Math.round((r-n(new Date(f.ts)))/86400000),h=e-1-L,R=L>=0&&L<e;if(R)c[h]=(c[h]??0)+1;if(f.decision!=="allow"){if(u++,f.ruleId)m[f.ruleId]=(m[f.ruleId]??0)+1;let v=rt(f.segment||f.command);if(v)g[v]=(g[v]??0)+1;if(f.failureStage)p++;if(R)l[h]=(l[h]??0)+1}}return{days:e,logsDir:t,homeDir:e0(),totalInWindow:s.length,truncated:s.length>ur,unreadable:a.count,counts:{blocked:u,allowed:s.length-u,agents:d,blockedByDay:l,analyzedByDay:c,rules:m,commands:g,errors:p},entries:t0(s).sort((f,b)=>new Date(b.ts).getTime()-new Date(f.ts).getTime())}}import{spawn as n0}from"node:child_process";import{existsSync as r0,statSync as Yd}from"node:fs";import{delimiter as o0,join as i0}from"node:path";var s0=120000,pr="Choose the project folder",a0=`try
|
|
252
276
|
return POSIX path of (choose folder with prompt "${pr}")
|
|
253
277
|
on error number -128
|
|
254
278
|
return ""
|
|
255
|
-
end try`,
|
|
279
|
+
end try`,l0=`Add-Type -AssemblyName System.Windows.Forms
|
|
256
280
|
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
257
281
|
$dialog.Description = '${pr}'
|
|
258
|
-
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Zd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${pr}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",pr]}],Xd=(e,t)=>(t.PATH??"").split(
|
|
282
|
+
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Zd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${pr}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",pr]}],Xd=(e,t)=>(t.PATH??"").split(o0).some((n)=>{if(n.length===0)return!1;try{let r=Yd(i0(n,e));return r.isFile()&&(r.mode&73)!==0}catch{return!1}});function li(e,t){if(e==="darwin"||e==="win32")return!0;if(e!=="linux")return!1;if(!t.DISPLAY&&!t.WAYLAND_DISPLAY)return!1;return Zd.some((n)=>Xd(n.binary,t))}function c0(e,t){if(e==="darwin")return{cmd:"osascript",args:["-e",a0]};if(e==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",l0]};let n=Zd.find((r)=>Xd(r.binary,t));return n?{cmd:n.binary,args:n.args}:null}function ci(e=process.platform,t=process.env){let n=c0(e,t);if(!n)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((r)=>{let o=n0(n.cmd,n.args,{env:t,stdio:["ignore","pipe","pipe"]}),i="",s=!1,a=(c)=>{if(s)return;s=!0,clearTimeout(l),r(c)},l=setTimeout(()=>{o.kill(),a({error:"The folder dialog timed out"})},s0);o.stdout.on("data",(c)=>{i+=c.toString()}),o.on("error",()=>a({error:`Could not open the folder dialog (${n.cmd})`})),o.on("close",()=>{let c=i.trim().replace(/\/+$/,"");if(!c)return a({cancelled:!0});if(!r0(c)||!Yd(c).isDirectory())return a({error:"That selection is not a folder on disk"});a({path:c})})})}var Qd=`<!doctype html>
|
|
259
283
|
<html lang="en">
|
|
260
284
|
<head>
|
|
261
285
|
<meta charset="utf-8">
|
|
@@ -5951,6 +5975,6 @@ load().then((loaded) => {
|
|
|
5951
5975
|
</script>
|
|
5952
5976
|
</body>
|
|
5953
5977
|
</html>
|
|
5954
|
-
`;var eu='<script id="ccsn-data" type="application/json">';function tu(e){return Qd.replace(eu,()=>eu+JSON.stringify({token:e}).replaceAll("<","\\u003c"))}var fr="kenryu42/cc-safety-net",
|
|
5955
|
-
`),{path:n,errors:[]}}catch(o){return{path:n,errors:[o instanceof Error?o.message:String(o)]}}}function
|
|
5956
|
-
`)}}finally{console.log=s,console.error=a}},o=ou.then(r);return ou=o.then(()=>{return},()=>{return}),o}async function
|
|
5978
|
+
`;var eu='<script id="ccsn-data" type="application/json">';function tu(e){return Qd.replace(eu,()=>eu+JSON.stringify({token:e}).replaceAll("<","\\u003c"))}var fr="kenryu42/cc-safety-net",m0=`https://github.com/${fr}`,ui=1e4,g0=7,h0="The project draft directory changed; reload the draft before applying.",y0="audit settings are user scope only; remove the audit section from a project proposal";async function mu(e,t={}){let n=E({label:"gui",booleans:{noOpen:["--no-open"]}},e),r=t.log??console.log,o=t.error??console.error;if(n.errors.length>0){for(let s of n.errors)o(s);return o("Usage: cc-safety-net gui [--no-open]"),1}let i=await v0(t);if(r(`CC Safety Net policy GUI: ${i.url}`),!n.flags.noOpen)try{await(t.openBrowser??A0)(i.url)}catch(s){o(`Failed to open browser: ${s instanceof Error?s.message:String(s)}`),o(`Open this URL manually: ${i.url}`)}if(t.keepAlive===!1)return await i.close(),0;return await D0(i),0}async function v0(e={}){let t=d0(24).toString("base64url"),n={dir:null,revision:0},r=p0((s,a)=>{b0(s,a,t,e,n)});await new Promise((s,a)=>{r.once("error",a),r.listen(0,"127.0.0.1",()=>{r.off("error",a),s()})});let i=`http://127.0.0.1:${r.address().port}`;return{origin:i,token:t,url:`${i}/?token=${encodeURIComponent(t)}`,close:()=>P0(r)}}async function b0(e,t,n,r,o){let i=new URL(e.url??"/","http://127.0.0.1");if(e.method==="GET"&&i.pathname==="/favicon.ico"){t.writeHead(204,{"cache-control":"no-store"}),t.end();return}if(!C0(e,i,n)){C(t,403,{error:"Forbidden"});return}if(e.method==="GET"&&i.pathname==="/"){R0(t,tu(n));return}if(e.method==="GET"&&i.pathname==="/api/policy"){let s=au(r),a=z(r);C(t,200,{...s,configState:Ht(a),...a.policyScopes?{projectPolicy:{path:se(r.cwd),weakenings:a.policyScopes.weakenings}}:{},destructiveCommandRules:$t,secretPatterns:iu,version:I(),preview:s.errors.length>0?null:cu(s.policy)});return}if(e.method==="POST"&&i.pathname==="/api/policy/preview"){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=lu(s.value);C(t,a.errors.length>0?400:200,a);return}if(e.method==="POST"&&i.pathname==="/api/policy/explain"){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=s.value;if(a===null||typeof a.command!=="string"){C(t,400,{errors:["command must be a string"]});return}let l=Ee(a.policy);if(l.length>0){C(t,400,{errors:l});return}C(t,200,k0(a.command,a.policy,r));return}if(e.method==="POST"&&i.pathname==="/api/policy"){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=cn(s.value,r);C(t,a.errors.length>0?400:200,a);return}if(e.method==="POST"&&i.pathname==="/api/reset"){C(t,200,cn(su,r));return}if(e.method==="POST"&&i.pathname==="/api/repair"){C(t,200,du(r));return}if(e.method==="POST"&&i.pathname==="/api/policy/project/choose-directory"){let s=await(r.chooseDirectory??ci)();if("path"in s)o.dir=s.path,o.revision+=1;C(t,200,{cancelled:"cancelled"in s,..."error"in s?{error:s.error}:{}});return}if(e.method==="GET"&&i.pathname==="/api/policy/project"){let s=gu(o,r),a=nu(s),l=lt(r);C(t,200,{dir:s,path:se(s),revision:o.revision,baseline:l.baseline,userPolicyDiagnostics:l.diagnostics,projection:a.projection,projectionDiagnostics:a.diagnostics,canPickDirectory:li(process.platform,process.env)});return}if(e.method==="POST"&&i.pathname==="/api/policy/project/diff"){let s=await ru(e,t,o,r);if(!s)return;let a=nu(s.dir),l=lt(r).baseline,c=Ge(l,Be(s.proposal).policy);C(t,200,{rows:Ft(Ge(l,a.projection).policy,c.policy,!1),weakenings:c.weakenings,existingFileDiagnostics:a.diagnostics,errors:[]});return}if(e.method==="POST"&&i.pathname==="/api/policy/project/apply"){let s=await ru(e,t,o,r);if(!s)return;let a=w0(s.dir,s.proposal);C(t,a.errors.length>0?500:200,a);return}if(e.method==="GET"&&i.pathname==="/api/activity"){let s=ct(r),a=x0(i.searchParams.get("days"),s);if(a===null){C(t,400,{error:`days must be an integer between 1 and ${s}`});return}C(t,200,Wd(a,r.activityLogsDir));return}if(e.method==="POST"&&i.pathname==="/api/rules/choose-directory"){C(t,200,await ci());return}if(e.method==="GET"&&i.pathname==="/api/rules"){let s=De(r),a=new Map(s.rules.map((l)=>[l.name,l]));C(t,200,{projectPath:r.cwd??process.cwd(),canPickDirectory:li(process.platform,process.env),rulebooks:s.rulebooks.map((l)=>({source:l.source,spec:l.spec,name:l.name,version:l.version,rules:l.rules.flatMap((c)=>{let d=a.get(c);if(!d)return[];return[{name:d.name,command:d.command,subcommand:d.subcommand,block_args:d.block_args,reason:d.reason}]})})),errors:s.errors,warnings:s.warnings});return}if(e.method==="GET"&&i.pathname==="/api/star/context"){C(t,200,await(r.fetchStarContext??(()=>$0({logsDir:r.activityLogsDir})))());return}if(e.method==="POST"&&i.pathname==="/api/star"){let s=await(r.starRepo??E0)();C(t,200,s.ok?{ok:!0}:{ok:!1,fallbackUrl:m0});return}if(e.method==="GET"&&i.pathname==="/api/integrations"){C(t,200,await(r.fetchIntegrations??_0)());return}if(e.method==="GET"&&i.pathname==="/api/health"){C(t,200,await(r.fetchHealth??T0)());return}if(e.method==="POST"&&(i.pathname==="/api/install"||i.pathname==="/api/uninstall")){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=s.value?.target;if(typeof a!=="string"||!pe.some((c)=>c.target===a)){C(t,400,{error:"unknown target"});return}let l=i.pathname==="/api/install"?"install":"uninstall";C(t,200,await(r.runIntegration??I0)(l,a));return}C(t,404,{error:"Not found"})}function gu(e,t){return e.dir??t.cwd??process.cwd()}function nu(e){let t=se(e),n=u0(t)?_e(t):{value:void 0,errors:[]},r=Be(n.value);return{projection:r.policy,diagnostics:[...n.errors,...r.diagnostics]}}async function ru(e,t,n,r){let o=gu(n,r),i=n.revision,s=await dn(e);if(!s.ok)return C(t,s.status,{errors:[s.error]}),null;let a=s.value;if(typeof a?.revision!=="number")return C(t,400,{errors:["revision must be a number"]}),null;if(a.revision!==i)return C(t,409,{errors:[h0]}),null;let l=L0(a.proposal);if(l.length>0)return C(t,400,{errors:l}),null;return{dir:o,proposal:a.proposal}}function L0(e){let t=Ee(e);if(t.length>0)return t;return e?.audit===void 0?[]:[y0]}function w0(e,t){let n=se(e),r=jt(t,Y(t));try{return B(x(Rt(e,"project policy"),n),`${JSON.stringify(r,null,2)}
|
|
5979
|
+
`),{path:n,errors:[]}}catch(o){return{path:n,errors:[o instanceof Error?o.message:String(o)]}}}function k0(e,t,n){let r=Y(t),o=z(n),i=Ot({rules:o.policy.rules,transparentWrappers:o.policy.transparentWrappers,safety:pu(r.safety),worktreeMode:r.workflow.worktree_mode,destructiveCommandProtectionEnabled:r.destructive_command_protection.enabled,destructiveCommandRuleOverrides:r.destructive_command_protection.overrides,destructiveCommandAllowPaths:r.destructive_command_protection.allow_paths,secretProtection:{enabled:r.secret_protection.enabled,disabledRules:uu(r.secret_protection.overrides),denyPaths:r.secret_protection.deny_paths,allowPaths:r.secret_protection.allow_paths}});return at(e,{policySnapshot:i,cwd:n.cwd,userConfigDir:n.userConfigDir})}function x0(e,t){if(e===null)return Math.min(g0,t);let n=Number(e);if(!Number.isInteger(n)||n<1||n>t)return null;return n}function C0(e,t,n){if(t.searchParams.get("token")!==n)return!1;if(e.method!=="POST")return!0;return e.headers["x-cc-safety-net-token"]===n}var S0=1048576;async function dn(e){let t=[],n=0;for await(let r of e){let o=r;if(n+=o.byteLength,n>S0)return{ok:!1,status:413,error:"Request body is too large"};t.push(o)}try{return{ok:!0,value:JSON.parse(Buffer.concat(t).toString("utf-8")||"{}")}}catch(r){return{ok:!1,status:400,error:`Invalid JSON: ${r instanceof Error?r.message:String(r)}`}}}function R0(e,t){e.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),e.end(t)}function C(e,t,n){e.writeHead(t,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),e.end(JSON.stringify(n))}function P0(e){return new Promise((t,n)=>{e.close((r)=>r?n(r):t())})}function D0(e){return new Promise((t)=>{let n=()=>{process.off("SIGINT",r),process.off("SIGTERM",r)},r=()=>{n(),e.close().then(t)};process.once("SIGINT",r),process.once("SIGTERM",r)})}function A0(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",n=process.platform==="win32"?["/c","start","",e]:[e];return new Promise((r,o)=>{let i=fu(t,n,{detached:!0,stdio:"ignore"}),s=(l)=>{i.off("spawn",a),o(l)},a=()=>{i.off("error",s),i.unref(),r()};i.once("error",s),i.once("spawn",a)})}async function E0(e="gh",t=ui){return{ok:await di(e,["api","-X","PUT",`/user/starred/${fr}`],t)===0}}async function _0(e={}){let t=await qt(e.fetcher),n=hu(t,e.homeDir);return{targets:X.map((r)=>{let o=n.find((i)=>i.platform===r.id);return{target:r.id,label:D(r.id),version:t.versions[r.id]??null,status:o?.configured?"active":o?.detected?"disabled":o?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:t.version,nodeVersion:t.nodeVersion,platform:t.platform}}}function hu(e,t){return vt(process.cwd(),{homeDir:t,ampPluginListOutput:e.ampPluginListOutput,codexPluginListOutput:e.codexPluginListOutput,copilotCliVersion:e.versions["copilot-cli"]})}async function T0(e={}){let[t,n]=await Promise.all([qt(e.fetcher),(e.checkUpdates??Te)()]);return{hooks:hu(t,e.homeDir).filter((r)=>r.detected).map((r)=>({platform:r.platform,label:D(r.platform),configured:r.configured})),update:{currentVersion:n.currentVersion,latestVersion:n.latestVersion??null,updateAvailable:n.updateAvailable}}}var ou=Promise.resolve();function I0(e,t,n={}){let r=async()=>{let i=[],s=console.log,a=console.error;console.log=(...l)=>i.push(l.map(String).join(" ")),console.error=console.log;try{return{ok:await ln(e,[],{selectTargets:async()=>[t],output:new f0({write(c,d,m){i.push(String(c).replace(/\n$/,"")),m()}}),...n})===0,output:i.join(`
|
|
5980
|
+
`)}}finally{console.log=s,console.error=a}},o=ou.then(r);return ou=o.then(()=>{return},()=>{return}),o}async function $0(e={}){let[t,n,r]=await Promise.all([O0(e.command),F0(e.fetchRepo),Promise.resolve(Rn(ct(),e.logsDir).totalBlocked)]);return{starred:t,starCount:n,blockedTotal:r}}async function O0(e="gh",t=ui){if(await di(e,["auth","status"],t)!==0)return null;let n=await di(e,["api",`/user/starred/${fr}`],t);if(n===0)return!0;if(n===null)return null;return!1}function di(e,t,n){return new Promise((r)=>{let o=fu(e,t,{stdio:"ignore",windowsHide:!0}),i=!1,s,a=(l)=>{if(i)return;if(i=!0,s)clearTimeout(s);r(l)};o.once("error",()=>a(null)),o.once("close",a),s=setTimeout(()=>{o.kill(),a(null)},n)})}async function F0(e=fetch){try{let t=await e(`https://api.github.com/repos/${fr}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(ui)});if(!t.ok)return null;let n=await t.json();return typeof n.stargazers_count==="number"?n.stargazers_count:null}catch{return null}}function j0(e){if(e[0]!=="help")return!1;let t=e[1];if(!t)Bo(),process.exit(0);if(rn(t))process.exit(0);console.error(`Unknown command: ${t}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var N0={hook:async(e)=>{let t=Qs(e);if(t){await t.run();return}console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),rn("hook",console.error),process.exit(1)},install:async(e)=>{process.exit(await ln("install",e))},update:async(e)=>{process.exit(await ri(e))},uninstall:async(e)=>{process.exit(await ln("uninstall",e))},rule:async(e)=>{process.exit(await zd(e))},policy:async(e)=>{process.exit(await Dd(e))},status:async(e)=>{if(fe(E({label:"status"},e).errors))process.exit(1);Jd()},statusline:async(e)=>{let t=E({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},e);if(t.errors.length===0&&t.flags.claudeCode){await si();return}if(fe(t.errors),!t.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");rn("statusline",console.error),process.exit(1)},doctor:async(e)=>{let t=No(e);if(!t)process.exit(1);let n=await yc({json:t.json,skipUpdateCheck:t.skipUpdateCheck});process.exit(n)},logs:async(e)=>{process.exit(await Ls(e))},gui:async(e)=>{process.exit(await mu(e))},explain:async(e)=>{process.exit(await Cc(e))}};async function H0(){let e=process.argv.slice(2),t=E({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},e);if(j0(e))return;let n=e[0],r=n?Sn(n):void 0;if(t.help&&r&&r.name!=="rule")rn(r.name),process.exit(0);if(!n||t.help&&!r)Bo(),process.exit(0);if(t.flags.version)Pc(),process.exit(0);if(r){await N0[r.name](e.slice(1));return}let o=ea(n);if(o){await o.run();return}if(n==="--statusline"){await si();return}console.error(n.startsWith("-")?`Unknown option: ${n}`:`Unknown command: ${n}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}H0().catch((e)=>{console.error("CC Safety Net error:",e),process.exit(1)});
|