cc-safety-net 2.2.2 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,43 +1,44 @@
1
1
  #!/usr/bin/env node
2
- import{b as Uo,c as Go,d as G,e as Bo,f as Xn,g as tt,h as Ae,i as gr,j as pe,k as Fi,l as xr,m as Jt,n as Hi,o as Mi,p as Yt}from"../chunks/index-j6a67cs3.js";import{$ as V,$a as ad,A as De,Aa as br,B as Je,Ba as wr,C as Gc,Ca as ki,D as ii,Da as xi,E as si,Ea as Jo,F as ai,Fa as Qe,G as yt,Ga as or,H as tr,Ha as ir,I as ur,Ia as di,J as li,Ja as Ke,Ka as nd,L as ci,La as Zo,M as Q,Ma as Xo,Na as kr,O as ee,Oa as Qo,P as Ze,Pa as ei,Q as Xe,Qa as Z,R as Lt,Ra as sr,S as _c,Sa as fr,T as te,Ta as mr,U as Y,Ua as X,V as pr,Va as rd,W as nr,Wa as kt,X as Wt,Xa as od,Y as rr,Ya as No,Za as id,_ as me,_a as sd,aa as Zi,ab as Tn,bb as ld,ca as Ee,cb as cd,da as Zt,db as Ci,ea as St,eb as Si,fa as vt,fb as Di,ga as Pe,gb as Ri,ha as hr,hb as Fc,ia as fe,ib as ui,ja as ji,jb as pi,ka as Cr,kb as ar,la as Bi,lb as fi,ma as qi,mb as mi,na as yr,nb as ve,oa as Li,ob as Re,pa as Ko,pb as de,qa as vi,qb as gi,ra as bi,rb as B,s as Ct,sa as wi,sb as xt,t as yi,ta as Lr,tb as bt,u as H,ua as Wo,ub as Gi,v as k,va as S,w as gt,wa as vr,x as w,xa as Ui,y as Se,ya as ue,z as oi,za as wt}from"../chunks/index-z08yh4sm.js";var gd=["-h","--help"];function _(e,t){let n=Object.entries(e.booleans??{}),r=Object.entries(e.values??{}),o=Object.fromEntries(n.map(([d])=>[d,!1])),i={},s=[],a=[],l=!1,c=-1;for(let[d,p]of t.entries()){if(d<=c)continue;if(p==="--"){s.push(...t.slice(d+1));break}if(gd.includes(p)){l=!0;continue}let g=n.find(([,m])=>m.includes(p));if(g){o[g[0]]=!0;continue}let u=r.find(([,m])=>m.includes(p));if(u){let m=t[d+1];if(m===void 0||m.startsWith("-")){a.push(`${p} requires a value`);continue}i[u[0]]=m,c=d+1;continue}if(p.startsWith("-")){a.push(`Unknown option for ${e.label}: ${p}`);continue}if(e.positionals==="tail"){s.push(...t.slice(d));break}s.push(p)}if(e.positionals!=="list"&&e.positionals!=="tail")a.push(...s.map((d)=>`Unexpected argument for ${e.label}: ${d}`));return{flags:o,values:i,positionals:s,help:l,errors:a}}function le(e){for(let t of e)console.error(t);return e.length>0}import{readdirSync as tu,statSync as Ei,unlinkSync as nu}from"node:fs";import{basename as Pi,dirname as ru,join as ou,resolve as iu}from"node:path";function O(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 Wn=(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"},qe=(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 hd,readdirSync as yd,readFileSync as Ld}from"node:fs";import{join as vd}from"node:path";function Le(e,t){try{return yd(e,{withFileTypes:!0,encoding:"utf8"}).flatMap((n)=>{let r=vd(e,n.name);if(n.isDirectory())return Le(r,t);if(n.name.endsWith(".jsonl"))return[r];return[]})}catch{if(t&&hd(e))t.count++;return[]}}function Jn(e){let t=(o)=>`${o.sessionId}
3
- ${qe(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 bd=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function wd(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 bd.every((n)=>t[n]===void 0||typeof t[n]==="string")}function Ce(e,t){try{return Ld(e,"utf-8").split(`
4
- `).filter(Boolean).flatMap((n)=>{try{let r=JSON.parse(n);if(!wd(r)){if(t)t.count++;return[]}return[r]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as Kd}from"node:path";var kd=["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 qo(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 Vo(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(Zn(xd(a,r,s)))}catch{o++}},finish(a){if(i)return i;try{i=Zn({events:Object.freeze(t),droppedEvents:o,terminal:Cd(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 xd(e,t,n){if(e.kind!=="step")throw TypeError("invalid trace event");let{scope:r,step:o}=e;zt(o,n,t);let i=Ve(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 Cd(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:Ve(e.reason,t,n),segment:Ve(e.segment,t,n),...o?{ruleId:Ve(o,t,n)}:{}})}function zt(e,t,n,r=0,o=new WeakSet){if(typeof e==="string"){let a=e.slice(0,n.maxTextLength);if(!Xn(a))return;for(let l of Bo(a))for(let c of l.match(/[^\s"'()$]+/g)??[])t.add(zo(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++)zt(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++,zt(a,t,n);let l=Yn(a,n,t);if(s.has(l))continue;s.add(l),zt(e[a],t,n,r+1,o)}}function Ve(e,t,n,r=0,o=new WeakSet){if(typeof e==="string")return Yn(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(Ve(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=Yn(a,t,n);if(Object.hasOwn(i,l))continue;Object.defineProperty(i,l,{value:Ve(e[a],t,n,r+1,o),enumerable:!0,configurable:!0,writable:!0})}return i}function Yn(e,t,n){let r=e.slice(0,t.maxTextLength),o=Xn(r)?Go(r):r,i=n.size>0?Dd(o,n):o;return(Sd(i)?Uo(i):i).slice(0,t.maxTextLength)}function Sd(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&&kd.some((t)=>e.includes(t))||e.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(e)}function Dd(e,t){return e.replace(/[^\s"'()$]+/g,(n)=>t.has(zo(n))?"<redacted>":n)}function zo(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 Zn(e){if(e&&typeof e==="object"&&!Object.isFrozen(e)){for(let t of Object.values(e))Zn(t);Object.freeze(e)}return e}function Yo(e,t,n){let r=n??Ko(),o=r.getCommandProgram(e,t.shell??"auto"),i=Vo(),s=qo(i),a=o.dialect==="powershell"?r.getCommandProgram(e,"posix"):o,l=Wo(a);s.recordGlobal({type:"parse",input:e,segments:l.map((p)=>[...p])});let c=Jo(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((p)=>p.kind==="command")?.segment??e,...c.ruleId?{ruleId:c.ruleId}:{}}:{result:"allowed"}),program:o})}import{resolve as Rd}from"node:path";function Qn(e){let t=Zo().safeParse(e);return{errors:t.success?[]:Qo(t.error.issues),ruleNames:new Set(Xo(e).map((n)=>n.toLowerCase()))}}function er(e){let t=ti(e);if(!t.ok)return t.result;return Qn(t.parsed)}function ti(e){let t=[],n=new Set;try{let r=typeof e==="string"?gt(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 ni(e){return Rd(e??process.cwd(),".safety-net.json")}function ce(e){let t=ti(e);if(!t.ok)return t.result;let n=ei(t.parsed);return{errors:n.errors,ruleNames:n.sources}}import{isAbsolute as Ad,join as ht,relative as Ed,resolve as ri,sep as Pd}from"node:path";async function Ye(e={}){let t=cr(e);return Td(t,await Kt(t,Ke()))}function Td(e,t){if(!t.ok)return t;let n=Y(e),r=[...new Set(de(n.configPath,n.lockPath,e,n.filesystemScope))];if(r.length===0)return t;return{ok:!1,errors:r,warnings:t.warnings,entries:t.entries}}async function Kt(e,t,n,r={}){let o=null,i=!1;try{let s=Y(e),a=sr(s.configTarget);if(!a.ok)return a.result;let l=a.config;if(e.check)return Fd(l,s,e);o={target:s.lockTarget,content:w(s.lockTarget)};let c=ar(s.lockTarget);if(c.errors.some((L)=>L.startsWith("Unable to access ")))return{ok:!1,errors:c.errors,warnings:[],entries:[]};if(e.only&&c.errors.length>0)return{ok:!1,errors:c.errors,warnings:[],entries:[]};let d=c.errors.length>0?null:c.lock,p=e.only?ui(l,d,e.only):{ok:!0,specs:l.rules};if(!p.ok)return p.result;if(e.only&&!d&&p.specs.length<l.rules.length)return{ok:!1,errors:[`No lockfile available for partial update; run ${ci}`],warnings:[],entries:[]};let g=(await _d(p.specs,(L)=>fi(L,s.configDir,e,d,s.filesystemScope,t),t)).map((L)=>Hd(L,d,n));for(let L of g)Ud(L.content,L.entry,s.configDir,e,s.filesystemScope);let u=e.only?Md(l,d,g):g.map((L)=>L.entry);i=!0,X(s.lockTarget,{version:1,rulebooks:u},void 0,r._testAfterPolicyRename);let m=new Map(g.map((L)=>[L.entry.spec,L.rulebook.rules.length])),f=Gd(u,s.configDir,e,s.filesystemScope,r);return{ok:!0,errors:[],warnings:f,entries:u.map((L)=>jd(L,m))}}catch(s){if(i&&o)try{ze(o.target,o.content)}catch(a){return We(a)}return We(s)}}async function lr(e,t={}){return Id(e,cr(t),Ke())}async function Id(e,t,n,r={}){let o=null,i=!1;try{let s=Y(t),a=w(s.configTarget);o={target:s.configTarget,content:a};let l=sr(s.configTarget);if(!l.ok)return l.result;let c=l.config,d=li(e)?await mi(e,n):[{spec:e}],p=d.map((m)=>m.spec),g=[...new Set([...c.rules,...p])];if(g.length>or)return Od();if(g.length!==c.rules.length)i=!0,X(s.configTarget,{version:1,rules:g,overrides:c.overrides??{},transparent_wrappers:c.transparent_wrappers??[]},void 0,r._testAfterPolicyRename);let u=await Kt(t,n,new Map(d.filter((m)=>!!m.display_ref).map((m)=>[m.spec,m.display_ref])),r);if(!u.ok)ze(s.configTarget,a);return u}catch(s){if(i&&o)try{ze(o.target,o.content)}catch(a){return We(a)}return We(s)}}async function _d(e,t,n=Ke()){if(e.length>or)throw Error(ir);let r=Array(e.length),o=0,i,s=Array.from({length:Math.min(e.length,di.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 Od(){return{ok:!1,errors:[ir],warnings:[],entries:[]}}function cr(e){return{cwd:e.cwd,cacheConfigDir:e.cacheConfigDir,userConfigDir:e.userConfigDir,userConfigPath:e.userConfigPath,projectConfigPath:e.projectConfigPath,global:e.global,check:e.check,only:e.only,refresh:e.refresh}}function $d(e){return{...cr(e),deleteSource:e.deleteSource}}async function dr(e,t={}){try{return await Nd(e,$d(t),{})}catch(n){return We(n)}}async function Nd(e,t,n){let r=Y(t),o=Z(r.configTarget);if(o.errors.length>0)return{ok:!1,errors:o.errors,warnings:[],entries:[]};if(!o.config)return{ok:!1,errors:[`No config found at ${r.configPath}`],warnings:[],entries:[]};let i=ar(r.lockTarget);if(i.errors.length>0)return{ok:!1,errors:i.errors,warnings:[],entries:[]};let s=pi(o.config.rules,i.lock,e);if(!s.ok)return s.result;let a=t.deleteSource?Bd(r.configDir,s.specs,i.lock,r.filesystemScope):{ok:!0,dirs:[]};if(!a.ok)return a.result;let l=w(r.configTarget);if(l===null)return We(Error("Rules config is unavailable."));try{X(r.configTarget,{version:1,rules:o.config.rules.filter((p)=>!s.specs.includes(p)),overrides:o.config.overrides??{},transparent_wrappers:o.config.transparent_wrappers??[]},void 0,n._testAfterPolicyRename)}catch(p){throw ze(r.configTarget,l),p}let c=await Kt(t,Ke(),void 0,n);if(!c.ok)return ze(r.configTarget,l),c;let d=qd(r.configDir,a.dirs,n,r.filesystemScope);if(!d.ok){ze(r.configTarget,l);let p=await Kt(t,Ke(),void 0,n);if(!p.ok)return{ok:!1,errors:[...d.result.errors,...p.errors],warnings:p.warnings,entries:p.entries};return d.result}return c}async function Fd(e,t,n){let r=gi(e,t.lockPath,t.configDir,n,n.global?"user":"project",t.filesystemScope);return{ok:r.errors.length===0&&r.warnings.length===0,errors:[...r.errors,...r.warnings],warnings:[],entries:r.entries}}function Hd(e,t,n){let r=t?.rulebooks.find((i)=>i.spec===e.entry.spec&&i.kind==="github"),o=n?.get(e.entry.spec)??(r?.kind==="github"?r.display_ref:void 0);if(!o||e.entry.kind!=="github")return e;return{...e,entry:{...e.entry,display_ref:o}}}function Md(e,t,n){let r=new Set(e.rules),o=new Set(t?.rulebooks.map((s)=>s.spec)??[]),i=new Map(n.map((s)=>[s.entry.spec,s.entry]));return[...(t?.rulebooks.filter((s)=>r.has(s.spec))??[]).map((s)=>i.get(s.spec)??s),...n.filter((s)=>!o.has(s.entry.spec)).map((s)=>s.entry)]}function jd(e,t){return{...e,ruleCount:t.get(e.spec)}}function Ud(e,t,n,r,o){let i=nr(t,rr(n,r));Se(k(o,i),e)}function Gd(e,t,n,r,o){let i=rr(t,n),s=Wt(i),a=k(r,s),l=De(a);if(!l)return[];let c=e.map((p)=>k(r,nr(p,i))),d=l.filter((p)=>p.kind==="directory").map((p)=>({directory:k(r,ht(s,p.name)),identity:k(r,ht(s,p.name,tr))})).filter((p)=>!c.some((g)=>oi(p.identity,g))).map((p)=>p.directory);for(let p of d)ai(p);return d.flatMap((p)=>{try{return Vd(p,o),[]}catch{return["Unable to prune rules policy cache safely."]}})}function Bd(e,t,n,r){let o=new Map(n?.rulebooks.map((c)=>[c.spec,c])??[]),i=t.flatMap((c)=>{let d=o.get(c);if(!d)return yt.test(c)?[]:["--delete-source can only delete local rulebook sources"];return d.kind==="local-directory"?[]:["--delete-source can only delete local rulebook sources"]}),s=t.map((c)=>{let d=o.get(c);return ht(e,d?.kind==="local-directory"?d.path:c)}),a=i.length>0?[]:s.flatMap((c)=>hi(e,c,r)),l=[...i,...a];return l.length>0?{ok:!1,result:{ok:!1,errors:l,warnings:[],entries:[]}}:{ok:!0,dirs:s}}function hi(e,t,n){let r=ri(e),o=ri(t),i=Ed(r,o);if(i===""||i===".."||i.startsWith(`..${Pd}`)||Ad(i))return[`Refusing to delete local rulebook source outside ${e}: ${t}`];let s=k(n,o),a=De(s);if(!a)return[`Local rulebook source directory not found: ${t}`];let l=a.find((c)=>c.name==="rulebook.json");if(!l)return[`Local rulebook source directory is missing rulebook.json: ${t}`];if(l.kind!=="file")throw new H(n.label);if(w(k(n,ht(o,"rulebook.json"))),a.length>1)return[`Local rulebook source directory contains extra files: ${t}. delete manually if you really want to remove the directory.`];return[]}function qd(e,t,n,r){let o=t.flatMap((i)=>{try{if(!De(k(r,i)))return[];let s=hi(e,i,r);if(s.length>0)return s;return zd(i,n,r),[]}catch(s){return[`Failed to delete local rulebook source ${i}: ${s instanceof Error?s.message:String(s)}`]}});return o.length>0?{ok:!1,result:{ok:!1,errors:o,warnings:[],entries:[]}}:{ok:!0}}function Vd(e,t){if(t._testPruneRulebookCacheDir){t._testPruneRulebookCacheDir(e.path);return}ii(e)}function zd(e,t,n){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(e);return}Je(k(n,ht(e,tr))),si(k(n,e))}function ze(e,t){if(t===null){Je(e);return}Se(e,t)}function We(e){return{ok:!1,errors:[e instanceof Error?e.message:String(e)],warnings:[],entries:[]}}function et(e,t){let n=Jd(t),r=ki(n),o={effectiveLevel:r.effectiveLevel,selectedPreset:n.policySnapshot.policy.safety.level??"standard",effectiveCapabilities:r.effectiveCapabilities,destructiveCommandRuleOverrides:n.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:i,configValid:s}=Wd({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=Yd(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:G(a.reason),segment:G(a.target),...a.ruleId?{ruleId:G(a.ruleId)}:{},configSource:i,configValid:s,...o};let l=Yo(e,n),c=l.decision,d=c?.ruleId??Zd(e,n),p=vt.find((u)=>u.id===d&&u.activationCapability),g=p?r.policy.effectiveDestructiveCommandRules[p.id]:void 0;return{trace:Qd(l.trace),result:c?"blocked":"allowed",reason:c?G(c.reason):void 0,segment:c?G(c.evidence.find((u)=>u.kind==="command")?.segment??e):void 0,ruleId:c?.ruleId?G(c.ruleId):void 0,customRule:Xd(eu(c?.ruleId,n.policySnapshot)),configSource:i,configValid:s,...o,...p&&g?{ruleActivation:{id:p.id,...g}}:{}}}function Wd(e){let t=Q(e?.cwd),n=e?.userConfigPath??ee(e),r=te({cwd:e?.cwd,userConfigDir:e?.userConfigDir,userConfigPath:e?.userConfigPath});try{if(w(r.projectConfigTarget)!==null){if(ce(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=ce(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 Jd(e){let t=Kd(e?.cwd??process.cwd()),n=e?.policySnapshot??B({cwd:t,userConfigDir:e?.userConfigDir}),r=ue(n.policy);return{cwd:t,effectiveCwd:t,policySnapshot:n,environment:yi(),protectedGitMetadata:wi([t]),effectiveCapabilities:r.capabilities,strict:e?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function Yd(e,t){let n=t.cwd??process.cwd(),r=Li(Qe("",{command:e},{kind:"command",shell:"posix"},{executionCwd:n,configCwd:n},e)),o=Si(r);if(o)return{reason:Ci,target:o.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let i=bi(r,t.protectedGitMetadata);if(i)return{reason:vi,target:i.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let s=t.policySnapshot.policy,a=s.secretProtection.enabled===!1?null:Ri(r,s.secretProtection,{strict:t.strict});if(a)return{reason:Di,target:a.target,ruleId:a.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function Zd(e,t){let n=t.policySnapshot.policy,r=bt({...n,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...n.destructiveCommandRuleOverrides,...Object.fromEntries(vt.flatMap((o)=>o.activationCapability?[[o.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return xi(e,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function Xd(e){if(!e)return;return{id:G(e.id),...e.rulebook?{rulebook:{name:G(e.rulebook.name),version:G(e.rulebook.version)}}:{},...e.source?{source:G(e.source)}:{},...e.override?{override:{type:"reason",reason:G(e.override.reason)}}:{}}}function Qd(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 eu(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})}function su(e){let t=tt(),n=_({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(le(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:Ai(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):Ai(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:iu(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 Ti(e,t={}){let n=su(e);if(!n)return 1;let r=t.logsDir??pe();if(n.pruneLegacy)return au(r,n.json,n.dryRun);if(!r)return console.log(n.json?"[]":n.id?`No retained audit log entry found for id ${O(n.id)}.`:"No audit log entries found."),0;Ae(r);let o={count:0},i=Le(r,o).flatMap((d)=>Ce(d,o).map((p)=>({entry:p,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 uu(i,n,t.timeZone);let s=Date.now()-n.since*24*60*60*1000,a=i.filter((d)=>pu(d,n,r,s)),l=n.suspect?Jn(a.map((d)=>d.entry)):null,c=(l?a.filter((d)=>l.has(d.entry)):a).sort((d,p)=>Date.parse(p.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(gu(d.entry,t.timeZone));return 0}function au(e,t,n){let r=e?cu(e).map((a)=>ou(e,a)):[];if(n)return lu(r,t);let o=[],i=0,s=0;for(let a of r){let l=Ei(a,{throwIfNoEntry:!1})?.size??0,c=du(a);if(c){o.push(`${Pi(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"} (${Ii(s)}).`);for(let a of o)console.error(`Could not remove ${O(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 lu(e,t){let n=e.reduce((r,o)=>r+(Ei(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"} (${Ii(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 cu(e){try{return tu(e,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function du(e){try{return nu(e),null}catch(t){return t instanceof Error?t.message:String(t)}}function Ii(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 uu(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 ${O(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 ${O(t.id??"")}.`),0;return console.log(hu(o.entry,n)),0}function pu(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&&!fu(e,n,t.session))return!1;if(t.project!==void 0&&!mu(e.entry.cwd,t.project))return!1;return!0}function fu(e,t,n){if(e.entry.sessionId===n)return!0;return ru(e.file)===t&&Pi(e.file,".jsonl")===n}function mu(e,t){if(!e)return!1;return e===t||e.startsWith(`${t}/`)}function gu(e,t){let n=O(e.id??"-"),r=O(e.decision??"deny"),o=e.cwd?` [${O(e.cwd)}]`:"",i=e.segment||e.command,s=i===e.command?"":"↳ ",a=i.length>50?`${i.slice(0,50)}…`:i;return`${n.padEnd(16)} ${O(_i(e.ts,t))} ${r.padEnd(5)} ${O(e.agent??"-").padEnd(15)} ${O(e.ruleId??"-").padEnd(20)} ${s}${O(a)}${o}`}function hu(e,t){let n=(o)=>O(o===void 0||o===null||o===""?"-":o),r=e.shape?`${e.agent??"-"} (shape: ${e.shape})`:e.agent??"-";return[`id: ${n(e.id)}`,`ts: ${n(_i(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(`
5
- `)}function _i(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 Ai(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:null}var Oi={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 $i={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 Ni={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 Vi,join as Ru,relative as Au}from"node:path";var yu=8388608;function Lu(e,t){console.log(JSON.stringify(e(Hi(t))))}async function vu(e){let t;try{t=(await Sr(process.stdin)).trim()}catch{e({reason:"Failed to parse hook input JSON."});return}if(!t){e({reason:"Missing hook input JSON."});return}return Dr(t,e,"Failed to parse hook input JSON.")}async function Sr(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>yu)throw bu(e),Error("hook input byte limit exceeded");t.push(o)}return Buffer.concat(t,n).toString("utf-8")}function bu(e){let t=e.destroy??e.cancel;if(!t)return;try{Promise.resolve(t.call(e)).catch(()=>{})}catch{}}function Dr(e,t,n){try{return JSON.parse(e)}catch{t({reason:n});return}}function N(e,t){let n=t.get(e);return n?{kind:"command",shell:n}:{kind:ji(e)}}function ne(e,t,n,r){let o=e===void 0?process.cwd():e,i=typeof o==="string"&&o.trim()!==""?V([o]):void 0;if(i)return{configCwd:i,executionCwd:i};return P(r,t,n,Cu(o)),null}function P(e,t,n,r){let o;try{o=Cr(t)}catch(i){if(!(i instanceof fe))throw i}e(Jt({command:o,segment:r,toolName:n}))}async function wu(e){let t=await vu(e.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){P(e.outputDeny);return}if(!e.isSupported(t))return;let n=e.getAgent?.(t)??e.agent,r=e.agent===n?void 0:e.agent,o=Du(t),i=(u,m)=>{Fi(u,()=>e.getSessionId(t),{agent:n,shape:r,toolName:m,cwd:o}),e.outputDeny(u)},s=e.getToolName(t);if(typeof s!=="string"||s.trim()===""){P((u)=>i(u),Su(t));return}let a=s,l=(u)=>i(u,a),c;try{c=e.getToolInput(t,a,l)}catch(u){if(!(u instanceof fe))throw u;P(l,void 0,a);return}if(!c.ok)return;let d=e.getContext(t,c.input,a,l);if(!d)return;let p;try{p=Cr(c.input)}catch(u){if(!(u instanceof fe))throw u;P(l,void 0,a);return}let g=Qe(a,c.input,c.route,d,p??null);try{let u=Yt(g,{guard:{auditAllowed:Ui(),dependencies:e.guardDependencies},audit:{agent:n,shape:r,getSessionId:()=>e.getSessionId(t)}}),m=xr(u,{includeEvidence:!0,toolName:u.stage==="command-analysis"?void 0:a});if(m){e.outputDeny(m);return}e.outputAllow?.()}catch(u){if(!(u instanceof Gi))throw u;ku(u);let m=xr(u.evaluation,{includeEvidence:!0,toolName:u.evaluation.stage==="command-analysis"?void 0:a});if(m)e.outputDeny(m);return}}function ku(e){if(!wt(S.debug))return;console.error(`CC Safety Net debug: ${xu(e.stage)}: ${Mi(e.cause)}`)}function xu(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 Cu(e){return typeof e==="string"?e:void 0}function Su(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 Du(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 F(e){let t=(o)=>Lu(e.createDenyOutput,o),n=e.createAllowOutput;await wu({...e,outputDeny:t,outputAllow:n?()=>console.log(JSON.stringify(n())):void 0})}function Dt(e){return Ru(e,".gemini","config","hooks.json")}var Eu=new Map([["run_command","auto"]]),Pu=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function zi(e){return N(e,Eu)}async function Ki(){await F({agent:"antigravity-cli",createDenyOutput:(e)=>({decision:"deny",reason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolCall?.name,getToolInput:(e,t)=>({ok:!0,input:$u(e.toolCall?.args,t),route:zi(t)}),getContext:Tu,getSessionId:(e)=>e.conversationId})}function Tu(e,t,n,r){let i=Ou(e).flatMap((c)=>{let d=V([c]);return d?[d]:[]});if(!i[0])return Te(r,t,n),null;if(n!=="run_command"){let c;try{c=Iu(t,n,i)}catch(d){if(d instanceof fe)return Te(r,void 0,n),null;if(!(d instanceof Ee))throw d;return Te(r,t,n),null}if(!c)return Te(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 Te(r,t,n),null;let l=me(a,i);if(l){let c=Wi(l,i);if(!c)return Te(r,t,n,a),null;return{configCwd:c,executionCwd:l}}return Te(r,t,n,a),null}function Iu(e,t,n){let r=zi(t),o=[...Bi(e,Pu),...r.kind==="patch"?qi(e):[]].filter(Vi),i=Zt(),s=new Set(o.flatMap((a)=>{let l=Wi(St(a,Ct,i),n);return l?[l]:[]}));if(s.size>1)return null;return[...s][0]??n[0]??null}function Wi(e,t){return t.filter((n)=>_u(e,n)).reduce((n,r)=>r.length>n.length?r:n,"")||null}function _u(e,t){let n=Au(t,e);return n===""||!n.startsWith("..")&&!Vi(n)}function Te(e,t,n,r){let o=t&&typeof t==="object"?t.command:void 0;e(Jt({command:typeof o==="string"?o:void 0,segment:r,toolName:n}))}function Ou(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 V(t)?t:[]}function $u(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 Rt=[{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,install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:5,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:4,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:6,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:7,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:8,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:3,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"]}}],Xt=Rt.slice().sort((e,t)=>e.doctorOrder-t.doctorOrder).map((e)=>e.id),Ji=Rt.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})),z=Rt.slice().sort((e,t)=>e.install.order-t.install.order).map((e)=>({id:e.id,...e.install})).map(({order:e,...t})=>t),Oh=Object.fromEntries(Rt.map((e)=>[e.id,e.displayName]));function R(e){return Rt.find((t)=>t.id===e)?.displayName??e}import{homedir as Nu}from"node:os";import{isAbsolute as Yi,join as Rr}from"node:path";function Xi(e){if(e!==void 0&&e!==null&&typeof e!=="string")return"unknown";if(typeof e==="string"&&!Yi(e))return"unknown";try{let t=Zt(),n=typeof e==="string"&&e?St(e,Ct,t):void 0,r=process.env.HOME||Nu(),o=[["codex",process.env.CODEX_HOME||Rr(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||Rr(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||Rr(r,".claude")]],i=n?o.flatMap(([s,a])=>{if(!Yi(a))return[];return Zi(n,St(a,Ct,t))?[s]:[]}):[];if(i.length===1)return i[0]??"unknown";if(i.length>1)return"unknown"}catch(t){if(t instanceof Ee)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var Ar="PreToolUse",Qi="BeforeTool",es="pre_tool_call",Er="PreToolUse";var Fu=new Map([["Bash","posix"],["PowerShell","powershell"]]);function Hu(e){return N(e,Fu)}async function ts(){await F({agent:"claude-code",getAgent:(e)=>Xi(e.transcript_path),createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Ar,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Ar,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:Hu(t)}),getContext:(e,t,n,r)=>ne(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var Mu=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function ju(e){return N(e,Mu)}async function ns(){await F({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=Dr(e.toolArgs,n,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:ju(t)}},getContext:(e,t,n,r)=>ne(e.cwd,t,n,r),getSessionId:(e)=>typeof e.sessionId==="string"&&e.sessionId.trim()?e.sessionId:void 0})}var Uu=new Map([["Shell","auto"]]);function Gu(e){return N(e,Uu)}async function rs(){await F({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:Gu(t)}),getContext:Bu,getSessionId:(e)=>e.conversation_id})}function Bu(e,t,n,r){let o=qu(e);if(!o[0])return P(r,t,n),null;let i=me(zu(e.cwd),o);if(!i)return P(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 P(r,t,n),null;let a=me(s,o);if(!a)return P(r,t,n,s),null;return{configCwd:i,executionCwd:a}}function qu(e){return Vu(e).flatMap((t)=>{let n=V([t]);return n?[n]:[]})}function Vu(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 zu(e){return typeof e==="string"&&e.trim()!==""?e:"."}var Ku=new Map([["run_shell_command","auto"]]);function Wu(e){return N(e,Ku)}async function os(){await F({agent:"gemini-cli",createDenyOutput:(e)=>({decision:"deny",reason:e,systemMessage:e}),isSupported:(e)=>e.hook_event_name===Qi,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:Wu(t)}),getContext:(e,t,n,r)=>ne(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var Ju=new Map([["run_terminal_command","auto"]]);function Yu(e){return N(e,Ju)}async function is(){await F({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 P(n,e.toolInput,t),{ok:!1};return{ok:!0,input:e.toolInput,route:Yu(t)}},getContext:Zu,getSessionId:(e)=>e.sessionId})}function Zu(e,t,n,r){let o=V(Xu(e));if(!o)return P(r,t,n),null;let i=me(Qu(e.cwd),[o]);if(!i)return P(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;return{configCwd:i,executionCwd:i}}function Xu(e){let t=e.workspaceRoot===void 0?e.cwd:e.workspaceRoot;return typeof t==="string"&&t.trim()!==""?[t]:[]}function Qu(e){return typeof e==="string"&&e.trim()!==""?e:"."}import{resolve as ep}from"node:path";var tp=new Map([["terminal","posix"]]);async function ss(){await F({agent:"hermes-agent",createDenyOutput:(e)=>({action:"block",message:e}),isSupported:(e)=>e.hook_event_name===es,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:N(t,tp)}),getContext:np,getSessionId:(e)=>e.session_id})}function np(e,t,n,r){let o=ne(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 P(r,t,n),null;let s=V([ep(o.configCwd,i)]);if(!s)return P(r,t,n,i),null;return{...o,executionCwd:s}}var as=new Map([["Bash","posix"]]);function rp(e){return N(e,as)}async function ls(){await F({agent:"kimi-code",createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Er,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Er,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:rp(t)}),getContext:(e,t,n,r)=>{let o=ne(e.cwd,t,n,r);if(!o)return null;let i=e.tool_input;if(!as.has(n)||!i||!Object.hasOwn(i,"cwd"))return o;let s=i.cwd;if(typeof s!=="string"||s.trim()==="")return P(r,t,n),null;let a=me(s,[o.configCwd]);if(!a)return P(r,t,n,s),null;return{configCwd:o.configCwd,executionCwd:a}},getSessionId:(e)=>e.session_id})}var op={"antigravity-cli":Ki,"claude-code":ts,"copilot-cli":ns,cursor:rs,"gemini-cli":os,"grok-build":is,"hermes-agent":ss,"kimi-code":ls},nt=Ji.map((e)=>({...e,run:op[e.id]}));function cs(e){let t=_({label:"hook",booleans:Object.fromEntries(nt.map((r)=>[r.id,[...r.flags,...r.legacyFlags]]))},e);if(t.errors.length>0)return;let n=nt.filter((r)=>t.flags[r.id]);return n.length===1?n[0]:void 0}function ds(e){return nt.find((t)=>t.legacyTopLevelFlags.some((n)=>n===e))}var ip=nt.map((e)=>({flags:e.flags.join(", "),description:e.description})),sp=nt.flatMap((e)=>e.flags.map((t)=>`cc-safety-net hook ${t}`)),us={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...ip,{flags:"-h, --help",description:"Show this help"}],examples:sp};var ps={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...z.map((e)=>({flags:e.flag,description:`Install ${R(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...z.map((e)=>`cc-safety-net install ${e.flag}`)]},fs={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...z.map((e)=>({flags:e.flag,description:`Uninstall ${R(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...z.map((e)=>`cc-safety-net uninstall ${e.flag}`)]},ms={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 gs={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 rt={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>",description:"Add a rulebook source and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Refresh rulebook lock/cache state"},{usage:"sync",description:"Sync configured rulebooks"},{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:"--check",description:"Check without changing lock/cache state"},{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"},{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","cc-safety-net rule add project-rules","cc-safety-net rule sync","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var hs={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 ys={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 Qt=[hs,Oi,gs,$i,rt,ps,ms,fs,us,Ni,ys];function ap(e){return e.aliases??[]}function en(e){let t=e.toLowerCase();return Qt.find((n)=>n.name.toLowerCase()===t||ap(n).some((r)=>r.toLowerCase()===t))}import{basename as lp}from"node:path";function tn(e=7,t=pe()){let n=Date.now()-e*24*60*60*1000,r=[],o=new Set,i=0,s,a,l,c;if(t)Ae(t);let d={count:0},p=t?Le(t,d):[];for(let u of p)for(let m of Ce(u,d)){if(m.decision==="allow")continue;let f=new Date(m.ts).getTime();if(f>=n){if(i++,o.add(m.sessionId??lp(u,".jsonl")),a===void 0||f<=a)s=m.ts,a=f;if(c===void 0||f>c)l=m.ts,c=f;cp(r,m,f)}}let g=r.map((u)=>({timestamp:u.ts,command:u.command,reason:u.reason,relativeTime:Wn(new Date(u.ts))}));return{totalBlocked:i,sessionCount:o.size,recentEntries:g,oldestEntry:s,newestEntry:l,unreadable:d.count}}function cp(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 dp}from"node:path";function Ls(e,t,n,r,o){let i;try{if(w(r)===null)return{path:e,exists:!1,valid:!1,ruleCount:0};i=ce(r),i.errors.push(...de(e,t,{userConfigDir:n},o))}catch(s){if(!(s instanceof H))throw s;i={errors:[s.message],ruleNames:new Set}}return{path:e,exists:!0,valid:i.errors.length===0,ruleCount:i.ruleNames.size,...i.errors.length>0?{errors:i.errors}:{}}}function up(e,t){return{source:t,name:e.name,command:e.command,subcommand:e.subcommand,blockArgs:[...e.block_args],reason:e.reason}}function vs(e,t){let n=t?.userConfigPath??ee(),r=t?.projectConfigPath??Q(e),o=dp(n),i=ve({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),s=te({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),a=new Map(i.rulebooks.flatMap((l)=>l.rules.map((c)=>[c,l.source])));return{userConfig:Ls(n,Ze({userConfigPath:n}),o,s.userConfigTarget,s.userScope),projectConfig:Ls(r,Xe(r),o,s.projectConfigTarget,s.projectScope),effectiveRules:i.rules.map((l)=>up(l,a.get(l.name)??"project")),shadowedRules:[]}}var pp=[{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 bs(){return[...pp.map((e)=>({name:e.flag.name,value:br(e.flag),isSet:wr(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 ws={error:0,warning:1,info:2},fp=["policy","config","audit"];function mp(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 gp=[{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=R(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:"Correct the named source, run `cc-safety-net rule sync` for a rule source, then rerun doctor."}]:[]},{derive:(e)=>{let t=e.environment.find((n)=>n.name==="CC_SAFETY_NET_AUDIT_SCOPE");return vr(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."}]:[]}},...fp.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 ${mp(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 ks(e){return gp.flatMap((t,n)=>t.derive(e).map((r,o)=>({finding:r,catalogOrder:n,occurrence:o}))).sort((t,n)=>ws[t.finding.severity]-ws[n.finding.severity]||t.catalogOrder-n.catalogOrder||t.occurrence-n.occurrence).map((t)=>t.finding)}function re(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var hp=(e)=>re()?`\x1B[32m${e}\x1B[0m`:e,yp=(e)=>re()?`\x1B[33m${e}\x1B[0m`:e,Lp=(e)=>re()?`\x1B[34m${e}\x1B[0m`:e,vp=(e)=>re()?`\x1B[35m${e}\x1B[0m`:e,bp=(e)=>re()?`\x1B[36m${e}\x1B[0m`:e,wp=(e)=>re()?`\x1B[31m${e}\x1B[0m`:e,kp=(e)=>re()?`\x1B[2m${e}\x1B[0m`:e,xp=(e)=>re()?`\x1B[1m${e}\x1B[0m`:e,h={green:hp,yellow:yp,blue:Lp,magenta:vp,cyan:bp,red:wp,dim:kp,bold:xp},Cp="\x1B[0m",Sp=[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 Dp(e){let t=e;return()=>(t=(t*1664525+1013904223)%4294967296,t/4294967296)}function Rp(e){let t=[...Sp],n=Dp(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 Ap(e,t=0){if(!re())return"";let n=Rp(t);return`\x1B[38;5;${n[e%n.length]}m`}function xs(e,t,n=0){if(!re())return`"${e}"`;return`${Ap(t,n)}"${e}"${Cp}`}var Ep=new RegExp("\x1B\\[[0-9;]*m","g"),Pr=(e)=>e.replace(Ep,"").length;function Ie(e){let t=(e.headers??e.rows[0]??[]).map((s,a)=>{let l=Math.max(...e.rows.map((c)=>Pr(c[a]??"")));return Math.max(Pr(s),l)}),n=(s,a)=>s+" ".repeat(Math.max(0,a-Pr(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(`
6
- `)}function Cs(e){let t=[];t.push("Hook Integration"),t.push(Pp(e));let n=[],r=[];for(let o of e){let i=R(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(h.red(` Error (${o.platform}): ${o.message}`));return t.join(`
7
- `)}function Pp(e){let t=["Platform","Discovery","Configuration","Inspection"],n=e.map((r)=>{let o=R(r.platform);if(r.inspectionStatus==="not-inspected"){let l=h.dim("Not inspected");return[o,l,l,l]}let i=r.detected?h.green("Detected"):r.inspectionStatus==="failed"?h.red("Unknown"):h.dim("Not detected"),s=r.configured?h.green("Configured"):r.detected?h.yellow("Not configured"):r.inspectionStatus==="failed"?h.red("Unknown"):h.dim("Not applicable"),a=r.inspectionStatus==="verified"?h.green("Verified"):r.inspectionStatus==="failed"?h.red("Failed"):h.dim("Not applicable");return[o,i,s,a]});return Ie({headers:t,rows:n})}function Ss(e){let n=["Guard Engine Verification",` Synthetic self-test: ${e.failed>0?h.red(`${e.passed}/${e.total} FAIL`):h.green(`${e.passed}/${e.total} passed`)}`],r=e.results.filter((o)=>!o.passed);if(r.length>0){n.push(""),n.push(h.red(" Failures:"));for(let o of r)n.push(h.red(` • ${o.description}`)),n.push(h.red(` expected ${o.expected}, got ${o.actual}`))}return n.join(`
8
- `)}function Tp(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 Ie({headers:t,rows:n})}function Ds(e){let t=[];if(t.push("Configuration"),t.push(Ip(e.userConfig,e.projectConfig)),t.push(""),e.effectiveRules.length>0)t.push(` Effective rules (${e.effectiveRules.length} total):`),t.push(Tp(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(`
9
- `)}function Ip(e,t){let n=["Scope","Status"],r=(i)=>{if(!i.exists)return h.dim("N/A");if(!i.valid)return h.red(`Invalid (${i.errors?.[0]??"unknown error"})`);return h.green("Configured")},o=[["User",r(e)],["Project",r(t)]];return Ie({headers:n,rows:o})}function Rs(e){let t=[];return t.push("Environment"),t.push(_p(e)),t.join(`
10
- `)}function As(e){let t=["Effective Safety",` Selected preset: ${e.effectiveSafety.selectedPreset}`,` Effective: ${e.effectiveSafety.level}`],n=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[r,o]of n){let i=e.effectiveSafety.capabilities[r],s=i.enabled?h.green("ON"):h.dim("OFF"),a=i.sources.length>0?` (${i.sources.join(", ")})`:"";t.push(` ${o}: ${s} via ${i.source}${a}`)}t.push(` Stored rule customizations: ${e.effectiveSafety.ruleCounts.stored}`),t.push(` Effective rule customizations: ${e.effectiveSafety.ruleCounts.effective}`);for(let[r,o]of Object.entries(e.effectiveSafety.ruleOverrides))t.push(` ${r}: ${o}`);return t.join(`
11
- `)}function Es(e){let t=["Findings"];if(e.length===0)return t.push(" No findings from inspected doctor facts."),t.join(`
12
- `);for(let n of e){let r=`[${n.severity.toUpperCase()}] ${n.checkId}: ${O(n.title)}`,o=n.severity==="error"?h.red:n.severity==="warning"?h.yellow:h.blue;if(t.push(` ${o(r)}`),t.push(` ${O(n.detail)}`),n.path)t.push(` Path: ${O(n.path)}`);if(n.fixHint)t.push(` Fix: ${O(n.fixHint)}`)}return t.join(`
13
- `)}function _p(e){let t=["Variable","Status","Legacy"],n=e.map((r)=>{let o=r.isSet?h.green("✓"):h.dim("✗"),i=r.legacyName&&r.legacyIsSet?`${r.legacyName} ${h.green("✓")}`:r.legacyName??"";return[r.name,o,i]});return Ie({headers:t,rows:n})}function Ps(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(Op(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(`
14
- `)}function Op(e){let t=["Time","Command"],n=e.map((r)=>{let o=O(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 Ie({headers:t,rows:n})}function Ts(e){let t=[];if(t.push("Update Check"),e.latestVersion===null&&!e.error)return t.push(nn([["Status",h.dim("Skipped")],["Installed",e.currentVersion]])),t.join(`
15
- `);if(e.error)return t.push(nn([["Status",`${h.yellow("⚠")} Error`],["Installed",e.currentVersion],["Error",h.dim(e.error)]])),t.join(`
16
- `);if(e.updateAvailable)return t.push(nn([["Status",`${h.yellow("⚠")} Update Available`],["Current",e.currentVersion],["Latest",h.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(`
17
- `);return t.push(nn([["Status",`${h.green("✓")} Up to date`],["Version",e.currentVersion]])),t.join(`
18
- `)}function nn(e){return Ie({rows:e})}function Is(e){let t=[];return t.push("System Info"),t.push($p(e)),t.join(`
19
- `)}function $p(e){let t=["Component","Version"],n=(i)=>{if(i===null)return h.dim("not found");return i},o=[{label:"cc-safety-net",value:e.version},...Xt.map((i)=>({label:R(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 Ie({headers:t,rows:o})}function _s(e){if(e.findings.length===0)return h.green(`
2
+ import{b as fi,c as mi,d as V,e as gi,f as vr,g as ct,h as He,i as Hr,j as be,k as Ss,l as zr,m as vn,n as Rs,o as Ds,p as bn}from"../chunks/index-2z9vsvqb.js";import{$a as Er,A as it,Aa as As,Ab as Ot,B as he,Ba as ye,Bb as Es,C as Oa,Ca as Nt,D as Yi,Da as qr,E as De,Ea as Vr,F as yn,Fa as ss,G as Dt,Ga as as,H as kr,Ha as wi,I as je,Ia as st,J as Se,Ja as ls,K as Ne,Ka as cs,L as re,La as Pr,M as xr,Ma as Ar,Na as Zi,O as oe,Oa as Sr,P as se,Pa as ge,Qa as Xi,R as ie,Ra as Ui,S as It,Sa as Gi,T as Fd,Ta as ru,U as Ae,Ua as xi,V as U,Va as Ci,W as Re,Wa as Ee,Xa as Si,Y as we,Ya as Ge,Z,Za as Ri,_ as Hs,_a as q,aa as Me,ab as Or,ba as Ln,bb as Fr,ca as Ut,cb as J,da as Ai,db as ou,ea as Ei,eb as ve,fa as $t,fb as iu,ga as Ue,gb as cn,ha as Mr,hb as su,ia as _i,ib as au,ja as Ti,jb as lu,ka as Le,kb as Be,la as Ps,lb as Y,ma as Kr,mb as cu,na as _s,nb as du,oa as Ts,ob as ds,pa as Ur,pb as us,qa as ns,qb as ps,ra as bi,rb as fs,s as Mt,sa as rs,sb as Pt,t as ts,ta as os,tb as Pe,u as H,ua as is,ub as W,v as Rt,va as Gr,vb as Qi,w as x,wa as Li,wb as Dr,x as St,xa as Ii,xb as _t,y as w,ya as S,yb as z,z as B,za as Br,zb as Ht}from"../chunks/index-6fvz7zfr.js";var vu=["-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(vu.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 bp,statSync as ys,unlinkSync as Lp}from"node:fs";import{basename as vs,dirname as wp,join as kp,resolve as xp}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 mr=(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 bu,readdirSync as Lu,readFileSync as wu}from"node:fs";import{join as ku}from"node:path";function Ce(e,t){try{return Lu(e,{withFileTypes:!0,encoding:"utf8"}).flatMap((n)=>{let r=ku(e,n.name);if(n.isDirectory())return Ce(r,t);if(n.name.endsWith(".jsonl"))return[r];return[]})}catch{if(t&&bu(e))t.count++;return[]}}function gr(e){let t=(o)=>`${o.sessionId}
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 xu=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Cu(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 xu.every((n)=>t[n]===void 0||typeof t[n]==="string")}function Fe(e,t){try{return wu(e,"utf-8").split(`
4
+ `).filter(Boolean).flatMap((n)=>{try{let r=JSON.parse(n);if(!Cu(r)){if(t)t.count++;return[]}return[r]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as cp}from"node:path";var Su=["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 hi(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 yi(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(yr(Ru(a,r,s)))}catch{o++}},finish(a){if(i)return i;try{i=yr({events:Object.freeze(t),droppedEvents:o,terminal:Du(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 Ru(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 Du(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(!vr(a))return;for(let l of gi(a))for(let c of l.match(/[^\s"'()$]+/g)??[])t.add(vi(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=hr(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 hr(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=hr(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 hr(e,t,n){let r=e.slice(0,t.maxTextLength),o=vr(r)?mi(r):r,i=n.size>0?Au(o,n):o;return(Pu(i)?fi(i):i).slice(0,t.maxTextLength)}function Pu(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&&Su.some((t)=>e.includes(t))||e.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(e)}function Au(e,t){return e.replace(/[^\s"'()$]+/g,(n)=>t.has(vi(n))?"<redacted>":n)}function vi(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 yr(e){if(e&&typeof e==="object"&&!Object.isFrozen(e)){for(let t of Object.values(e))yr(t);Object.freeze(e)}return e}function ki(e,t,n){let r=n??bi(),o=r.getCommandProgram(e,t.shell??"auto"),i=yi(),s=hi(i),a=o.dialect==="powershell"?r.getCommandProgram(e,"posix"):o,l=Li(a);s.recordGlobal({type:"parse",input:e,segments:l.map((m)=>[...m])});let c=wi(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 Eu}from"node:path";function br(e){let t=xi().safeParse(e);return{errors:t.success?[]:Si(t.error.issues),ruleNames:new Set(Ci(e).map((n)=>n.toLowerCase()))}}function Lr(e){let t=Di(e);if(!t.ok)return t.result;return br(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 Pi(e){return Eu(e??process.cwd(),".safety-net.json")}function me(e){let t=Di(e);if(!t.ok)return t.result;let n=Ri(t.parsed);return{errors:n.errors,ruleNames:n.sources}}import{join as _r,resolve as Gu}from"node:path";import{dirname as mn}from"node:path";var _u="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=wr(Ti(n.command));if(o.length===0)return[`tests[${r}]: could not parse fixture command: ${n.command}`];let i=o.reduce((s,a)=>s??Ii(a,t)?.id.slice(_u.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 wr(e){return e.nodes.flatMap((t)=>{if(t.kind==="group"||t.kind==="function")return wr(t.body);if(t.kind!=="command")return[];let n=_i(Ei(t.dialect,t.words)).words.map(Ai);return[...n.length>0?[n]:[],...t.nested.flatMap((r)=>wr(r))]})}var Tu=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function $i(e,t){let n=ji(e.rules,t);if(n.length>0)return{ok:!0,specs:n};return Fi(e.rules,t)}function Oi(e,t){let n=ji(e,t);if(n.length>0)return{ok:!0,specs:n};let r=$u(e,t);if(r.length>0)return{ok:!0,specs:r};let o=Ou(e,t);if(!o.ok)return o;if(o.specs.length>0)return{ok:!0,specs:o.specs};return Fi(e,t)}function Fi(e,t){let n=e.filter((r)=>Cr(r)?.name===t);if(n.length===1)return{ok:!0,specs:n};return Iu(t,n)}function Iu(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 ji(e,t){return e.filter((n)=>n===t)}function $u(e,t){let n=t.match(Tu),r=n?.[1],o=n?.[2],i=n?.[3];if(!r||!o||!i||!Ne(i))return[];return Ni(e,(s)=>s.owner===r&&s.repo===o&&s.ref===i)}function Ou(e,t){if(!Se(t))return{ok:!0,specs:[]};let[n,r]=t.split("/"),o=Ni(e,(s)=>s.owner===n&&s.repo===r);if(new Set(o.map((s)=>Cr(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 Cr(e){try{return je(e)}catch{return null}}function Ni(e,t){return e.filter((n)=>{let r=Cr(n);return r?t(r):!1})}var Bi=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Hi(e,t,n=Rt(mn(mn(t)),"rules policy"),r=ge()){if(re(e))return Hu(e,r);return Nu(e,t,n)}async function qi(e,t,n,r,o,i){if(!re(e))return Hi(e,t,n,r);let s=o?null:Fu(e,t,n);if(s)return s;if(!o&&!i)throw Error(`${e} is not vendored; run rule update ${e} to vendor it`);return Hi(e,t,n,r)}function Fu(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=Pt(Rr(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 Vi(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 ju(n,r,e,o),s=await Ki(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(kr);return p?.[1]?[p[1]]:[]}))].sort();if(m.length===0)throw Error(`No rulebooks found in ${e} under ${Dt}/`);return{source:e,owner:n,repo:r,ref:i,commit:s,names:m}}async function ju(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 Nu(e,t,n){xr(e);let r=Re(t,e),o=w(x(n,r));if(o===null)throw Error(`Rulebook source not found: ${e}`);let i=zi(Rr(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 Hu(e,t){let n=je(e),r=await Ki(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=zi(Rr(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 zi(e){let t=Pt(e),n=fn(t);if(n.length>0)throw Error(n.join("; "));return t}function Rr(e,t){try{return JSON.parse(e)}catch{throw Error(t)}}async function Ki(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 Mu(e,t,n={}){if(n.signal?.aborted)throw n.signal.reason;let r=n.budget??Sr(),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??Bi.timeoutMs);try{if(n.signal?.aborted)throw n.signal.reason;Ui(r);let l=await(n.fetch??fetch)(e,{signal:o.signal,redirect:"error"});if(!l.ok)return Ji(l),{response:l,content:""};return{response:l,content:await Uu(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 Mu(n.resolveUrl?.(e)??e,t,{budget:n.budget,signal:n.controller.signal})}async function Uu(e,t,n=Sr(),r){let o=Bi[`${t}Bytes`],i=Number(e.headers.get("content-length"));if(Number.isFinite(i)&&i>o)throw Ji(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{Gi(n,c.value.byteLength)}catch(d){throw r?.(),Mi(s),d}if(l+=c.value.byteLength,l>o)throw r?.(),Mi(s),Error(`GitHub ${t} response exceeds ${o} bytes`);a.push(Buffer.from(c.value))}return Buffer.concat(a,l).toString("utf-8")}function Ji(e){if(!e.body)return;Wi(()=>e.body?.cancel())}function Mi(e){Wi(()=>e.cancel())}function Wi(e){try{Promise.resolve(e()).catch(()=>{})}catch{}}async function Tt(e={}){let t=Ir(e);return Bu(t,await hn(t,ge()))}function Bu(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=Er(i.configTarget);if(!s.ok)return s.result;let a=s.config;if(e.check)return ip(a,i,e);let l=e.only?$i(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)=>qi(v,i.configDir,i.filesystemScope,t,c.has(v),!e.refresh||c.has(v)),m=await ep(a.rules,e.refresh?(v)=>d(v).then((D)=>({ok:!0,item:D})).catch((D)=>{if(Xi(D))throw D;return{ok:!1,spec:v,message:D instanceof Error?D.message:String(D)}}):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)=>qu(v,a.rules)),f=u.flatMap((v)=>Vu(v,o,i)),b=new Set([...p,...f].map((v)=>v.spec)),L=[...g,...p,...f],h=[],R=Ku(h,()=>u.flatMap((v)=>b.has(v.spec)||L.length>0&&o.has(v.spec)?[]:zu(v,i,n,h)));return{ok:L.length===0,errors:L.map((v)=>`Failed to update ${v.spec}: ${v.message}`),entries:u.map(Wu),changes:R}}catch(i){return Et(i)}}function qu(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 Vu(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 zu(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),Ju(e,s)}function Ku(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 Ju(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 Wu(e){return{spec:e.spec,name:e.rulebook.name,version:e.rulebook.version,ruleCount:e.rulebook.rules.length}}async function Tr(e,t={}){return Yu(e,np(t),ge())}async function Yu(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=Er(s.configTarget);if(!l.ok)return l.result;let c=l.config,d=Se(e);Zu(e,t,d);let m=d?await Vi(e,{ref:t.ref,operation:n}):null,g=m?Xu(m,t.rulebooks):[],u=m?g.map((h)=>Qu(c.rules,m,h)??`${e}#${m.ref}/${h}`):[e],p=u.filter((h)=>!c.rules.includes(h)),f=[...c.rules,...p];if(f.length>Pr)return tp();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 Zu(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)=>!De.test(o))??[];if(r.length>0)throw Error(`Invalid rulebook names: ${r.join(", ")}`)}function Xu(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 Qu(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 ep(e,t,n=ge()){if(e.length>Pr)throw Error(Ar);let r=Array(e.length),o=0,i,s=Array.from({length:Math.min(e.length,Zi.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 tp(){return{ok:!1,errors:[Ar],entries:[]}}function Ir(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 np(e){return{...Ir(e),ref:e.ref,rulebooks:e.rulebooks}}function rp(e){return{...Ir(e),deleteSource:e.deleteSource}}async function $r(e,t={}){try{return await op(e,rp(t),{})}catch(n){return Et(n)}}async function op(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=Oi(o.config.rules,e);if(!i.ok)return i.result;let s=t.deleteSource?sp(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=ap(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 ip(e,t,n){let r=Qi(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 sp(e,t,n){let r=t.flatMap((a)=>De.test(a)?[]:["--delete-source can only delete local rulebook sources"]),o=t.map((a)=>_r(e,a)),i=r.length>0?[]:o.flatMap((a)=>es(a,n)),s=[...r,...i];return s.length>0?{ok:!1,result:{ok:!1,errors:s,entries:[]}}:{ok:!0,dirs:o}}function es(e,t){let n=Gu(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,_r(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 ap(e,t,n){let r=e.flatMap((o)=>{try{if(!it(x(n,o)))return[];let i=es(o,n);if(i.length>0)return i;return lp(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 lp(e,t,n){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(e);return}he(x(n,_r(e,yn))),Yi(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=up(t),r=ss(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}=dp({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=pp(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=ki(e,n),c=l.decision,d=c?.ruleId??fp(e,n),m=$t.find((u)=>u.id===d&&u.activationCapability),g=m?r.policy.effectiveDestructiveCommandRules[m.id]:void 0;return{trace:gp(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:mp(hp(c?.ruleId,n.policySnapshot)),configSource:i,configValid:s,...o,...m&&g?{ruleActivation:{id:m.id,...g}}:{}}}function dp(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 up(e){let t=cp(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:ts(),protectedGitMetadata:is([t]),effectiveCapabilities:r.capabilities,strict:e?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function pp(e,t){let n=t.cwd??process.cwd(),r=ns(st("",{command:e},{kind:"command",shell:"posix"},{executionCwd:n,configCwd:n},e)),o=us(r);if(o)return{reason:ds,target:o.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let i=cs(r);if(i)return{reason:ls,target:i.target,ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};let s=os(r,t.protectedGitMetadata);if(s)return{reason:rs,target:s.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let a=t.policySnapshot.policy,l=a.secretProtection.enabled===!1?null:fs(r,a.secretProtection,{strict:t.strict});if(l)return{reason:ps,target:l.target,ruleId:l.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function fp(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 as(e,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function mp(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 gp(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 hp(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 gs,readFileSync as yp}from"node:fs";function ms(e,t){return{"safety.level":e.safety.level,...jr("safety.overrides",e.safety.overrides),"workflow.worktree_mode":String(e.workflow.worktree_mode),"destructive_command_protection.enabled":String(e.destructive_command_protection.enabled),...jr("destructive_command_protection.overrides",e.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":Nr(e.destructive_command_protection.allow_paths),"secret_protection.enabled":String(e.secret_protection.enabled),...jr("secret_protection.overrides",e.secret_protection.overrides),"secret_protection.deny_paths":Nr(e.secret_protection.deny_paths),"secret_protection.allow_paths":Nr(e.secret_protection.allow_paths),...t?{"audit.retention_days":String(e.audit.retention_days)}:{}}}function Ft(e,t,n){let r=ms(e,n),o=ms(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(!gs(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(!gs(e))return{errors:[`${e}: file not found`]};try{return{value:JSON.parse(yp(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=vp(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 jr(e,t){return Object.fromEntries(Object.entries(t).flatMap(([n,r])=>r===void 0?[]:[[`${e}.${n}`,String(r)]]))}function Nr(e){return e.length===0?"(none)":e.join(", ")}function vp(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Cp(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:hs(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):hs(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:xp(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 bs(e,t={}){let n=Cp(e);if(!n)return 1;let r=t.logsDir??be();if(n.pruneLegacy)return Sp(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 Ap(i,n,t.timeZone);let s=Date.now()-n.since*24*60*60*1000,a=i.filter((d)=>Ep(d,n,r,s)),l=n.suspect?gr(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(Ip(d.entry,t.timeZone));return 0}function Sp(e,t,n){let r=e?Dp(e).map((a)=>kp(e,a)):[];if(n)return Rp(r,t);let o=[],i=0,s=0;for(let a of r){let l=ys(a,{throwIfNoEntry:!1})?.size??0,c=Pp(a);if(c){o.push(`${vs(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"} (${Ls(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 Rp(e,t){let n=e.reduce((r,o)=>r+(ys(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"} (${Ls(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 Dp(e){try{return bp(e,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function Pp(e){try{return Lp(e),null}catch(t){return t instanceof Error?t.message:String(t)}}function Ls(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 Ap(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($p(o.entry,n)),0}function Ep(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&&!_p(e,n,t.session))return!1;if(t.project!==void 0&&!Tp(e.entry.cwd,t.project))return!1;return!0}function _p(e,t,n){if(e.entry.sessionId===n)return!0;return wp(e.file)===t&&vs(e.file,".jsonl")===n}function Tp(e,t){if(!e)return!1;return e===t||e.startsWith(`${t}/`)}function Ip(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(ws(e.ts,t))} ${r.padEnd(5)} ${F(e.agent??"-").padEnd(15)} ${F(e.ruleId??"-").padEnd(20)} ${s}${F(a)}${o}`}function $p(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(ws(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 ws(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 hs(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:null}var ks={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 xs={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 Cs={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 Is,join as Vp,relative as zp}from"node:path";var Op=8388608;function Fp(e,t){console.log(JSON.stringify(e(Rs(t))))}async function jp(e){let t;try{t=(await Jr(process.stdin)).trim()}catch{e({reason:"Failed to parse hook input JSON."});return}if(!t){e({reason:"Missing hook input JSON."});return}return Wr(t,e,"Failed to parse hook input JSON.")}async function Jr(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>Op)throw Np(e),Error("hook input byte limit exceeded");t.push(o)}return Buffer.concat(t,n).toString("utf-8")}function Np(e){let t=e.destroy??e.cancel;if(!t)return;try{Promise.resolve(t.call(e)).catch(()=>{})}catch{}}function Wr(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:Ps(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,Gp(o)),null}function T(e,t,n,r){let o;try{o=Kr(t)}catch(i){if(!(i instanceof Le))throw i}e(vn({command:o,segment:r,toolName:n}))}async function Hp(e){let t=await jp(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=qp(t),i=(u,p)=>{Ss(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),Bp(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=Kr(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:As(),dependencies:e.guardDependencies},audit:{agent:n,shape:r,getSessionId:()=>e.getSessionId(t)}}),p=zr(u,{includeEvidence:!0,toolName:u.stage==="command-analysis"?void 0:a});if(p){e.outputDeny(p);return}e.outputAllow?.()}catch(u){if(!(u instanceof Es))throw u;Mp(u);let p=zr(u.evaluation,{includeEvidence:!0,toolName:u.evaluation.stage==="command-analysis"?void 0:a});if(p)e.outputDeny(p);return}}function Mp(e){if(!Nt(S.debug))return;console.error(`CC Safety Net debug: ${Up(e.stage)}: ${Ds(e.cause)}`)}function Up(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 Gp(e){return typeof e==="string"?e:void 0}function Bp(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 qp(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)=>Fp(e.createDenyOutput,o),n=e.createAllowOutput;await Hp({...e,outputDeny:t,outputAllow:n?()=>console.log(JSON.stringify(n())):void 0})}function Gt(e){return Vp(e,".gemini","config","hooks.json")}var Kp=new Map([["run_command","auto"]]),Jp=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function $s(e){return j(e,Kp)}async function Os(){await N({agent:"antigravity-cli",createDenyOutput:(e)=>({decision:"deny",reason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolCall?.name,getToolInput:(e,t)=>({ok:!0,input:Qp(e.toolCall?.args,t),route:$s(t)}),getContext:Wp,getSessionId:(e)=>e.conversationId})}function Wp(e,t,n,r){let i=Xp(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=Yp(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=Fs(l,i);if(!c)return qe(r,t,n,a),null;return{configCwd:c,executionCwd:l}}return qe(r,t,n,a),null}function Yp(e,t,n){let r=$s(t),o=[..._s(e,Jp),...r.kind==="patch"?Ts(e):[]].filter(Is),i=Ln(),s=new Set(o.flatMap((a)=>{let l=Fs(Ut(a,Mt,i),n);return l?[l]:[]}));if(s.size>1)return null;return[...s][0]??n[0]??null}function Fs(e,t){return t.filter((n)=>Zp(e,n)).reduce((n,r)=>r.length>n.length?r:n,"")||null}function Zp(e,t){let n=zp(t,e);return n===""||!n.startsWith("..")&&!Is(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 Xp(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 Qp(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,install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:5,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:4,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:6,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:7,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:8,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:3,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),js=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),Kv=Object.fromEntries(Bt.map((e)=>[e.id,e.displayName]));function P(e){return Bt.find((t)=>t.id===e)?.displayName??e}import{homedir as e2}from"node:os";import{isAbsolute as Ns,join as Yr}from"node:path";function Ms(e){if(e!==void 0&&e!==null&&typeof e!=="string")return"unknown";if(typeof e==="string"&&!Ns(e))return"unknown";try{let t=Ln(),n=typeof e==="string"&&e?Ut(e,Mt,t):void 0,r=process.env.HOME||e2(),o=[["codex",process.env.CODEX_HOME||Yr(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||Yr(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||Yr(r,".claude")]],i=n?o.flatMap(([s,a])=>{if(!Ns(a))return[];return Hs(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 Zr="PreToolUse",Us="BeforeTool",Gs="pre_tool_call",Xr="PreToolUse";var t2=new Map([["Bash","posix"],["PowerShell","powershell"]]);function n2(e){return j(e,t2)}async function Bs(){await N({agent:"claude-code",getAgent:(e)=>Ms(e.transcript_path),createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Zr,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Zr,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:n2(t)}),getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var r2=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function o2(e){return j(e,r2)}async function qs(){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=Wr(e.toolArgs,n,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:o2(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 i2=new Map([["Shell","auto"]]);function s2(e){return j(e,i2)}async function Vs(){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:s2(t)}),getContext:a2,getSessionId:(e)=>e.conversation_id})}function a2(e,t,n,r){let o=l2(e);if(!o[0])return T(r,t,n),null;let i=we(d2(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 l2(e){return c2(e).flatMap((t)=>{let n=Z([t]);return n?[n]:[]})}function c2(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 d2(e){return typeof e==="string"&&e.trim()!==""?e:"."}var u2=new Map([["run_shell_command","auto"]]);function p2(e){return j(e,u2)}async function zs(){await N({agent:"gemini-cli",createDenyOutput:(e)=>({decision:"deny",reason:e,systemMessage:e}),isSupported:(e)=>e.hook_event_name===Us,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:p2(t)}),getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var f2=new Map([["run_terminal_command","auto"]]);function m2(e){return j(e,f2)}async function Ks(){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:m2(t)}},getContext:g2,getSessionId:(e)=>e.sessionId})}function g2(e,t,n,r){let o=Z(h2(e));if(!o)return T(r,t,n),null;let i=we(y2(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 h2(e){let t=e.workspaceRoot===void 0?e.cwd:e.workspaceRoot;return typeof t==="string"&&t.trim()!==""?[t]:[]}function y2(e){return typeof e==="string"&&e.trim()!==""?e:"."}import{resolve as v2}from"node:path";var b2=new Map([["terminal","posix"]]);async function Js(){await N({agent:"hermes-agent",createDenyOutput:(e)=>({action:"block",message:e}),isSupported:(e)=>e.hook_event_name===Gs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:j(t,b2)}),getContext:L2,getSessionId:(e)=>e.session_id})}function L2(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([v2(o.configCwd,i)]);if(!s)return T(r,t,n,i),null;return{...o,executionCwd:s}}var Ws=new Map([["Bash","posix"]]);function w2(e){return j(e,Ws)}async function Ys(){await N({agent:"kimi-code",createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Xr,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Xr,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:w2(t)}),getContext:(e,t,n,r)=>{let o=ae(e.cwd,t,n,r);if(!o)return null;let i=e.tool_input;if(!Ws.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 k2={"antigravity-cli":Os,"claude-code":Bs,"copilot-cli":qs,cursor:Vs,"gemini-cli":zs,"grok-build":Ks,"hermes-agent":Js,"kimi-code":Ys},dt=js.map((e)=>({...e,run:k2[e.id]}));function Zs(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 Xs(e){return dt.find((t)=>t.legacyTopLevelFlags.some((n)=>n===e))}var x2=dt.map((e)=>({flags:e.flags.join(", "),description:e.description})),C2=dt.flatMap((e)=>e.flags.map((t)=>`cc-safety-net hook ${t}`)),Qs={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...x2,{flags:"-h, --help",description:"Show this help"}],examples:C2};var ea={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 ${P(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}`)]},ta={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 ${P(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}`)]},na={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 ra={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 kn={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 Qr=[{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"}],eo=["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"},...Qr.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",...eo,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var oa={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 ia={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 xn=[oa,ks,ra,xs,ut,kn,ea,na,ta,Qs,Cs,ia];function S2(e){return e.aliases??[]}function Cn(e){let t=e.toLowerCase();return xn.find((n)=>n.name.toLowerCase()===t||S2(n).some((r)=>r.toLowerCase()===t))}import{basename as R2}from"node:path";function Sn(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??R2(u,".jsonl")),a===void 0||f<=a)s=p.ts,a=f;if(c===void 0||f>c)l=p.ts,c=f;D2(r,p,f)}}let g=r.map((u)=>({timestamp:u.ts,command:u.command,reason:u.reason,relativeTime:mr(new Date(u.ts))}));return{totalBlocked:i,sessionCount:o.size,recentEntries:g,oldestEntry:s,newestEntry:l,unreadable:d.count}}function D2(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 P2}from"node:path";function sa(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 A2(e,t){return{source:t,name:e.name,command:e.command,subcommand:e.subcommand,blockArgs:[...e.block_args],reason:e.reason}}function aa(e,t){let n=t?.userConfigPath??ie(),r=t?.projectConfigPath??oe(e),o=P2(n),i=Pe({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:sa(n,s.userConfigTarget,s.userScope),projectConfig:sa(r,s.projectConfigTarget,s.projectScope),effectiveRules:i.rules.map((l)=>A2(l,a.get(l.name)??"project")),shadowedRules:[]}}var E2=[{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 la(){return[...E2.map((e)=>({name:e.flag.name,value:qr(e.flag),isSet:Vr(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 ca={error:0,warning:1,info:2},_2=["policy","config","audit"];function T2(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 I2=[{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=P(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 Br(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 ${T2(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 da(e){return I2.flatMap((t,n)=>t.derive(e).map((r,o)=>({finding:r,catalogOrder:n,occurrence:o}))).sort((t,n)=>ca[t.finding.severity]-ca[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 $2=(e)=>le()?`\x1B[32m${e}\x1B[0m`:e,O2=(e)=>le()?`\x1B[33m${e}\x1B[0m`:e,F2=(e)=>le()?`\x1B[34m${e}\x1B[0m`:e,j2=(e)=>le()?`\x1B[35m${e}\x1B[0m`:e,N2=(e)=>le()?`\x1B[36m${e}\x1B[0m`:e,H2=(e)=>le()?`\x1B[31m${e}\x1B[0m`:e,M2=(e)=>le()?`\x1B[2m${e}\x1B[0m`:e,U2=(e)=>le()?`\x1B[1m${e}\x1B[0m`:e,y={green:$2,yellow:O2,blue:F2,magenta:j2,cyan:N2,red:H2,dim:M2,bold:U2},G2="\x1B[0m",B2=[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 q2(e){let t=e;return()=>(t=(t*1664525+1013904223)%4294967296,t/4294967296)}function V2(e){let t=[...B2],n=q2(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 z2(e,t=0){if(!le())return"";let n=V2(t);return`\x1B[38;5;${n[e%n.length]}m`}function ua(e,t,n=0){if(!le())return`"${e}"`;return`${z2(t,n)}"${e}"${G2}`}function Rn(e){return e==="default"?"built-in default":`${e} policy`}var K2=new RegExp("\x1B\\[[0-9;]*m","g"),to=(e)=>e.replace(K2,"").length;function Ve(e){let t=(e.headers??e.rows[0]??[]).map((s,a)=>{let l=Math.max(...e.rows.map((c)=>to(c[a]??"")));return Math.max(to(s),l)}),n=(s,a)=>s+" ".repeat(Math.max(0,a-to(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 pa(e){let t=[];t.push("Hook Integration"),t.push(J2(e));let n=[],r=[];for(let o of e){let i=P(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 J2(e){let t=["Platform","Discovery","Configuration","Inspection"],n=e.map((r)=>{let o=P(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 fa(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 W2(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 ma(e){let t=[];if(t.push("Configuration"),t.push(Y2(e.userConfig,e.projectConfig)),t.push(""),e.effectiveRules.length>0)t.push(` Effective rules (${e.effectiveRules.length} total):`),t.push(W2(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 Y2(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 ga(e){let t=[];return t.push("Environment"),t.push(Z2(e)),t.join(`
11
+ `)}function ha(e){let t=e.effectiveSafety.policyScopes,n=["Effective Safety",` Selected preset: ${e.effectiveSafety.selectedPreset}${t?` (${Rn(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
+ `)}function ya(e){let t=["Findings"];if(e.length===0)return t.push(" No findings from inspected doctor facts."),t.join(`
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 Z2(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 va(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(X2(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 X2(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 ba(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
+ `);if(e.error)return t.push(Dn([["Status",`${y.yellow("⚠")} Error`],["Installed",e.currentVersion],["Error",y.dim(e.error)]])),t.join(`
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
+ `);return t.push(Dn([["Status",`${y.green("✓")} Up to date`],["Version",e.currentVersion]])),t.join(`
19
+ `)}function Dn(e){return Ve({rows:e})}function La(e){let t=[];return t.push("System Info"),t.push(Q2(e)),t.join(`
20
+ `)}function Q2(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:P(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 wa(e){if(e.findings.length===0)return y.green(`
20
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=`
21
- ${e.findings.length} ${r}: ${n.join(", ")}.`;if(t.error>0)return h.red(o);if(t.warning>0)return h.yellow(o);return h.blue(o)}import{lstatSync as Np}from"node:fs";import{dirname as Tr}from"node:path";function Ir(e,t){try{let n=Np(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 Os(e){let t=pe();return{directories:[Ir("policy",Tr(Tr(e))),Ir("config",Tr(e)),...t?[Ir("audit",t)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as Fp}from"node:child_process";import{existsSync as $s}from"node:fs";import{delimiter as Hp,extname as Mp,join as jp}from"node:path";import{stripVTControlCharacters as Ns}from"node:util";var Hs="2.2.2",Up=5000,Gp="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function T(){return Hs}function _r(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 Bp(e){return(_r(e,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((t)=>t.length>0)}function qp(e,t){let n=Mp(e)?[e]:[...Bp(t).map((r)=>`${e}${r}`),e];if(e.includes("/")||e.includes("\\"))return n.find((r)=>$s(r))??e;return(_r(t,"PATH")??"").split(Hp).flatMap((r)=>n.map((o)=>jp(r,o))).find((r)=>$s(r))??e}function Fs(e){if(!/[\s"&|<>^]/.test(e))return e;return`"${e.replace(/"/g,'""')}"`}function _e(e,t){let[n,...r]=e,o=t[Gp]==="win32"?"win32":process.platform;if(!n||o!=="win32")return{cmd:n??"",args:r};let i=qp(n,t);if(!/\.(?:bat|cmd)$/i.test(i))return{cmd:i,args:r};return{cmd:_r(t,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Fs(i),...r.map(Fs)].join(" ")]}}var ot=async(e,t=Up)=>{let n=await Vp(e,{timeoutMs:t});if(n.code!==0)return null;return Ns(n.stdout).trim()||Ns(n.stderr).trim()||null};function Vp(e,t){let[n,...r]=e;if(!n)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((o)=>{try{let i=_e([n,...r],process.env),s=Fp(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(p),o(g)},p=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 rn(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(`
22
- `)[0]?.trim()||null}async function At(e=ot){let[t,n,r,o,i,s]=await Promise.all([Promise.all(z.map(async(a)=>[a.id,rn(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:Hs,versions:Object.fromEntries(t),codexPluginListOutput:n,ampPluginListOutput:r,nodeVersion:rn(o),npmVersion:rn(i),bunVersion:rn(s),platform:`${process.platform} ${process.arch}`}}function Or(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 be(){let e=T(),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=Or(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 zs from"node:readline";var Gs=(e)=>`\x1B[${e}B`,zp=(e)=>`\x1B[${e}A`;var Ms=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function Kp(e){return new Promise((t)=>setTimeout(t,e))}function Wp(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 Et(e,t){return e&&e>0?e:t}function on(e){return Math.max(0,Math.min(1,e))}function it(e){return Math.max(0,Math.min(255,Math.round(e)))}function $r(e){return e<=0.0031308?12.92*e:1.055*e**0.4166666666666667-0.055}function Jp(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:it($r(on(-0.0041960863*s-0.7034186147*a+1.707614701*l))*255),green:it($r(on(-1.2684380046*s+2.6097574011*a-0.3413193965*l))*255),red:it($r(on(4.0767416621*s-3.3077115913*a+0.2309699292*l))*255)}}function Nr(e,t){let n=(t*e*180/Math.PI%360+360)%360;return Jp(0.72,0.15,n)}function Bs(e,t=0.1){let n=Nr(t,e);return`\x1B[38;2;${n.red};${n.green};${n.blue}m`}function Yp(e,t){return{blue:it(e.blue+(255-e.blue)*t),green:it(e.green+(255-e.green)*t),red:it(e.red+(255-e.red)*t)}}function qs(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 Zp(e,t,n){let r=Math.floor(qs(e,t,n)*Ms.length);return Ms[r]??"░"}function js(e){let t=on(e);return t*t*t*(t*(t*6-15)+10)}function Xp(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 Qp(e,t,n,r,o){return e.map((i,s)=>({...Nr(n,r+t+s/o),bold:!1,character:i}))}function e2(e,t,n,r,o,i,s,a){let l=Math.max(1,r*0.75),c=Math.min(1,n/l),d=o*js(c),p=Math.max(0,(n-l)/Math.max(1,r-l)),g=(1-js(n/r))*a*2,u=0.35*Math.max(0,1-p*2),m=c>=1,f=Math.min(e.length,Math.ceil(d+2+1));return e.slice(0,f).map((L,v)=>{let x=Nr(i,s+t+v/a+g),y=v+qs(t,v,7919)*2-1;if(y>d+2)return{...x,bold:!1,character:" "};let C=d-y,j=0.8*Math.exp(-(C*C)/12.5),ye=Math.min(0.9,j+u),zn=!m&&y>d-4;return{...Yp(x,ye),bold:ye>0.3,character:zn?Zp(t,v,n):L}})}function Us(e){return`\x1B[?2026h${e.map((t,n)=>`\x1B8${n>0?Gs(n):""}${Xp(t)}`).join("")}\x1B[?2026l`}async function Fr(e,t={}){if(!e)return;let n=t.output??process.stdout,r=t.sleep??Kp,o=Et(t.frequency,0.1),i=t.seed??0,s=Et(t.speed,40),a=Et(t.spread,3),l=Et(t.frameRate,60),c=Math.max(1,Math.floor(Et(t.duration,12))),d=e.split(`
23
- `).map((f)=>Array.from(f)),p=Math.max(...d.map((f)=>f.length)),g=1000*c*d.filter((f)=>f.length>0).length/s,u=p>0?Math.max(1,Math.ceil(g/(1000/l))):0,m=u>0?g/u:0;n.write(`\x1B[?25l${d.length>1?`${`
24
- `.repeat(d.length-1)}${zp(d.length-1)}`:""}\x1B7`);try{for(let f=1;f<=u;f+=1){if(t.signal?.aborted)break;n.write(Us(d.map((L,v)=>e2(L,v,f,u,p,o,i,a)))),await Wp(m,r,t.signal)}}finally{if(n.write(Us(d.map((f,L)=>Qp(f,L,o,i,a)))),n.write("\x1B8"),d.length>1)n.write(Gs(d.length-1));n.write(`
25
- \x1B[0m\x1B[?25h`)}}var Vs=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
- `);function t2(e){return Boolean(e.isTTY)}async function Pt(e={}){let t=e.output??process.stdout;if(!t2(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 Fr(Vs,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()};zs.emitKeypressEvents(n),n.on("keypress",l),n.setRawMode(!0),n.resume();try{await Fr(Vs,{...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")}var Ks="\r\x1B[2K",n2="\x1B[?25l",r2="\x1B[39m",o2="\x1B[?25h",i2=100,s2=0.55,a2=80,Ws=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function l2(e){return new Promise((t)=>setTimeout(t,e))}async function sn(e,t={}){let n=t.output??process.stdout;if(!n.isTTY)return e;let r=t.sleep??l2,o=!1,i=e.then((a)=>(o=!0,a),(a)=>{throw o=!0,a});if(await Promise.race([i.then(()=>!0),r(i2).then(()=>!1)]))return i;n.write(n2);try{for(let a=0;!o;a+=1)n.write(`${Ks}${Bs(a*s2)}${Ws[a%Ws.length]}${r2} ${t.loadingMessage??"Loading…"}`),await Promise.race([i,r(a2)]);return await i}finally{n.write(`${Ks}${o2}`)}}async function Tt(e,t,n,r={}){let o=t();if(e)await n();if(e&&o.ready)await sn(o.ready,r);return o.finish()}import{homedir as Hf}from"node:os";import{stripVTControlCharacters as c2}from"node:util";var an="amp plugins list",d2=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Js(e){if(!e.ampPluginListOutput)return{platform:"amp",status:"n/a"};let t=c2(e.ampPluginListOutput).split(`
27
- `).map((n)=>d2.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:an,configPath:an,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:an,configPath:an}}import{existsSync as u2,readFileSync as p2}from"node:fs";var f2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function m2(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"||!f2.test(a))return[];return[{command:a,enabled:n.enabled!==!1}]})})})}function Ys(e){let t=Dt(e.homeDir);if(!u2(t))return{platform:"antigravity-cli",status:"n/a",configPath:t};let n;try{n=m2(JSON.parse(p2(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 Zs}from"node:path";import{existsSync as g2,lstatSync as h2,readFileSync as y2}from"node:fs";function oe(e,t=(n)=>n){if(!g2(e))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(t(y2(e,"utf-8")))}}catch{return{kind:"unreadable"}}}function E(e){try{return h2(e)}catch{return}}function ln(e,t){let n=E(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 b(e,t){return typeof e==="object"&&e!==null?e[t]:void 0}var Hr="cc-safety-net@cc-marketplace";function Xs(e){return Zs(e,".claude","plugins","installed_plugins.json")}function Qs(e,t){let n=b(b(e,"plugins"),t);return Array.isArray(n)&&n.length>0}function cn(e,t){let n=oe(Xs(e));return n.kind==="ok"&&Qs(n.value,t)}function Mr(e){let t=Xs(e),n=oe(t);if(n.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(n.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Qs(n.value,Hr))return{platform:"claude-code",status:"n/a"};let r=Zs(e,".claude","settings.json"),o=oe(r);if(o.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(o.kind==="ok"&&b(b(o.value,"enabledPlugins"),Hr)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:r,errors:[`${Hr} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:t}}function ea(e){return Mr(e.homeDir)}function ta(e){if(!e.codexPluginListOutput)return{platform:"codex",status:"n/a"};let t=e.codexPluginListOutput.split(`
28
- `).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 fn,readdirSync as L2,readFileSync as v2}from"node:fs";import{join as M}from"node:path";var ie="cc-safety-net@cc-marketplace",dn=["cc-marketplace","cc-safety-net"],na=["_direct","copilot-safety-net"],ra=["cc-marketplace","safety-net"],oa="safety-net@cc-marketplace";function un(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${n}([^a-z0-9-]|$)`,"m").test(e??"")}function ia(e){return un(e,"cc-safety-net@cc-marketplace")}function sa(e){return un(e,"cc-marketplace")}function aa(e){return un(e,"copilot-safety-net")}function la(e){return un(e,"safety-net@cc-marketplace")}function q(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]!==`
29
- `)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 jr(e){if(!e?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(e)}function da(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 b2(e){return da(e,[0,0,422])}function w2(e){return da(e,[1,0,8])}function It(e){return process.env.COPILOT_HOME||M(e,".copilot")}function Ur(e){return(e.hooks?.preToolUse??[]).some((n)=>{if(n.type!=="command")return!1;return jr(n.command)||jr(n.bash)||jr(n.powershell)})}function pn(e){return e===void 0||typeof e==="string"}function k2(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)&&pn(r.type)&&pn(r.command)&&pn(r.bash)&&pn(r.powershell))}function Gr(e,t){try{let n=JSON.parse(q(v2(e,"utf-8")));if(!k2(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 ua(e,t){try{return L2(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 x2(e,t){if(!fn(e))return[];let n=[];for(let r of ua(e,t)){let o=M(e,r),i=Gr(o,t);if(i&&Ur(i))n.push(o)}return n}function st(e,t){if(!fn(e))return;let n=Gr(e,t);if(!n)return;return{path:e,config:n}}function ca(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 C2(e){for(let t of e){if(t?.config.disableAllHooks===!0)return t.path;if(t?.config.disableAllHooks===!1)return}return}function S2(e,t,n,r){let o=It(e),i=M(t,".github","hooks"),s=M(o,"hooks"),a=M(t,".github","copilot"),l=M(t,".claude"),c=w2(n),d=c===!0?r:void 0,p=[st(M(a,"settings.local.json"),d),st(M(a,"settings.json"),d),st(M(l,"settings.local.json"),d),st(M(l,"settings.json"),d)],g=[st(M(o,"settings.json"),d),st(M(o,"config.json"),d)];if(c!==!1){let C=C2([...p,...g]);if(C){if(c===null)r.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${C} as active`);return{activeConfigPaths:[],disabledBy:C}}}let u=x2(i,r),m=b2(n),f=m===!0?r:void 0,L=fn(s)?ua(s,f):[],v=[];for(let C of L){let j=M(s,C),ye=Gr(j,f);if(ye&&Ur(ye))v.push(j)}if(m!==!0&&v.length>0)ca(r,n,`user hook files in ${s}`,"0.0.422"),v.length=0;let x=[];for(let C of[...p,...g]){if(!C)continue;if(!Ur(C.config))continue;if(c===!0){x.push(C);continue}ca(r,n,"inline hook definitions in Copilot config files","1.0.8");break}let y=(C)=>C.filter((j)=>!!j&&x.includes(j)).map((j)=>j.path);return{activeConfigPaths:[...y(p),...u,...y(g),...v]}}function pa(e){let t=[],n=S2(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=It(e.homeDir),o=M(r,"installed-plugins",...dn),i=fn(o),s=M(r,"settings.json"),a=oe(s,q);if(i&&a.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(i&&a.kind==="ok"&&b(b(a.value,"enabledPlugins"),ie)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:s,errors:[`${ie} 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 $2,readFileSync as N2}from"node:fs";import{existsSync as fa,mkdirSync as A2,readFileSync as E2}from"node:fs";import{dirname as P2,join as T2}from"node:path";import{renameSync as D2,writeFileSync as R2}from"node:fs";function I(e,t){let n=`${e}.${process.pid}.tmp`;R2(n,t),D2(n,e)}var _t="npx -y cc-safety-net hook --cursor",ma=30;function gn(e){return T2(e,".cursor","hooks.json")}function Oe(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Br(){return{command:_t,timeout:ma,failClosed:!0}}function mn(e){return Oe(e)&&e.command===_t}function I2(e){return Object.keys(e).length===3&&e.command===_t&&e.timeout===ma&&e.failClosed===!0}function _2(e){try{return JSON.parse(E2(e,"utf-8"))}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${e}: ${t.message}`);throw t}}function ga(e){let t=_2(e);if(!Oe(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&&!Oe(t.hooks))throw Error(`Cursor hooks config ${e} "hooks" must be an object`);let n=Oe(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 ha(e){let t=Oe(e.hooks)?e.hooks.preToolUse:void 0;return Array.isArray(t)?t:[]}function O2(e){if(!e.some(mn))return[...e,Br()];return e.reduce((t,n)=>{if(!mn(n))return t.result.push(n),t;if(!t.inserted)t.result.push(Br()),t.inserted=!0;return t},{result:[],inserted:!1}).result}function ya(e,t,n){let r=Oe(t.hooks)?t.hooks:{},o={...t,hooks:{...r,preToolUse:n}};I(e,`${JSON.stringify(o,null,2)}
30
- `)}function La(e){let t=gn(e);if(!fa(t))return A2(P2(t),{recursive:!0}),I(t,`${JSON.stringify({version:1,hooks:{preToolUse:[Br()]}},null,2)}
31
- `),{path:t,alreadyInstalled:!1};let n=ga(t),r=ha(n),o=r.filter(mn);if(Oe(n.hooks)&&Array.isArray(n.hooks.preToolUse)&&o.length===1&&o[0]!==void 0&&I2(o[0]))return{path:t,alreadyInstalled:!0};return ya(t,n,O2(r)),{path:t,alreadyInstalled:!1}}function va(e){let t=gn(e);if(!fa(t))return{path:t,alreadyInstalled:!1};let n=ga(t),r=ha(n),o=r.filter((i)=>!mn(i));if(o.length===r.length)return{path:t,alreadyInstalled:!1};return ya(t,n,o),{path:t,alreadyInstalled:!0}}function F2(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===_t)}function H2(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 ba(e){let t=gn(e.homeDir);if(!$2(t))return{platform:"cursor",status:"n/a",configPath:t};let n;try{n=JSON.parse(N2(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=F2(n);if(r.length===0)return{platform:"cursor",status:"n/a",configPath:t};let o=H2(r);return{platform:"cursor",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{existsSync as M2}from"node:fs";import{join as qr}from"node:path";var Vr="gemini-safety-net";function zr(e){let t=qr(e,".gemini","extensions"),n=qr(t,Vr);if(!M2(n))return{platform:"gemini-cli",status:"n/a"};let r=qr(t,"extension-enablement.json"),o=oe(r);if(o.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let i=o.kind==="ok"?b(b(o.value,Vr),"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:[`${Vr} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:n}}function wa(e){return zr(e.homeDir)}import{existsSync as B2,readFileSync as q2}from"node:fs";import{existsSync as xa,mkdirSync as j2,readFileSync as Ca,rmSync as U2}from"node:fs";import{dirname as G2,join as ka}from"node:path";var Ot="npx -y cc-safety-net hook --grok-build",Ln=30;function vn(e){return ka(process.env.GROK_HOME??ka(e,".grok"),"hooks","cc-safety-net.json")}function $e(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function hn(){return{hooks:[{type:"command",command:Ot,timeout:Ln}]}}function Sa(e){return $e(e)&&e.command===Ot}function Da(e){return e.flatMap((t)=>{if(!$e(t)||!Array.isArray(t.hooks))return[t];let n=t.hooks.filter((r)=>!Sa(r));if(n.length===t.hooks.length)return[t];return n.length===0?[]:[{...t,hooks:n}]})}function Ra(e){try{let t=JSON.parse(e);return $e(t)?t:null}catch{return null}}function Aa(e){let t=$e(e.hooks)?e.hooks.PreToolUse:void 0;return Array.isArray(t)?t:[]}function yn(e,t,n){let r=$e(t.hooks)?t.hooks:{};I(e,`${JSON.stringify({...t,hooks:{...r,PreToolUse:n}},null,2)}
32
- `)}function Ea(e){let t=vn(e);if(!xa(t))return j2(G2(t),{recursive:!0}),yn(t,{},[hn()]),{path:t,alreadyInstalled:!1};let n=Ra(Ca(t,"utf-8"));if(!n)return yn(t,{},[hn()]),{path:t,alreadyInstalled:!1};let r=Aa(n),o=r.filter((i)=>$e(i)&&Array.isArray(i.hooks)&&i.hooks.some(Sa));if(o.length===1&&JSON.stringify(o[0])===JSON.stringify(hn()))return{path:t,alreadyInstalled:!0};return yn(t,n,[...Da(r),hn()]),{path:t,alreadyInstalled:!1}}function Pa(e){let t=vn(e);if(!xa(t))return{path:t,alreadyInstalled:!1};let n=Ra(Ca(t,"utf-8"));if(!n)return{path:t,alreadyInstalled:!1};let r=Aa(n),o=Da(r);if(JSON.stringify(o)===JSON.stringify(r))return{path:t,alreadyInstalled:!1};let i=$e(n.hooks)?n.hooks:{};if(o.length===0&&Object.keys(n).length===1&&Object.keys(i).length===1)return U2(t),{path:t,alreadyInstalled:!0};return yn(t,n,o),{path:t,alreadyInstalled:!0}}function $t(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function V2(e){if(!$t(e)||!$t(e.hooks))return[];let t=e.hooks.PreToolUse;if(!Array.isArray(t))return[];return t.filter((n)=>$t(n)&&Array.isArray(n.hooks)&&n.hooks.some((r)=>$t(r)&&r.command===Ot))}function z2(e){let n=(Array.isArray(e.hooks)?e.hooks.filter($t):[]).find((r)=>r.command===Ot);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===Ln?[]:[`Managed hook "timeout" is not ${Ln}; reinstall to repair`]]}function Ta(e){let t=vn(e.homeDir);if(!B2(t))return{platform:"grok-build",status:"n/a",configPath:t};let n;try{n=JSON.parse(q2(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=V2(n)[0];if(!r)return{platform:"grok-build",status:"n/a",configPath:t};let o=z2(r);return{platform:"grok-build",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{readFileSync as ja}from"node:fs";import{join as Ua}from"node:path";var K="cc-safety-net",Ia="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent";function _a(e){return`# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent
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 ef}from"node:fs";import{dirname as no}from"node:path";function ro(e,t){try{let n=ef(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 ka(e){let t=be();return{directories:[ro("policy",no(no(e))),ro("config",no(e)),...t?[ro("audit",t)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as tf}from"node:child_process";import{existsSync as xa}from"node:fs";import{delimiter as nf,extname as rf,join as of}from"node:path";import{stripVTControlCharacters as Ca}from"node:util";var Ra="2.3.1",sf=5000,af="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function I(){return Ra}function oo(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 lf(e){return(oo(e,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((t)=>t.length>0)}function cf(e,t){let n=rf(e)?[e]:[...lf(t).map((r)=>`${e}${r}`),e];if(e.includes("/")||e.includes("\\"))return n.find((r)=>xa(r))??e;return(oo(t,"PATH")??"").split(nf).flatMap((r)=>n.map((o)=>of(r,o))).find((r)=>xa(r))??e}function Sa(e){if(!/[\s"&|<>^]/.test(e))return e;return`"${e.replace(/"/g,'""')}"`}function ze(e,t){let[n,...r]=e,o=t[af]==="win32"?"win32":process.platform;if(!n||o!=="win32")return{cmd:n??"",args:r};let i=cf(n,t);if(!/\.(?:bat|cmd)$/i.test(i))return{cmd:i,args:r};return{cmd:oo(t,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Sa(i),...r.map(Sa)].join(" ")]}}var pt=async(e,t=sf)=>{let n=await df(e,{timeoutMs:t});if(n.code!==0)return null;return Ca(n.stdout).trim()||Ca(n.stderr).trim()||null};function df(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=tf(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 Pn(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,Pn(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:Ra,versions:Object.fromEntries(t),codexPluginListOutput:n,ampPluginListOutput:r,nodeVersion:Pn(o),npmVersion:Pn(i),bunVersion:Pn(s),platform:`${process.platform} ${process.arch}`}}function io(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=io(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 $a from"node:readline";var Ea=(e)=>`\x1B[${e}B`,uf=(e)=>`\x1B[${e}A`;var Da=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function pf(e){return new Promise((t)=>setTimeout(t,e))}function ff(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 An(e){return Math.max(0,Math.min(1,e))}function ft(e){return Math.max(0,Math.min(255,Math.round(e)))}function so(e){return e<=0.0031308?12.92*e:1.055*e**0.4166666666666667-0.055}function mf(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(so(An(-0.0041960863*s-0.7034186147*a+1.707614701*l))*255),green:ft(so(An(-1.2684380046*s+2.6097574011*a-0.3413193965*l))*255),red:ft(so(An(4.0767416621*s-3.3077115913*a+0.2309699292*l))*255)}}function ao(e,t){let n=(t*e*180/Math.PI%360+360)%360;return mf(0.72,0.15,n)}function _a(e,t=0.1){let n=ao(t,e);return`\x1B[38;2;${n.red};${n.green};${n.blue}m`}function gf(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 Ta(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 hf(e,t,n){let r=Math.floor(Ta(e,t,n)*Da.length);return Da[r]??"░"}function Pa(e){let t=An(e);return t*t*t*(t*(t*6-15)+10)}function yf(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 vf(e,t,n,r,o){return e.map((i,s)=>({...ao(n,r+t+s/o),bold:!1,character:i}))}function bf(e,t,n,r,o,i,s,a){let l=Math.max(1,r*0.75),c=Math.min(1,n/l),d=o*Pa(c),m=Math.max(0,(n-l)/Math.max(1,r-l)),g=(1-Pa(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=ao(i,s+t+L/a+g),R=L+Ta(t,L,7919)*2-1;if(R>d+2)return{...h,bold:!1,character:" "};let v=d-R,D=0.8*Math.exp(-(v*v)/12.5),ne=Math.min(0.9,D+u),un=!p&&R>d-4;return{...gf(h,ne),bold:ne>0.3,character:un?hf(t,L,n):b}})}function Aa(e){return`\x1B[?2026h${e.map((t,n)=>`\x1B8${n>0?Ea(n):""}${yf(t)}`).join("")}\x1B[?2026l`}async function lo(e,t={}){if(!e)return;let n=t.output??process.stdout,r=t.sleep??pf,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
+ `).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)}${uf(d.length-1)}`:""}\x1B7`);try{for(let f=1;f<=u;f+=1){if(t.signal?.aborted)break;n.write(Aa(d.map((b,L)=>bf(b,L,f,u,m,o,i,a)))),await ff(p,r,t.signal)}}finally{if(n.write(Aa(d.map((f,b)=>vf(f,b,o,i,a)))),n.write("\x1B8"),d.length>1)n.write(Ea(d.length-1));n.write(`
26
+ \x1B[0m\x1B[?25h`)}}var Ia=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
27
+ `);function Lf(e){return Boolean(e.isTTY)}async function zt(e={}){let t=e.output??process.stdout;if(!Lf(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 lo(Ia,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()};$a.emitKeypressEvents(n),n.on("keypress",l),n.setRawMode(!0),n.resume();try{await lo(Ia,{...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 wf}from"node:crypto";import{existsSync as Fa}from"node:fs";import{dirname as En,join as ja}from"node:path";var kf="`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.",xf="cache",Cf="rulebooks";function Na(e={}){let t=U(e),n=x(t.filesystemScope,Ma(t.configDir)),r=w(t.lockTarget);if(console.log(kf),r===null&&!Fa(n.path))return console.log(`No v2 lock or cache leftovers found in ${En(t.configDir)}; nothing to migrate.`),0;let o=Af(r),i=q(t.configTarget);if(!i.config&&(w(t.configTarget)!==null||o.size>0))return console.error(`Cannot migrate: the rules config in ${En(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)=>Sf(l,o,t,n,e.global===!0)))console.log(a);return he(t.lockTarget),Oa(n),console.log(`Removed the v2 lock and cache under ${En(t.configDir)}.`),0}function Ha(e){return[...new Set([{cwd:e},{cwd:e,global:!0}].flatMap((t)=>{let n=U(t);return[n.lockPath,Ma(n.configDir)]}))].filter((t)=>Fa(t))}function Sf(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&&Rf(a,i))return[];let l=t.get(e),c=l?Df(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 Rf(e,t){let n=_t(e);return!("problem"in n)&&n.rulebook.name===t}function Df(e,t,n,r){let o=ja(n,Cf,`${Pf(e)}--${e.digest.replace("sha256:","").slice(0,12)}`,yn),i=w(x(r,o));if(i===null||Tf(i)!==e.digest)return null;let s=_t(i);if("problem"in s||s.rulebook.name!==t)return null;return i}function Ma(e){return ja(En(e),xf)}function Pf(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 Af(e){let t=e===null?null:_f(e),n=Ua(t)&&Array.isArray(t.rulebooks)?t.rulebooks:[];return new Map(n.filter(Ef).map((r)=>[r.spec,r]))}function Ef(e){return Ua(e)&&typeof e.spec==="string"&&typeof e.digest==="string"}function Ua(e){return!!e&&typeof e==="object"}function _f(e){try{return JSON.parse(e)}catch{return null}}function Tf(e){return`sha256:${wf("sha256").update(e).digest("hex")}`}var Ga="\r\x1B[2K",If="\x1B[?25l",$f="\x1B[39m",Of="\x1B[?25h",Ff=100,jf=0.55,Nf=80,Ba=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Hf(e){return new Promise((t)=>setTimeout(t,e))}async function _n(e,t={}){let n=t.output??process.stdout;if(!n.isTTY)return e;let r=t.sleep??Hf,o=!1,i=e.then((a)=>(o=!0,a),(a)=>{throw o=!0,a});if(await Promise.race([i.then(()=>!0),r(Ff).then(()=>!1)]))return i;n.write(If);try{for(let a=0;!o;a+=1)n.write(`${Ga}${_a(a*jf)}${Ba[a%Ba.length]}${$f} ${t.loadingMessage??"Loading…"}`),await Promise.race([i,r(Nf)]);return await i}finally{n.write(`${Ga}${Of}`)}}async function Kt(e,t,n,r={}){let o=t();if(e)await n();if(e&&o.ready)await _n(o.ready,r);return o.finish()}import{homedir as mg}from"node:os";import{stripVTControlCharacters as Mf}from"node:util";var Tn="amp plugins list",Uf=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function qa(e){if(!e.ampPluginListOutput)return{platform:"amp",status:"n/a"};let t=Mf(e.ampPluginListOutput).split(`
28
+ `).map((n)=>Uf.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:Tn,configPath:Tn,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:Tn,configPath:Tn}}import{existsSync as Gf,readFileSync as Bf}from"node:fs";var qf=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Vf(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"||!qf.test(a))return[];return[{command:a,enabled:n.enabled!==!1}]})})})}function Va(e){let t=Gt(e.homeDir);if(!Gf(t))return{platform:"antigravity-cli",status:"n/a",configPath:t};let n;try{n=Vf(JSON.parse(Bf(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 za}from"node:path";import{existsSync as zf,lstatSync as Kf,readFileSync as Jf}from"node:fs";function ce(e,t=(n)=>n){if(!zf(e))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(t(Jf(e,"utf-8")))}}catch{return{kind:"unreadable"}}}function _(e){try{return Kf(e)}catch{return}}function In(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 co="cc-safety-net@cc-marketplace";function Ka(e){return za(e,".claude","plugins","installed_plugins.json")}function Ja(e,t){let n=k(k(e,"plugins"),t);return Array.isArray(n)&&n.length>0}function $n(e,t){let n=ce(Ka(e));return n.kind==="ok"&&Ja(n.value,t)}function uo(e){let t=Ka(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(!Ja(n.value,co))return{platform:"claude-code",status:"n/a"};let r=za(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"),co)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:r,errors:[`${co} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:t}}function Wa(e){return uo(e.homeDir)}function Ya(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 Nn,readdirSync as Wf,readFileSync as Yf}from"node:fs";import{join as M}from"node:path";var de="cc-safety-net@cc-marketplace",On=["cc-marketplace","cc-safety-net"],Za=["_direct","copilot-safety-net"],Xa=["cc-marketplace","safety-net"],Qa="safety-net@cc-marketplace";function Fn(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${n}([^a-z0-9-]|$)`,"m").test(e??"")}function el(e){return Fn(e,"cc-safety-net@cc-marketplace")}function tl(e){return Fn(e,"cc-marketplace")}function nl(e){return Fn(e,"copilot-safety-net")}function rl(e){return Fn(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 po(e){if(!e?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(e)}function il(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 Zf(e){return il(e,[0,0,422])}function Xf(e){return il(e,[1,0,8])}function Jt(e){return process.env.COPILOT_HOME||M(e,".copilot")}function fo(e){return(e.hooks?.preToolUse??[]).some((n)=>{if(n.type!=="command")return!1;return po(n.command)||po(n.bash)||po(n.powershell)})}function jn(e){return e===void 0||typeof e==="string"}function Qf(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)&&jn(r.type)&&jn(r.command)&&jn(r.bash)&&jn(r.powershell))}function mo(e,t){try{let n=JSON.parse(K(Yf(e,"utf-8")));if(!Qf(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 sl(e,t){try{return Wf(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 em(e,t){if(!Nn(e))return[];let n=[];for(let r of sl(e,t)){let o=M(e,r),i=mo(o,t);if(i&&fo(i))n.push(o)}return n}function mt(e,t){if(!Nn(e))return;let n=mo(e,t);if(!n)return;return{path:e,config:n}}function ol(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 tm(e){for(let t of e){if(t?.config.disableAllHooks===!0)return t.path;if(t?.config.disableAllHooks===!1)return}return}function nm(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=Xf(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=tm([...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=em(i,r),p=Zf(n),f=p===!0?r:void 0,b=Nn(s)?sl(s,f):[],L=[];for(let v of b){let D=M(s,v),ne=mo(D,f);if(ne&&fo(ne))L.push(D)}if(p!==!0&&L.length>0)ol(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(!fo(v.config))continue;if(c===!0){h.push(v);continue}ol(r,n,"inline hook definitions in Copilot config files","1.0.8");break}let R=(v)=>v.filter((D)=>!!D&&h.includes(D)).map((D)=>D.path);return{activeConfigPaths:[...R(m),...u,...R(g),...L]}}function al(e){let t=[],n=nm(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",...On),i=Nn(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 pm,readFileSync as fm}from"node:fs";import{existsSync as ll,mkdirSync as im,readFileSync as sm}from"node:fs";import{dirname as am,join as lm}from"node:path";import{renameSync as rm,writeFileSync as om}from"node:fs";function O(e,t){let n=`${e}.${process.pid}.tmp`;om(n,t),rm(n,e)}var Wt="npx -y cc-safety-net hook --cursor",cl=30;function Mn(e){return lm(e,".cursor","hooks.json")}function Ke(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function go(){return{command:Wt,timeout:cl,failClosed:!0}}function Hn(e){return Ke(e)&&e.command===Wt}function cm(e){return Object.keys(e).length===3&&e.command===Wt&&e.timeout===cl&&e.failClosed===!0}function dm(e){try{return JSON.parse(sm(e,"utf-8"))}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${e}: ${t.message}`);throw t}}function dl(e){let t=dm(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 ul(e){let t=Ke(e.hooks)?e.hooks.preToolUse:void 0;return Array.isArray(t)?t:[]}function um(e){if(!e.some(Hn))return[...e,go()];return e.reduce((t,n)=>{if(!Hn(n))return t.result.push(n),t;if(!t.inserted)t.result.push(go()),t.inserted=!0;return t},{result:[],inserted:!1}).result}function pl(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 fl(e){let t=Mn(e);if(!ll(t))return im(am(t),{recursive:!0}),O(t,`${JSON.stringify({version:1,hooks:{preToolUse:[go()]}},null,2)}
32
+ `),{path:t,alreadyInstalled:!1};let n=dl(t),r=ul(n),o=r.filter(Hn);if(Ke(n.hooks)&&Array.isArray(n.hooks.preToolUse)&&o.length===1&&o[0]!==void 0&&cm(o[0]))return{path:t,alreadyInstalled:!0};return pl(t,n,um(r)),{path:t,alreadyInstalled:!1}}function ml(e){let t=Mn(e);if(!ll(t))return{path:t,alreadyInstalled:!1};let n=dl(t),r=ul(n),o=r.filter((i)=>!Hn(i));if(o.length===r.length)return{path:t,alreadyInstalled:!1};return pl(t,n,o),{path:t,alreadyInstalled:!0}}function mm(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 gm(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 gl(e){let t=Mn(e.homeDir);if(!pm(t))return{platform:"cursor",status:"n/a",configPath:t};let n;try{n=JSON.parse(fm(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=mm(n);if(r.length===0)return{platform:"cursor",status:"n/a",configPath:t};let o=gm(r);return{platform:"cursor",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{existsSync as hm}from"node:fs";import{join as ho}from"node:path";var yo="gemini-safety-net";function vo(e){let t=ho(e,".gemini","extensions"),n=ho(t,yo);if(!hm(n))return{platform:"gemini-cli",status:"n/a"};let r=ho(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,yo),"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:[`${yo} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:n}}function hl(e){return vo(e.homeDir)}import{existsSync as Lm,readFileSync as wm}from"node:fs";import{existsSync as vl,mkdirSync as ym,readFileSync as bl,rmSync as vm}from"node:fs";import{dirname as bm,join as yl}from"node:path";var Yt="npx -y cc-safety-net hook --grok-build",Bn=30;function qn(e){return yl(process.env.GROK_HOME??yl(e,".grok"),"hooks","cc-safety-net.json")}function Je(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Un(){return{hooks:[{type:"command",command:Yt,timeout:Bn}]}}function Ll(e){return Je(e)&&e.command===Yt}function wl(e){return e.flatMap((t)=>{if(!Je(t)||!Array.isArray(t.hooks))return[t];let n=t.hooks.filter((r)=>!Ll(r));if(n.length===t.hooks.length)return[t];return n.length===0?[]:[{...t,hooks:n}]})}function kl(e){try{let t=JSON.parse(e);return Je(t)?t:null}catch{return null}}function xl(e){let t=Je(e.hooks)?e.hooks.PreToolUse:void 0;return Array.isArray(t)?t:[]}function Gn(e,t,n){let r=Je(t.hooks)?t.hooks:{};O(e,`${JSON.stringify({...t,hooks:{...r,PreToolUse:n}},null,2)}
33
+ `)}function Cl(e){let t=qn(e);if(!vl(t))return ym(bm(t),{recursive:!0}),Gn(t,{},[Un()]),{path:t,alreadyInstalled:!1};let n=kl(bl(t,"utf-8"));if(!n)return Gn(t,{},[Un()]),{path:t,alreadyInstalled:!1};let r=xl(n),o=r.filter((i)=>Je(i)&&Array.isArray(i.hooks)&&i.hooks.some(Ll));if(o.length===1&&JSON.stringify(o[0])===JSON.stringify(Un()))return{path:t,alreadyInstalled:!0};return Gn(t,n,[...wl(r),Un()]),{path:t,alreadyInstalled:!1}}function Sl(e){let t=qn(e);if(!vl(t))return{path:t,alreadyInstalled:!1};let n=kl(bl(t,"utf-8"));if(!n)return{path:t,alreadyInstalled:!1};let r=xl(n),o=wl(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 vm(t),{path:t,alreadyInstalled:!0};return Gn(t,n,o),{path:t,alreadyInstalled:!0}}function Zt(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function km(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 xm(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===Bn?[]:[`Managed hook "timeout" is not ${Bn}; reinstall to repair`]]}function Rl(e){let t=qn(e.homeDir);if(!Lm(t))return{platform:"grok-build",status:"n/a",configPath:t};let n;try{n=JSON.parse(wm(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=km(n)[0];if(!r)return{platform:"grok-build",status:"n/a",configPath:t};let o=xm(r);return{platform:"grok-build",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{readFileSync as Ol}from"node:fs";import{join as Fl}from"node:path";var Q="cc-safety-net",Dl="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent";function Pl(e){return`# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent
33
34
  # version: ${e}
34
- `}function K2(e){return`${_a(e)}name: cc-safety-net
35
+ `}function Cm(e){return`${Pl(e)}name: cc-safety-net
35
36
  version: "${e}"
36
37
  description: "Block destructive commands and secret-file access before Hermes runs a tool."
37
38
  author: "cc-safety-net"
38
39
  provides_hooks:
39
40
  - pre_tool_call
40
- `}function W2(e){return`${_a(e)}"""CC Safety Net guard for Hermes Agent.
41
+ `}function Sm(e){return`${Pl(e)}"""CC Safety Net guard for Hermes Agent.
41
42
 
42
43
  Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
43
44
  adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
@@ -175,86 +176,86 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
175
176
 
176
177
  def register(ctx):
177
178
  ctx.register_hook("pre_tool_call", _pre_tool_call)
178
- `}function Nt(e){return[{name:"__init__.py",content:W2(e)},{name:"plugin.yaml",content:K2(e)}]}import{mkdirSync as J2,readdirSync as Y2,readFileSync as Z2,rmSync as Kr}from"node:fs";import{join as Ne}from"node:path";var X2="__pycache__";function Wr(e){let t=process.env.HERMES_HOME?.trim();return t?t:Ne(e,".hermes")}function Jr(e){return Ne(Wr(e),"plugins",K)}function Yr(e){return e.startsWith(Ia)}function Zr(e,t){let n=Jr(e),r=E(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 Oa(e,t){let n=E(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=Z2(e,"utf-8");if(!Yr(r))throw Error(`Refusing to ${t} unmanaged file at ${e}. Move or remove it.`);return r}function $a(e){let t=Zr(e,"install"),n=Nt(T());if(n.map((o)=>Oa(Ne(t,o.name),"overwrite")).every((o,i)=>o===n[i]?.content))return{path:t,alreadyInstalled:!0};return J2(t,{recursive:!0}),n.forEach((o)=>{I(Ne(t,o.name),o.content)}),{path:t,alreadyInstalled:!1}}function Xr(e){let t=Zr(e,"remove");if(!E(t))return[];return Nt(T()).filter((n)=>Oa(Ne(t,n.name),"remove")!==void 0)}function Na(e){let t=Zr(e,"remove");if(!E(t))return{path:t,alreadyInstalled:!1};let n=Xr(e);if(n.forEach((r)=>{Kr(Ne(t,r.name))}),Kr(Ne(t,X2),{recursive:!0,force:!0}),Y2(t).length===0)Kr(t,{recursive:!0});return{path:t,alreadyInstalled:n.length>0}}var bn="hermes-agent",Fa=/^([^\s#][^:]*):/,Q2=/^\s+([A-Za-z_][\w-]*):/,Ha=/^\s+-\s*(.*)$/;function ef(e){return e.trim().replace(/^(["'])(.*)\1$/,"$2")}function tf(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>Fa.exec(i)?.[1]?.trim()==="plugins");if(n===-1)return[];let r=t.slice(n+1),o=r.findIndex((i)=>Fa.test(i));return o===-1?r:r.slice(0,o)}function Ma(e,t){let n=tf(e),r=n.findIndex((s)=>Q2.exec(s)?.[1]===t);if(r===-1)return[];let o=n.slice(r+1),i=o.findIndex((s)=>!Ha.test(s));return(i===-1?o:o.slice(0,i)).map((s)=>ef(Ha.exec(s)?.[1]??""))}function nf(e){try{return ja(Ua(Wr(e),"config.yaml"),"utf-8")}catch{return}}function Qr(e){let t=nf(e)??"";return Ma(t,"enabled").includes(K)&&!Ma(t,"disabled").includes(K)}function Ga(e){return/^# version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function rf(e,t){let n=E(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=ja(e,"utf-8");if(!Yr(r))return{error:`Unmanaged ${t.name} occupies ${e}; move or remove it`};if(Ga(r)===T()&&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 Ba(e){let t=Jr(e.homeDir),n=ln(bn,t);if(n)return n;let r=Nt(T()).map((a)=>rf(Ua(t,a.name),a)),o=r.flatMap((a)=>("error"in a)?[a.error]:[]);if(o.length>0)return{platform:bn,status:"n/a",configPath:t,errors:o};let i=r.some((a)=>("content"in a)&&Ga(a.content)!==T()),s=i?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Qr(e.homeDir))return{platform:bn,status:"disabled",method:"plugin directory",configPath:t,errors:[`${K} is not enabled in Hermes; run \`hermes plugins enable ${K}\``,...s]};return{platform:bn,status:"configured",method:"plugin directory",configPath:t,errors:i?s:void 0}}import{existsSync as of,readFileSync as sf}from"node:fs";import{join as qa}from"node:path";var af=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function lf(e){return qa(process.env.KIMI_CODE_HOME||qa(e,".kimi-code"),"config.toml")}function Ft(e){let t=lf(e.homeDir);if(!of(t))return{platform:"kimi-code",status:"n/a",configPath:t};try{if(!af.test(sf(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 el}from"node:fs";import{join as Mt}from"node:path";var A="cc-safety-net",W="index.js",at="openclaw.plugin.json",lt="package.json";var wn="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as uf,lstatSync as pf,readdirSync as ff,readFileSync as mf}from"node:fs";import{dirname as Ka,join as we}from"node:path";import{fileURLToPath as gf}from"node:url";import{spawn as cf}from"node:child_process";function df(e){return e.join(" ")}function eo(e,t,n){return[`Failed to run ${df(e)}${t===null?"":` (exit ${t})`}.`,n.trim()].filter(Boolean).join(`
179
- `)}function to(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 se(e,t){return new Promise((n,r)=>{let o=_e([...e],process.env),i=cf(o.cmd,o.args,{stdio:["ignore","pipe","pipe"]}),s=to(i),a=()=>[s.stdout,s.stderr].filter(Boolean).join(`
180
- `),l=t?.timeoutMs??120000,c=setTimeout(()=>{i.kill(),r(Error(eo(e,null,`Timed out after ${l}ms.
181
- ${a()}`.trim())))},l);i.on("error",(d)=>{clearTimeout(c),r(Error(eo(e,null,`${d.message}
182
- ${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(eo(e,d,a())));return}n(t?.stdoutOnly?s.stdout:a())})})}async function no(e){for(let t of e)await se(t)}async function Va(e){for(let t of e)try{await se(t)}catch(n){console.warn(n instanceof Error?n.message:String(n))}}var za=we("openclaw",A),hf=[W,at,lt];function ro(e,t){if(e==="~")return t;if(e.startsWith("~/")||e.startsWith("~\\"))return we(t,e.slice(2));return e}function Wa(e){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return ro(t,e);let n=process.env.OPENCLAW_CONFIG_PATH?.trim();return n?Ka(ro(n,e)):we(e,".openclaw")}function Ja(e){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?ro(t,e):we(Wa(e),"openclaw.json")}function oo(e){return we(Wa(e),"extensions",A)}function yf(e){let t=ff(e);if(t.length===0)return!0;if(t.some((o)=>!hf.includes(o)))return!1;let n=we(e,W),r=E(n);return r!==void 0&&!r.isSymbolicLink()&&r.isFile()&&mf(n,"utf-8").startsWith(wn)}function io(e){let t=oo(e),n=E(t);if(!n)return;if(!n.isSymbolicLink()&&n.isDirectory()&&yf(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 Ya(){let e=Ka(gf(import.meta.url));return[we(e,"..",za),we(e,"..","..","..","dist",za)]}function so(e=Ya()){return e.find((t)=>uf(t)&&pf(t).isDirectory())}function Lf(e=Ya()){let t=so(e);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function Za(e=Lf()){return[["openclaw","plugins","install",e,"--force"],["openclaw","plugins","enable",A]]}function vf(e){let t=(()=>{try{return JSON.parse(e)}catch{return}})(),n=b(b(t,"plugin"),"status");return typeof n==="string"?n:void 0}async function Xa(){let e=vf(await se(["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 kn="openclaw",Ht=`run \`openclaw plugins enable ${A}\``;function ct(e,t){let n=Mt(e,t),r=E(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:el(n,"utf-8")}}catch(o){return{error:`Failed to read ${n}: ${o instanceof Error?o.message:String(o)}`}}}function tl(e){try{return JSON.parse(q(e))}catch{return}}function bf(e){let t=ct(e,at);if("error"in t)return t.error;if(b(tl(t.content),"id")===A)return;return`${Mt(e,at)} is not a valid ${A} manifest; run install --openclaw`}function wf(e){let t=ct(e,lt);if("error"in t)return t.error;let n=b(b(tl(t.content),"openclaw"),"extensions");if(Array.isArray(n)&&n.includes(`./${W}`))return;return`${Mt(e,lt)} does not point OpenClaw at ${W}; run install --openclaw`}function Qa(e){return Array.isArray(e)?e.filter((t)=>typeof t==="string"):[]}function kf(e){let t=Ja(e);if(!E(t))return`${A} is not enabled; ${Ht}`;let n=(()=>{try{return JSON.parse(q(el(t,"utf-8")))}catch{return}})();if(n===void 0)return`Failed to read ${t}; fix it, then ${Ht}`;let r=b(n,"plugins");if(b(r,"enabled")===!1)return`plugins.enabled is false in ${t}; no OpenClaw plugin loads`;let o=b(b(b(r,"entries"),A),"enabled");if(Qa(b(r,"deny")).includes(A)||o===!1)return`${A} is disabled in ${t}; ${Ht}`;let i=Qa(b(r,"allow"));if(i.length>0&&!i.includes(A))return`plugins.allow in ${t} does not list ${A}; add it, then ${Ht}`;if(i.includes(A)||o===!0)return;return`${A} is not enabled; ${Ht}`}function nl(e){return/^\/\/ version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function xf(e,t,n){if(n===void 0)return[];let r=ct(n,W);if("error"in r||nl(r.content)!==t)return[];return[W,at,lt].flatMap((o)=>{let i=ct(e,o),s=ct(n,o);if("error"in i||"error"in s||i.content===s.content)return[];return[`Modified ${o} occupies ${Mt(e,o)}; run install --openclaw to restore it`]})}function rl(e){let t=oo(e.homeDir),n=ln(kn,t);if(n)return n;let r=ct(t,W),i=["error"in r?r.error:r.content.startsWith(wn)?void 0:`Unmanaged ${W} occupies ${Mt(t,W)}; move or remove it`,bf(t),wf(t)].filter((d)=>d!==void 0),s="content"in r?nl(r.content):void 0,a=i.length>0?i:xf(t,s,so());if(a.length>0)return{platform:kn,status:"n/a",configPath:t,errors:a};let l=s===T()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],c=kf(e.homeDir);if(c)return{platform:kn,status:"disabled",method:"plugin directory",configPath:t,errors:[c,...l]};return{platform:kn,status:"configured",method:"plugin directory",configPath:t,errors:l.length>0?l:void 0}}import{existsSync as Of,readFileSync as $f}from"node:fs";import{join as Nf}from"node:path";import{existsSync as ao,readFileSync as ll,rmSync as Sf}from"node:fs";import{join as ge}from"node:path";import{pathToFileURL as Df}from"node:url";function ol(e){return e!==void 0&&/\s/.test(e)}function Cf(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 xn(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=Cf(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 il(e,t){let n=e.lastIndexOf(`
183
- `,t)+1;return/^[ \t]*/.exec(e.slice(n))?.[0]??""}function Cn(e,t){let{start:n,end:r,end:o}=t;while(ol(e[o]))o++;if(e[o]===","){if(r=o+1,e[r]===`
184
- `)r++;return`${e.slice(0,n)}${e.slice(r)}`}o=t.start-1;while(ol(e[o]))o--;if(e[o]===","){n=o;let i=e.lastIndexOf(`
185
- `,n-1);if(i!==-1&&/^\s*$/.test(e.slice(i+1,n)))n=i}return`${e.slice(0,n)}${e.slice(r)}`}var Sn="cc-safety-net",cl=`${Sn}@latest`,dl=["opencode.json","opencode.jsonc"],sl="CCSafetyNetPlugin";function Dn(e){return ge(process.env.XDG_CONFIG_HOME||ge(e,".config"),"opencode")}function Rf(e){return ge(Dn(e),dl[0])}function Af(e){return dl.map((t)=>ge(Dn(e),t))}function ul(e){return ge(process.env.XDG_CACHE_HOME||ge(e,".cache"),"opencode","packages",cl)}function lo(e){Sf(ul(e),{recursive:!0,force:!0})}async function pl(e){let t=ge(ul(e),"node_modules",Sn),n=ge(t,"package.json");if(!ao(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 ${cl}\` for details.`);let r=b(JSON.parse(ll(n,"utf-8")),"main");if(typeof r!=="string")throw Error(`The cached OpenCode plugin at ${t} declares no "main" entry.`);let o=ge(t,r);if(typeof(await import(Df(o).href))[sl]==="function")return;throw Error(`The cached OpenCode plugin at ${o} does not export a callable ${sl}, so OpenCode would load nothing and fail open.`)}function Rn(e,t){if(e[t]==="/"&&e[t+1]==="/"){let n=e.indexOf(`
186
- `,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 al(e,t){let n=t;while(n<e.length){if(/\s/.test(e[n]??"")){n++;continue}let r=Rn(e,n);if(r===n)return n;n=r}return n}function fl(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 ml(e,t,n){return JSON.parse(e.slice(t,n))}function Ef(e,t){return xn(e,t,{skipComment:Rn,stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"})}function Pf(e){let t=0,n=0;while(n<e.length){let r=Rn(e,n);if(r!==n){n=r;continue}if(e[n]==='"'){let o=fl(e,n);if(t===1&&ml(e,n,o)==="plugin"){let i=al(e,o),s=al(e,i+1);if(e[i]===":"&&e[s]==="[")return{start:s,end:Ef(e,s)}}n=o;continue}if(e[n]==="{"||e[n]==="[")t++;if(e[n]==="}"||e[n]==="]")t--;n++}return}function Tf(e,t){let n=[],r=t.start+1;while(r<t.end){let o=Rn(e,r);if(o!==r){r=o;continue}if(e[r]==='"'){let i=fl(e,r),s=ml(e,r,i);if(typeof s==="string"&&s.includes(Sn))n.push({start:r,end:i});r=i;continue}r++}return n}function gl(e,t){try{return JSON.parse(q(e))}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${t}: ${n.message}`);throw n}}function If(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(Sn))}function _f(e,t){let n=Pf(e);if(!n)throw Error(`Failed to locate OpenCode plugin array in ${t}`);let r=[...Tf(e,n)].reverse().reduce(Cn,e);return gl(r,t),r}function hl(e){lo(e);let t=Af(e),n=t.find((o)=>ao(o)),r=[];for(let o of t){if(!ao(o))continue;try{let i=ll(o,"utf-8");if(!If(gl(i,o)))continue;return I(o,_f(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(`
187
- `));return{path:n??Rf(e),alreadyInstalled:!1}}function yl(e){let t=[],n=Dn(e.homeDir),r=["opencode.json","opencode.jsonc"];for(let o of r){let i=Nf(n,o);if(Of(i))try{let s=$f(i,"utf-8"),a=q(s);if((JSON.parse(a).plugin??[]).some((p)=>p.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 Ff}from"node:path";function co(e){return Ff(e,".pi","agent","settings.json")}function uo(e){if(typeof e!=="string")return!1;return e==="npm:cc-safety-net"||e.startsWith("npm:cc-safety-net@")}function Ll(e){let t=co(e.homeDir),n=oe(t);if(n.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(n.kind==="missing")return{platform:"pi",status:"n/a"};let r=b(n.value,"packages");if(!Array.isArray(r))return{platform:"pi",status:"n/a"};let o=r.find((a)=>uo(typeof a==="string"?a:b(a,"source")));if(o===void 0)return{platform:"pi",status:"n/a"};let i=b(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 Mf={amp:Js,"antigravity-cli":Ys,"claude-code":ea,codex:ta,"copilot-cli":pa,cursor:ba,"gemini-cli":wa,"grok-build":Ta,"hermes-agent":Ba,"kimi-code":Ft,openclaw:rl,opencode:yl,pi:Ll};function dt(e,t){let n={...t,cwd:e,homeDir:t?.homeDir??Hf()};return Xt.map((r)=>jf(Mf[r](n)))}function jf(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 Uf}from"node:os";import{join as Gf}from"node:path";var Bf=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}]),qf=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([])})})}),Vf={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 vl(){let e=Gf(Uf(),"cc-safety-net-self-test"),t=Bf.map((n)=>{let r=Yt(Qe("self-test",{command:n.command},{kind:"command",shell:"auto"},{configCwd:e,executionCwd:e},n.command),{guard:{dependencies:{loadPolicySnapshot:()=>qf,getModes:()=>Vf,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 po(e){let t=_({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},e);if(le(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function bl(e={}){let t=await Tt(!e.json,()=>{let n=zf(e);return{ready:n,finish:()=>n}},()=>Pt(),{loadingMessage:"Checking system status…"});if(e.json)console.log(JSON.stringify(t,null,2));else Kf(t);return t.engineSelfTest.failed>0||t.findings.some((n)=>n.severity==="error")?1:0}async function zf(e){let t=e.cwd??process.cwd(),n=await At(),r=dt(t,{ampPluginListOutput:n.ampPluginListOutput,codexPluginListOutput:n.codexPluginListOutput,copilotCliVersion:n.versions["copilot-cli"]}),o=vs(t),i=bs(),s=B({cwd:t}),a=s.policy,l=ue(a),c=Pe(a,l.capabilities),d=tn(7),p=e.skipUpdateCheck?{currentVersion:T(),latestVersion:null,updateAvailable:!1}:await be(),g={hooks:r,engineSelfTest:vl(),userConfig:o.userConfig,projectConfig:o.projectConfig,configState:xt(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(([,u])=>u.source==="rule_override"&&u.override==="off"&&u.inheritedEnabled&&u.changesInherited).map(([u])=>u),ruleCounts:{stored:Object.keys(a.destructiveCommandRuleOverrides).length,effective:Object.values(c).filter((u)=>u.changesInherited).length}},posture:Os(o.userConfig.path),activity:d,update:p,system:n};return{...g,findings:ks(g)}}function Kf(e){console.log(),console.log(Cs(e.hooks)),console.log(),console.log(Ss(e.engineSelfTest)),console.log(),console.log(Ds(e)),console.log(),console.log(Rs(e.environment)),console.log(),console.log(As(e)),console.log(),console.log(Es(e.findings)),console.log(),console.log(Ps(e.activity)),console.log(),console.log(Is(e.system)),console.log(),console.log(Ts(e.update)),console.log(_s(e))}import{existsSync as Wf}from"node:fs";var Jf=/^[A-Za-z0-9_@%+=:,./-]+$/,wl="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function fo(e){let t=_({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},e);if(le(t.errors))return console.error(wl),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!Wf(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)=>Jf.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!n)return console.error("Error: No command provided"),console.error(wl),null;return{json:t.flags.json,cwd:t.values.cwd,command:n}}function kl(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 xl(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 Cl(e,t=0){return`[${e.map((r,o)=>xs(r,o,t)).join(",")}]`}function An(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 Sl(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 go(e,t){let n=kl(t?.asciiOnly??!1),r=58,o=[],i=1;o.push(...xl(n,58)),o.push("");let s=e.trace.steps.find((u)=>u.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"?h.red("BLOCKED"):h.green("ALLOWED")}`),o.push(""),o.push("CONFIG");let u=e.configSource??"none";return o.push(` Path: ${u}`),o.join(`
188
- `)}let a=e.trace.steps.find((u)=>u.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 u=0;u<a.segments.length;u++){let m=a.segments[u];if(m){let f=Math.random();o.push(` Segment ${u+1}: ${Cl(m,f)}`)}}}let l=e.trace.segments,c=l.length>1;for(let u of l){if(c){o.push("");let v="";if(a&&a.type==="parse"){let Kn=a.segments[u.index];if(Kn)v=Kn.join(" ")}let x=54,y=v,C=` Segment ${u.index+1}: `,j=" ";if(v){if(C.length+v.length+j.length>x){let md=x-C.length-j.length;y=`${v.substring(0,md-1)}…`}}let ye=v?`${C}${y}${j}`:` Segment ${u.index+1} `,zn=v?`${C}${h.cyan(y)}${j}`:ye,Mo=58-ye.length,jo=Math.floor(Mo/2),fd=Mo-jo;o.push(`${n.sh.repeat(jo)}${zn}${n.sh.repeat(fd)}`)}if(u.steps.find((v)=>v.type==="segment-skipped")){o.push(""),o.push(" (skipped — prior segment blocked)");continue}let f=!1,L=!1;for(let v of u.steps){let x=Sl(v,i,n);if(x){if(L=!0,v.type==="recurse"){o.push("");let y=" RECURSING ",C=58-y.length-4;o.push(` ${n.tl}${n.h}${y}${n.h.repeat(C)}`),o.push(` ${n.v}`),f=!0;continue}for(let y of x.lines)if(f)o.push(` ${n.v} ${y}`);else o.push(y);if(x.incrementStep)i++}}if(f)o.push(` ${n.v}`),o.push(` ${n.bl}${n.h.repeat(56)}`),f=!1;if(!L)o.push(""),o.push(` ${h.green("✓")} Allowed (no matching rules)`)}if(o.push(""),o.push("RESULT"),e.result==="blocked"){if(o.push(` Status: ${h.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 u=An(e.reason," ");o.push(` Reason: ${u[0]}`);for(let m=1;m<u.length;m++)o.push(u[m]??"")}}else o.push(` Status: ${h.green("ALLOWED")}`);o.push(""),o.push("CONFIG");let d=e.configSource??"none",p=e.configValid?"":" (invalid)";o.push(` Path: ${d}${p}`),o.push(` Safety preset: ${e.selectedPreset??"standard"}`),o.push(` Effective capabilities: ${e.effectiveLevel}`);let g=Object.entries(e.destructiveCommandRuleOverrides??{});if(o.push(` Rule customizations: ${g.length}`),e.ruleActivation)o.push(` Rule activation: ${e.ruleActivation.id} — ${e.ruleActivation.enabled?"on":"off"} via ${e.ruleActivation.source}`);return o.join(`
189
- `)}function ho(e){return JSON.stringify(e,null,2)}function Dl(e){return new Promise((t)=>{process.stdout.write(`${e}
190
- `,()=>t())})}async function Rl(e){let t=fo(e);if(!t)return 1;try{let n=et(t.command,{cwd:t.cwd}),r=!!process.env.NO_COLOR||!process.stdout.isTTY;return await Dl(t.json?ho(n):go(n,{asciiOnly:r})),0}catch(n){if(!(n instanceof yr)&&!(n instanceof Ee)&&!(n instanceof fe))throw n;if(t.json)return await Dl(JSON.stringify({error:n.message})),1;return console.error(n.message),1}}var Al="2.2.2",J=" ",Fe="cc-safety-net";function El(e){return e.argument?`${e.flags} ${e.argument}`:e.flags}function Yf(e){return Math.max(...e.map((t)=>El(t).length))}function Zf(e){return Math.max(...e.map((t)=>t.usage.length))}function Xf(e){return Math.max(...e.map((t)=>`${Fe} ${t.usage}`.length))}function Qf(e,t){let n=`${Fe} ${e.usage}`;return`${J}${n.padEnd(t+2)}${e.description}`}function he(e,t){return`${J}${e.padEnd(Math.max(40,e.length+2))}${t}`}function En(e,t=console.log){let n=[];if(n.push(`${Fe} ${e.name}`),n.push(""),n.push(`${J}${e.description}`),n.push(""),n.push("USAGE:"),n.push(`${J}${Fe} ${e.usage}`),n.push(""),e.subcommands&&e.subcommands.length>0){n.push("SUBCOMMANDS:");let r=Zf(e.subcommands);for(let o of e.subcommands)n.push(`${J}${o.usage.padEnd(r+2)}${o.description}`);n.push("")}if(e.options.length>0){n.push("OPTIONS:");let r=Yf(e.options);for(let o of e.options){let i=El(o),s=o.default?`${o.description} (default: ${o.default})`:o.description;n.push(`${J}${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(`${J}${r}`)}t(n.join(`
191
- `))}function yo(){let e=Xf(Qt),t=[];t.push(`${Fe} v${Al}`),t.push(""),t.push("Blocks destructive commands and secret access."),t.push(""),t.push("COMMANDS:");for(let n of Qt)t.push(Qf(n,e));t.push(""),t.push("GLOBAL OPTIONS:"),t.push(`${J}-h, --help Show help (use with command for command-specific help)`),t.push(`${J}-V, --version Show version`),t.push(""),t.push("HELP:"),t.push(`${J}${Fe} help <command> Show help for a specific command`),t.push(`${J}${Fe} <command> --help Show help for a specific command`),t.push(""),t.push("ENVIRONMENT VARIABLES:"),t.push(he(`${S.level.name}=standard|strict|paranoid`,"Set session safety level")),t.push(he(`${S.worktree.name}=1`,"Allow local git discards in linked worktrees")),t.push(he(`${S.debug.name}=1`,"Print diagnostic messages to stderr")),t.push(he(`${S.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),t.push(he("CC_SAFETY_NET_HOME","Override rule config home directory")),t.push(""),t.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),t.push(he(`${S.strict.name}=1`,"Force safety.overrides.fail_closed on")),t.push(he(`${S.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),t.push(he(`${S.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),t.push(he(`${S.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),t.push(""),t.push("Documentation: https://ccsafetynet.com/docs"),console.log(t.join(`
192
- `))}function Pl(){console.log(Al)}function jt(e,t=console.log){let n=en(e);if(!n)return!1;if(n.name.toLowerCase()!==e.toLowerCase())return!1;return En(n,t),!0}import{existsSync as Eo,readFileSync as kc}from"node:fs";import{homedir as Ym,tmpdir as Zm}from"node:os";import{join as Ro}from"node:path";import*as ke from"node:readline";function em(e){return e==="install"?"Install":"Uninstall"}function tm(e){return e==="install"?"Installing":"Uninstalling"}function nm(e){return e==="install"?"into":"from"}function _l(e){return e?.available===!0}function rm(e,t){let n=new Set(t);return e.filter((r)=>n.has(r.target)).map((r)=>r.target)}function Tl(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)=>_l(e[r]))}function om(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 im(e){return{cursor:e.findIndex((t)=>t.available),selected:[]}}function sm(e,t,n){if(n==="confirm"||n==="update"||n==="abort"||n==="interrupt")return{state:e,done:n};if(n==="up")return{state:{...e,cursor:Tl(t,e.cursor,-1)}};if(n==="down")return{state:{...e,cursor:Tl(t,e.cursor,1)}};let r=t[e.cursor];if(!_l(r))return{state:e};let o=e.selected.includes(r.target)?e.selected.filter((i)=>i!==r.target):rm(t,[...e.selected,r.target]);return{state:{...e,selected:o}}}var Ol="◉",$l="◯",Nl=">",Fl=" ";function am(e,t,n,r={}){let o=r.color!==!1,i=o?h.dim:(l)=>l,s=o?h.green:(l)=>l,a=o?h.bold:(l)=>l;return["",`${em(e)} CC Safety Net ${nm(e)}:`,"",...t.map((l,c)=>{let d=n.selected.includes(l.target),p=c===n.cursor,g=d?Ol:$l,u=p?Nl:Fl,m=l.available?"":` (${l.unavailableReason??"not installed"})`,f=`${g} ${l.label}${m}`,L=!l.available?i(f):d?s(f):p?a(f):f;return`${u} ${L}`}),"",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(`
193
- `)}var Il=["global-hook","plugin"];function lm(e,t,n={}){let r=n.color!==!1?h.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?Ol:$l} ${i}`;return`${a?Nl:Fl} ${a?r(l):l}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
194
- `)}function Hl(e){let{input:t,output:n}=e;ke.emitKeypressEvents(t);let r=t.isRaw===!0;t.setRawMode(!0),t.resume();let o=0,i=()=>{if(o===0)return;ke.moveCursor(n,0,-o),ke.cursorTo(n,0),ke.clearScreenDown(n)},s=()=>{i();let a=e.render();n.write(`${a}
179
+ `}function Xt(e){return[{name:"__init__.py",content:Sm(e)},{name:"plugin.yaml",content:Cm(e)}]}import{mkdirSync as Rm,readdirSync as Dm,readFileSync as Pm,rmSync as bo}from"node:fs";import{join as We}from"node:path";var Am="__pycache__";function Lo(e){let t=process.env.HERMES_HOME?.trim();return t?t:We(e,".hermes")}function wo(e){return We(Lo(e),"plugins",Q)}function ko(e){return e.startsWith(Dl)}function xo(e,t){let n=wo(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 Al(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=Pm(e,"utf-8");if(!ko(r))throw Error(`Refusing to ${t} unmanaged file at ${e}. Move or remove it.`);return r}function El(e){let t=xo(e,"install"),n=Xt(I());if(n.map((o)=>Al(We(t,o.name),"overwrite")).every((o,i)=>o===n[i]?.content))return{path:t,alreadyInstalled:!0};return Rm(t,{recursive:!0}),n.forEach((o)=>{O(We(t,o.name),o.content)}),{path:t,alreadyInstalled:!1}}function Co(e){let t=xo(e,"remove");if(!_(t))return[];return Xt(I()).filter((n)=>Al(We(t,n.name),"remove")!==void 0)}function _l(e){let t=xo(e,"remove");if(!_(t))return{path:t,alreadyInstalled:!1};let n=Co(e);if(n.forEach((r)=>{bo(We(t,r.name))}),bo(We(t,Am),{recursive:!0,force:!0}),Dm(t).length===0)bo(t,{recursive:!0});return{path:t,alreadyInstalled:n.length>0}}var Vn="hermes-agent",Tl=/^([^\s#][^:]*):/,Em=/^\s+([A-Za-z_][\w-]*):/,Il=/^\s+-\s*(.*)$/;function _m(e){return e.trim().replace(/^(["'])(.*)\1$/,"$2")}function Tm(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>Tl.exec(i)?.[1]?.trim()==="plugins");if(n===-1)return[];let r=t.slice(n+1),o=r.findIndex((i)=>Tl.test(i));return o===-1?r:r.slice(0,o)}function $l(e,t){let n=Tm(e),r=n.findIndex((s)=>Em.exec(s)?.[1]===t);if(r===-1)return[];let o=n.slice(r+1),i=o.findIndex((s)=>!Il.test(s));return(i===-1?o:o.slice(0,i)).map((s)=>_m(Il.exec(s)?.[1]??""))}function Im(e){try{return Ol(Fl(Lo(e),"config.yaml"),"utf-8")}catch{return}}function So(e){let t=Im(e)??"";return $l(t,"enabled").includes(Q)&&!$l(t,"disabled").includes(Q)}function jl(e){return/^# version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function $m(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=Ol(e,"utf-8");if(!ko(r))return{error:`Unmanaged ${t.name} occupies ${e}; move or remove it`};if(jl(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 Nl(e){let t=wo(e.homeDir),n=In(Vn,t);if(n)return n;let r=Xt(I()).map((a)=>$m(Fl(t,a.name),a)),o=r.flatMap((a)=>("error"in a)?[a.error]:[]);if(o.length>0)return{platform:Vn,status:"n/a",configPath:t,errors:o};let i=r.some((a)=>("content"in a)&&jl(a.content)!==I()),s=i?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!So(e.homeDir))return{platform:Vn,status:"disabled",method:"plugin directory",configPath:t,errors:[`${Q} is not enabled in Hermes; run \`hermes plugins enable ${Q}\``,...s]};return{platform:Vn,status:"configured",method:"plugin directory",configPath:t,errors:i?s:void 0}}import{existsSync as Om,readFileSync as Fm}from"node:fs";import{join as Hl}from"node:path";var jm=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function Nm(e){return Hl(process.env.KIMI_CODE_HOME||Hl(e,".kimi-code"),"config.toml")}function Qt(e){let t=Nm(e.homeDir);if(!Om(t))return{platform:"kimi-code",status:"n/a",configPath:t};try{if(!jm.test(Fm(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 Wl}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 zn="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as Um,lstatSync as Gm,readdirSync as Bm,readFileSync as qm}from"node:fs";import{dirname as Gl,join as Ie}from"node:path";import{fileURLToPath as Vm}from"node:url";import{spawn as Hm}from"node:child_process";function Mm(e){return e.join(" ")}function Ro(e,t,n){return[`Failed to run ${Mm(e)}${t===null?"":` (exit ${t})`}.`,n.trim()].filter(Boolean).join(`
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=Hm(o.cmd,o.args,{stdio:["ignore","pipe","pipe"]}),s=Do(i),a=()=>[s.stdout,s.stderr].filter(Boolean).join(`
181
+ `),l=t?.timeoutMs??120000,c=setTimeout(()=>{i.kill(),r(Error(Ro(e,null,`Timed out after ${l}ms.
182
+ ${a()}`.trim())))},l);i.on("error",(d)=>{clearTimeout(c),r(Error(Ro(e,null,`${d.message}
183
+ ${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(Ro(e,d,a())));return}n(t?.stdoutOnly?s.stdout:a())})})}async function Po(e){for(let t of e)await ue(t)}async function Ml(e){for(let t of e)try{await ue(t)}catch(n){console.warn(n instanceof Error?n.message:String(n))}}var Ul=Ie("openclaw",A),zm=[ee,gt,ht];function Ao(e,t){if(e==="~")return t;if(e.startsWith("~/")||e.startsWith("~\\"))return Ie(t,e.slice(2));return e}function Bl(e){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return Ao(t,e);let n=process.env.OPENCLAW_CONFIG_PATH?.trim();return n?Gl(Ao(n,e)):Ie(e,".openclaw")}function ql(e){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?Ao(t,e):Ie(Bl(e),"openclaw.json")}function Eo(e){return Ie(Bl(e),"extensions",A)}function Km(e){let t=Bm(e);if(t.length===0)return!0;if(t.some((o)=>!zm.includes(o)))return!1;let n=Ie(e,ee),r=_(n);return r!==void 0&&!r.isSymbolicLink()&&r.isFile()&&qm(n,"utf-8").startsWith(zn)}function _o(e){let t=Eo(e),n=_(t);if(!n)return;if(!n.isSymbolicLink()&&n.isDirectory()&&Km(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 Vl(){let e=Gl(Vm(import.meta.url));return[Ie(e,"..",Ul),Ie(e,"..","..","..","dist",Ul)]}function To(e=Vl()){return e.find((t)=>Um(t)&&Gm(t).isDirectory())}function Jm(e=Vl()){let t=To(e);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function zl(e=Jm()){return[["openclaw","plugins","install",e,"--force"],["openclaw","plugins","enable",A]]}function Wm(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 Kl(){let e=Wm(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 Kn="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:Wl(n,"utf-8")}}catch(o){return{error:`Failed to read ${n}: ${o instanceof Error?o.message:String(o)}`}}}function Yl(e){try{return JSON.parse(K(e))}catch{return}}function Ym(e){let t=yt(e,gt);if("error"in t)return t.error;if(k(Yl(t.content),"id")===A)return;return`${tn(e,gt)} is not a valid ${A} manifest; run install --openclaw`}function Zm(e){let t=yt(e,ht);if("error"in t)return t.error;let n=k(k(Yl(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 Jl(e){return Array.isArray(e)?e.filter((t)=>typeof t==="string"):[]}function Xm(e){let t=ql(e);if(!_(t))return`${A} is not enabled; ${en}`;let n=(()=>{try{return JSON.parse(K(Wl(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(Jl(k(r,"deny")).includes(A)||o===!1)return`${A} is disabled in ${t}; ${en}`;let i=Jl(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 Zl(e){return/^\/\/ version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function Qm(e,t,n){if(n===void 0)return[];let r=yt(n,ee);if("error"in r||Zl(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 Xl(e){let t=Eo(e.homeDir),n=In(Kn,t);if(n)return n;let r=yt(t,ee),i=["error"in r?r.error:r.content.startsWith(zn)?void 0:`Unmanaged ${ee} occupies ${tn(t,ee)}; move or remove it`,Ym(t),Zm(t)].filter((d)=>d!==void 0),s="content"in r?Zl(r.content):void 0,a=i.length>0?i:Qm(t,s,To());if(a.length>0)return{platform:Kn,status:"n/a",configPath:t,errors:a};let l=s===I()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],c=Xm(e.homeDir);if(c)return{platform:Kn,status:"disabled",method:"plugin directory",configPath:t,errors:[c,...l]};return{platform:Kn,status:"configured",method:"plugin directory",configPath:t,errors:l.length>0?l:void 0}}import{existsSync as dg,readFileSync as ug}from"node:fs";import{join as pg}from"node:path";import{existsSync as Io,readFileSync as rc,rmSync as tg}from"node:fs";import{join as ke}from"node:path";import{pathToFileURL as ng}from"node:url";function Ql(e){return e!==void 0&&/\s/.test(e)}function eg(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 Jn(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=eg(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 ec(e,t){let n=e.lastIndexOf(`
184
+ `,t)+1;return/^[ \t]*/.exec(e.slice(n))?.[0]??""}function Wn(e,t){let{start:n,end:r,end:o}=t;while(Ql(e[o]))o++;if(e[o]===","){if(r=o+1,e[r]===`
185
+ `)r++;return`${e.slice(0,n)}${e.slice(r)}`}o=t.start-1;while(Ql(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 Yn="cc-safety-net",oc=`${Yn}@latest`,ic=["opencode.json","opencode.jsonc"],tc="CCSafetyNetPlugin";function Zn(e){return ke(process.env.XDG_CONFIG_HOME||ke(e,".config"),"opencode")}function rg(e){return ke(Zn(e),ic[0])}function og(e){return ic.map((t)=>ke(Zn(e),t))}function sc(e){return ke(process.env.XDG_CACHE_HOME||ke(e,".cache"),"opencode","packages",oc)}function $o(e){tg(sc(e),{recursive:!0,force:!0})}async function ac(e){let t=ke(sc(e),"node_modules",Yn),n=ke(t,"package.json");if(!Io(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 ${oc}\` for details.`);let r=k(JSON.parse(rc(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(ng(o).href))[tc]==="function")return;throw Error(`The cached OpenCode plugin at ${o} does not export a callable ${tc}, so OpenCode would load nothing and fail open.`)}function Xn(e,t){if(e[t]==="/"&&e[t+1]==="/"){let n=e.indexOf(`
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 nc(e,t){let n=t;while(n<e.length){if(/\s/.test(e[n]??"")){n++;continue}let r=Xn(e,n);if(r===n)return n;n=r}return n}function lc(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 cc(e,t,n){return JSON.parse(e.slice(t,n))}function ig(e,t){return Jn(e,t,{skipComment:Xn,stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"})}function sg(e){let t=0,n=0;while(n<e.length){let r=Xn(e,n);if(r!==n){n=r;continue}if(e[n]==='"'){let o=lc(e,n);if(t===1&&cc(e,n,o)==="plugin"){let i=nc(e,o),s=nc(e,i+1);if(e[i]===":"&&e[s]==="[")return{start:s,end:ig(e,s)}}n=o;continue}if(e[n]==="{"||e[n]==="[")t++;if(e[n]==="}"||e[n]==="]")t--;n++}return}function ag(e,t){let n=[],r=t.start+1;while(r<t.end){let o=Xn(e,r);if(o!==r){r=o;continue}if(e[r]==='"'){let i=lc(e,r),s=cc(e,r,i);if(typeof s==="string"&&s.includes(Yn))n.push({start:r,end:i});r=i;continue}r++}return n}function dc(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 lg(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(Yn))}function cg(e,t){let n=sg(e);if(!n)throw Error(`Failed to locate OpenCode plugin array in ${t}`);let r=[...ag(e,n)].reverse().reduce(Wn,e);return dc(r,t),r}function uc(e){$o(e);let t=og(e),n=t.find((o)=>Io(o)),r=[];for(let o of t){if(!Io(o))continue;try{let i=rc(o,"utf-8");if(!lg(dc(i,o)))continue;return O(o,cg(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(`
188
+ `));return{path:n??rg(e),alreadyInstalled:!1}}function pc(e){let t=[],n=Zn(e.homeDir),r=["opencode.json","opencode.jsonc"];for(let o of r){let i=pg(n,o);if(dg(i))try{let s=ug(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 fg}from"node:path";function Oo(e){return fg(e,".pi","agent","settings.json")}function Fo(e){if(typeof e!=="string")return!1;return e==="npm:cc-safety-net"||e.startsWith("npm:cc-safety-net@")}function fc(e){let t=Oo(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)=>Fo(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 gg={amp:qa,"antigravity-cli":Va,"claude-code":Wa,codex:Ya,"copilot-cli":al,cursor:gl,"gemini-cli":hl,"grok-build":Rl,"hermes-agent":Nl,"kimi-code":Qt,openclaw:Xl,opencode:pc,pi:fc};function vt(e,t){let n={...t,cwd:e,homeDir:t?.homeDir??mg()};return wn.map((r)=>hg(gg[r](n)))}function hg(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 yg}from"node:os";import{join as vg}from"node:path";var bg=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}]),Lg=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([])})})}),wg={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 mc(){let e=vg(yg(),"cc-safety-net-self-test"),t=bg.map((n)=>{let r=bn(st("self-test",{command:n.command},{kind:"command",shell:"auto"},{configCwd:e,executionCwd:e},n.command),{guard:{dependencies:{loadPolicySnapshot:()=>Lg,getModes:()=>wg,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 jo(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 gc(e={}){let t=await Kt(!e.json,()=>{let n=kg(e);return{ready:n,finish:()=>n}},()=>zt(),{loadingMessage:"Checking system status…"});if(e.json)console.log(JSON.stringify(t,null,2));else xg(t);return t.engineSelfTest.failed>0||t.findings.some((n)=>n.severity==="error")?1:0}async function kg(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=aa(t),i=la(),s=z({cwd:t}),a=s.policy,l=ye(a),c=Ue(a,l.capabilities),d=Sn(7),m=Ha(t),g=e.skipUpdateCheck?{currentVersion:I(),latestVersion:null,updateAvailable:!1}:await Te(),u={hooks:r,engineSelfTest:mc(),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:ka(o.userConfig.path),activity:d,update:g,system:n};return{...u,findings:da(u)}}function xg(e){console.log(),console.log(pa(e.hooks)),console.log(),console.log(fa(e.engineSelfTest)),console.log(),console.log(ma(e)),console.log(),console.log(ga(e.environment)),console.log(),console.log(ha(e)),console.log(),console.log(ya(e.findings)),console.log(),console.log(va(e.activity)),console.log(),console.log(La(e.system)),console.log(),console.log(ba(e.update)),console.log(wa(e))}import{existsSync as Cg}from"node:fs";var Sg=/^[A-Za-z0-9_@%+=:,./-]+$/,hc="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function No(e){let t=E({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},e);if(fe(t.errors))return console.error(hc),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!Cg(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)=>Sg.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!n)return console.error("Error: No command provided"),console.error(hc),null;return{json:t.flags.json,cwd:t.values.cwd,command:n}}function yc(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 vc(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 Ho(e){return JSON.stringify(e)}function bc(e,t=0){return`[${e.map((r,o)=>ua(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 Lc(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: ${Ho(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: ${Ho(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: ${Ho(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 Mo(e,t){let n=yc(t?.asciiOnly??!1),r=58,o=[],i=1;o.push(...vc(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
+ `)}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}: ${bc(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 fr=a.segments[p.index];if(fr)h=fr.join(" ")}let R=54,v=h,D=` Segment ${p.index+1}: `,ne=" ";if(h){if(D.length+h.length+ne.length>R){let yu=R-D.length-ne.length;v=`${h.substring(0,yu-1)}…`}}let un=h?`${D}${v}${ne}`:` Segment ${p.index+1} `,gu=h?`${D}${y.cyan(v)}${ne}`:un,ui=58-un.length,pi=Math.floor(ui/2),hu=ui-pi;o.push(`${n.sh.repeat(pi)}${gu}${n.sh.repeat(hu)}`)}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=Lc(h,i,n);if(R){if(L=!0,h.type==="recurse"){o.push("");let v=" RECURSING ",D=58-v.length-4;o.push(` ${n.tl}${n.h}${v}${n.h.repeat(D)}`),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?` (${Rn(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
+ `)}function Uo(e){return JSON.stringify(e,null,2)}function wc(e){return new Promise((t)=>{process.stdout.write(`${e}
191
+ `,()=>t())})}async function kc(e){let t=No(e);if(!t)return 1;try{let n=at(t.command,{cwd:t.cwd}),r=!!process.env.NO_COLOR||!process.stdout.isTTY;return await wc(t.json?Uo(n):Mo(n,{asciiOnly:r})),0}catch(n){if(!(n instanceof Ur)&&!(n instanceof Me)&&!(n instanceof Le))throw n;if(t.json)return await wc(JSON.stringify({error:n.message})),1;return console.error(n.message),1}}var xc="2.3.1",te=" ",Ye="cc-safety-net";function Cc(e){return e.argument?`${e.flags} ${e.argument}`:e.flags}function Rg(e){return Math.max(...e.map((t)=>Cc(t).length))}function Dg(e){return Math.max(...e.map((t)=>t.usage.length))}function Pg(e){return Math.max(...e.map((t)=>`${Ye} ${t.usage}`.length))}function Ag(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=Dg(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=Rg(e.options);for(let o of e.options){let i=Cc(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(`
192
+ `))}function Go(){let e=Pg(xn),t=[];t.push(`${Ye} v${xc}`),t.push(""),t.push("Blocks destructive commands and secret access."),t.push(""),t.push("COMMANDS:");for(let n of xn)t.push(Ag(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(`
193
+ `))}function Sc(){console.log(xc)}function rn(e,t=console.log){let n=Cn(e);if(!n)return!1;if(n.name.toLowerCase()!==e.toLowerCase())return!1;return bt(n,t),!0}import{existsSync as ei,readFileSync as yd}from"node:fs";import{homedir as Rh,tmpdir as Dh}from"node:os";import{join as Xo}from"node:path";import*as $e from"node:readline";function Eg(e){return e==="install"?"Install":"Uninstall"}function _g(e){return e==="install"?"Installing":"Uninstalling"}function Tg(e){return e==="install"?"into":"from"}function Pc(e){return e?.available===!0}function Ig(e,t){let n=new Set(t);return e.filter((r)=>n.has(r.target)).map((r)=>r.target)}function Rc(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)=>Pc(e[r]))}function $g(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 Og(e){return{cursor:e.findIndex((t)=>t.available),selected:[]}}function Fg(e,t,n){if(n==="confirm"||n==="update"||n==="abort"||n==="interrupt")return{state:e,done:n};if(n==="up")return{state:{...e,cursor:Rc(t,e.cursor,-1)}};if(n==="down")return{state:{...e,cursor:Rc(t,e.cursor,1)}};let r=t[e.cursor];if(!Pc(r))return{state:e};let o=e.selected.includes(r.target)?e.selected.filter((i)=>i!==r.target):Ig(t,[...e.selected,r.target]);return{state:{...e,selected:o}}}var Ac="◉",Ec="◯",_c=">",Tc=" ";function jg(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["",`${Eg(e)} CC Safety Net ${Tg(e)}:`,"",...t.map((l,c)=>{let d=n.selected.includes(l.target),m=c===n.cursor,g=d?Ac:Ec,u=m?_c:Tc,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(`
194
+ `)}var Dc=["global-hook","plugin"];function Ng(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?Ac:Ec} ${i}`;return`${a?_c:Tc} ${a?r(l):l}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
195
+ `)}function Ic(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}
195
196
  `),o=a.split(`
196
- `).length};return new Promise((a)=>{let l=(d)=>{t.off("keypress",c),t.setRawMode(r),t.pause(),i(),a(d)};function c(d,p){e.onKey(d,p,{finish:l,draw:s})}t.on("keypress",c),s()})}function Ml(e={}){let t=0;return Hl({input:e.input??process.stdin,output:e.output??process.stdout,render:()=>lm(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(Il[t]);if(r.name==="up"||r.name==="down"||n==="k"||n==="j")t=(t+1)%Il.length,o.draw()}})}function Lo(e=process.stdin,t=process.stdout){return Boolean(e.isTTY&&t.isTTY&&typeof e.setRawMode==="function")}function jl(e,t,n={}){let r=n.output??process.stdout,o=im(t);return Hl({input:n.input??process.stdin,output:r,render:()=>am(e,t,o),onKey:(i,s,a)=>{let l=om(e,i,s);if(!l)return;let c=sm(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(`${tm(e)} selected integrations...
197
- `);return}a.draw()}})}import{existsSync as Gl,lstatSync as dm,mkdirSync as um,mkdtempSync as pm,readdirSync as fm,readFileSync as pt,rmSync as In}from"node:fs";import{tmpdir as mm}from"node:os";import{basename as gm,dirname as hm,join as U}from"node:path";import{fileURLToPath as ym}from"node:url";var vo="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",He="cc-safety-net",Me="cc-safety-net/index.ts";import{spawn as cm}from"node:child_process";var bo=(e,t)=>{let n=_e([...e],process.env);return new Promise((r)=>{let o=cm(n.cmd,n.args,{cwd:t,stdio:["ignore","pipe","pipe"]}),i=to(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(`
198
- `)})}),o.on("close",(l)=>{clearTimeout(a),r({status:s?null:l,errorCode:s?"ETIMEDOUT":void 0,stdout:i.stdout,stderr:i.stderr})})})};var ut="cc-safety-net.ts",Ul=U("amp",Me);function Lm(e){return U(e,".config","amp","plugins","cc-safety-net.ts")}function vm(){let e=hm(ym(import.meta.url));return[U(e,"..",Ul),U(e,"..","..","..","dist",Ul)]}function bm(e=vm()){let t=e.find((n)=>Gl(n)&&dm(n).isFile());if(!t)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return t}function Bl(e){try{return JSON.parse(e)}catch{return}}function _n(e){return e.subarray(0,Buffer.byteLength(vo)).toString("utf-8")===vo}async function Ut(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(`
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 $c(e={}){let t=0;return Ic({input:e.input??process.stdin,output:e.output??process.stdout,render:()=>Ng(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(Dc[t]);if(r.name==="up"||r.name==="down"||n==="k"||n==="j")t=(t+1)%Dc.length,o.draw()}})}function Bo(e=process.stdin,t=process.stdout){return Boolean(e.isTTY&&t.isTTY&&typeof e.setRawMode==="function")}function Oc(e,t,n={}){let r=n.output??process.stdout,o=Og(t);return Ic({input:n.input??process.stdin,output:r,render:()=>jg(e,t,o),onKey:(i,s,a)=>{let l=$g(e,i,s);if(!l)return;let c=Fg(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(`${_g(e)} selected integrations...
198
+ `);return}a.draw()}})}import{existsSync as jc,lstatSync as Mg,mkdirSync as Ug,mkdtempSync as Gg,readdirSync as Bg,readFileSync as wt,rmSync as er}from"node:fs";import{tmpdir as qg}from"node:os";import{basename as Vg,dirname as zg,join as G}from"node:path";import{fileURLToPath as Kg}from"node:url";var qo="// 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 Hg}from"node:child_process";var Vo=(e,t)=>{let n=ze([...e],process.env);return new Promise((r)=>{let o=Hg(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(`
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",Fc=G("amp",Xe);function Jg(e){return G(e,".config","amp","plugins","cc-safety-net.ts")}function Wg(){let e=zg(Kg(import.meta.url));return[G(e,"..",Fc),G(e,"..","..","..","dist",Fc)]}function Yg(e=Wg()){let t=e.find((n)=>jc(n)&&Mg(n).isFile());if(!t)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return t}function Nc(e){try{return JSON.parse(e)}catch{return}}function tr(e){return e.subarray(0,Buffer.byteLength(qo)).toString("utf-8")===qo}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(`
199
200
  `).trim()].filter(Boolean).join(`
200
- `))}async function ql(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.`}
201
+ `))}async function Hc(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.`}
201
202
  ${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.
202
203
  ${[t.stdout,t.stderr].filter(Boolean).join(`
203
- `)}`.trim());let n=Bl(t.stdout),r=(Array.isArray(n)?n:[]).filter((o)=>b(o,"scope")==="user"&&b(o,"exists")===!0&&b(o,"viewerCanWrite")===!0).map((o)=>b(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 Vl(e,t){let n=pm(U(mm(),"cc-safety-net-amp-"));try{return await Ut(e,["amp","clone","user-plugins",n]),await t(n)}finally{In(n,{recursive:!0,force:!0})}}function wo(e){return`rerun ${e==="overwrite"?"install":"uninstall"} --amp`}function zl(e,t,n){let r=U(e,t),o=E(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 ${wo(n)}.`);let i=pt(r);if(_n(i))return i;throw Error(`Refusing to ${n} unmanaged file ${t} in your Amp personal plugins repository. Remove it there and ${wo(n)}.`)}function Kl(e,t){let n=U(e,He),r=E(n);if(!r)return;if(r.isSymbolicLink()||!r.isDirectory())throw Error(`Refusing to ${t} ${He} in your Amp personal plugins repository: not a regular directory. Remove it there and ${wo(t)}.`);return zl(e,Me,t)}function wm(e){let t=U(e,ut),n=E(t);if(!n||n.isSymbolicLink()||!n.isFile())return;let r=pt(t);return _n(r)?r:void 0}async function Wl(e,t,n,r){if(await Ut(e,n,t),(await Ut(e,["git","status","--porcelain"],t)).stdout.trim()==="")return!1;return await Ut(e,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",r],t),await Ut(e,["git","push","origin","HEAD"],t),!0}function Pn(e,t){km(e,t),xm(e,t)}function Jl(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 km(e,t){let n=Lm(e),r=E(n);if(!r)return;if(!r.isSymbolicLink()&&r.isFile()&&_n(pt(n))){In(n);return}Jl(n,t)}function xm(e,t){let n=U(e,".config","amp","plugins",He),r=E(n);if(!r)return;if(!r.isSymbolicLink()&&r.isDirectory()&&Cm(n)){In(n,{recursive:!0});return}Jl(n,t)}function Cm(e){let t=gm(Me);if(fm(e).join("\x00")!==t)return!1;let n=U(e,t),r=E(n);return!!r&&!r.isSymbolicLink()&&r.isFile()&&_n(pt(n))}function Sm(){let e=kt();if(!Gl(e))return"";let t=Bl(pt(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(Tn(t))};
204
- `}async function Yl(e,t=bm(),n=bo){let r=Buffer.concat([pt(t),Buffer.from(Sm(),"utf-8")]),o=await ql(n);return Vl(n,async(i)=>{let s=`${o}/${He}`,a=Kl(i,"overwrite"),l=zl(i,ut,"overwrite");if(a?.equals(r)&&!l)return Pn(e,"fail"),{path:s,alreadyInstalled:!0};if(um(U(i,He),{recursive:!0}),I(U(i,Me),r),l)In(U(i,ut));let c=await Wl(n,i,["git","add","--",Me,...l?[ut]:[]],`chore: update cc-safety-net plugin to v${T()}`);return Pn(e,"fail"),{path:s,alreadyInstalled:!c}})}async function Zl(e,t=bo){let n=await ql(t);return Vl(t,async(r)=>{let o=Kl(r,"remove"),i=wm(r),s=`${n}/${i&&!o?ut:He}`;if(!o&&!i)return Pn(e,"keep"),{path:s,alreadyInstalled:!1};return await Wl(t,r,["git","rm","--",...o?[Me]:[],...i?[ut]:[]],`chore: remove cc-safety-net plugin v${T()}`),Pn(e,"keep"),{path:s,alreadyInstalled:!0}})}import{existsSync as Xl,mkdirSync as Dm,readFileSync as Rm}from"node:fs";import{dirname as Am}from"node:path";var ko="npx -y cc-safety-net hook --agy-cli",je="cc-safety-net";function Ue(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function $n(){return{PreToolUse:[{hooks:[{type:"command",command:ko,timeout:30}]}]}}function Ql(e){try{let t=JSON.parse(Rm(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 ec(e){let t=e[je];if(t===void 0){let r=$n();return e[je]=r,{definition:r,preToolUse:r.PreToolUse??[]}}if(!Ue(t))throw Error(`Antigravity hooks config entry "${je}" must be an object`);let n=Array.isArray(t.PreToolUse)?t.PreToolUse:[];return t.PreToolUse=n,{definition:t,preToolUse:n}}function tc(e){if(!Array.isArray(e.PreToolUse))return!1;return e.PreToolUse.some((t)=>Ue(t)&&Array.isArray(t.hooks)&&t.hooks.some((n)=>Ue(n)&&n.command===ko))}function Em(e){return Object.values(e).some((t)=>Ue(t)&&t.enabled!==!1&&tc(t))}function Pm(e){if(e[je]===void 0)return!1;let t=ec(e);if(t.definition.enabled!==!1||!tc(t.definition))return!1;return t.definition.enabled=!0,!0}function Tm(e){if(e[je]===void 0){e[je]=$n();return}let t=ec(e);t.definition.enabled=!0,t.preToolUse.push($n().PreToolUse?.[0]??{hooks:[]})}function Im(e){let t=!1;for(let n of Object.values(e)){if(!Ue(n)||!Array.isArray(n.PreToolUse))continue;n.PreToolUse=n.PreToolUse.flatMap((r)=>{if(!Ue(r)||!Array.isArray(r.hooks))return[r];let o=r.hooks.filter((i)=>!Ue(i)||i.command!==ko);if(o.length!==r.hooks.length)t=!0;return o.length===0?[]:[{...r,hooks:o}]})}return t}function On(e,t){I(e,`${JSON.stringify(t,null,2)}
205
- `)}function nc(e){let t=Dt(e);if(Dm(Am(t),{recursive:!0}),!Xl(t))return On(t,{[je]:$n()}),{path:t,alreadyInstalled:!1};let n=Ql(t);if(Em(n))return{path:t,alreadyInstalled:!0};if(Pm(n))return On(t,n),{path:t,alreadyInstalled:!1};return Tm(n),On(t,n),{path:t,alreadyInstalled:!1}}function rc(e){let t=Dt(e);if(!Xl(t))return{path:t,alreadyInstalled:!1};let n=Ql(t);if(!Im(n))return{path:t,alreadyInstalled:!1};return On(t,n),{path:t,alreadyInstalled:!0}}import{existsSync as _m,readdirSync as Om,rmSync as $m}from"node:fs";import{join as Nm}from"node:path";function oc(e,t=process.platform,n){if(!_m(e))return;let r=t==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);Om(e).filter((o)=>o!==n&&r.test(o)).forEach((o)=>{$m(Nm(e,o),{recursive:!0,force:!0})})}import{spawn as Fm}from"node:child_process";var ae=z.map((e)=>({target:e.id,flag:e.flag,label:R(e.id),probeCommand:e.probeCommand}));function xo(e){let t=new Set(e);return ae.map((n)=>n.target).filter((n)=>t.has(n))}async function ic(e,t){for(let n of e)await t(n)}var Hm=5000;function Co(e){return new Promise((t)=>{let n=_e([...e],process.env),r=Fm(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)},Hm);r.on("error",()=>i(!1)),r.on("close",(a)=>i(a===0))})}function sc(e=Co,t={}){let n=new Set(t.configuredTargets??[]);return Promise.all(ae.map(async(r)=>({target:r.target,flag:r.flag,label:r.label,...lc(t.action,await e(r.probeCommand),n.has(r.target))})))}function ac(e,t){let n=new Set(t.configuredTargets??[]);return e.map((r)=>({...r,...lc(t.action,r.available,n.has(r.target))}))}function lc(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 cc,readdirSync as Mm,rmSync as jm}from"node:fs";import{join as ft}from"node:path";function Nn(e,t=process.platform){let n=ft(process.env.npm_config_cache||(t==="win32"?ft(process.env.LOCALAPPDATA||ft(e,"AppData","Local"),"npm-cache"):ft(e,".npm")),"_npx");if(!cc(n))return;Mm(n).filter((r)=>cc(ft(n,r,"node_modules","cc-safety-net"))).forEach((r)=>{jm(ft(n,r),{recursive:!0,force:!0})})}import{existsSync as uc,mkdirSync as Um,readFileSync as pc}from"node:fs";import{dirname as Gm,join as dc}from"node:path";var Gt="npx -y cc-safety-net hook --kimi-code",So=`[[hooks]]
204
+ `)}`.trim());let n=Nc(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 Mc(e,t){let n=Gg(G(qg(),"cc-safety-net-amp-"));try{return await on(e,["amp","clone","user-plugins",n]),await t(n)}finally{er(n,{recursive:!0,force:!0})}}function zo(e){return`rerun ${e==="overwrite"?"install":"uninstall"} --amp`}function Uc(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 ${zo(n)}.`);let i=wt(r);if(tr(i))return i;throw Error(`Refusing to ${n} unmanaged file ${t} in your Amp personal plugins repository. Remove it there and ${zo(n)}.`)}function Gc(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 ${zo(t)}.`);return Uc(e,Xe,t)}function Zg(e){let t=G(e,Lt),n=_(t);if(!n||n.isSymbolicLink()||!n.isFile())return;let r=wt(t);return tr(r)?r:void 0}async function Bc(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 Qn(e,t){Xg(e,t),Qg(e,t)}function qc(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 Xg(e,t){let n=Jg(e),r=_(n);if(!r)return;if(!r.isSymbolicLink()&&r.isFile()&&tr(wt(n))){er(n);return}qc(n,t)}function Qg(e,t){let n=G(e,".config","amp","plugins",Ze),r=_(n);if(!r)return;if(!r.isSymbolicLink()&&r.isDirectory()&&eh(n)){er(n,{recursive:!0});return}qc(n,t)}function eh(e){let t=Vg(Xe);if(Bg(e).join("\x00")!==t)return!1;let n=G(e,t),r=_(n);return!!r&&!r.isSymbolicLink()&&r.isFile()&&tr(wt(n))}function th(){let e=ve();if(!jc(e))return"";let t=Nc(wt(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(Y(t))};
205
+ `}async function Vc(e,t=Yg(),n=Vo){let r=Buffer.concat([wt(t),Buffer.from(th(),"utf-8")]),o=await Hc(n);return Mc(n,async(i)=>{let s=`${o}/${Ze}`,a=Gc(i,"overwrite"),l=Uc(i,Lt,"overwrite");if(a?.equals(r)&&!l)return Qn(e,"fail"),{path:s,alreadyInstalled:!0};if(Ug(G(i,Ze),{recursive:!0}),O(G(i,Xe),r),l)er(G(i,Lt));let c=await Bc(n,i,["git","add","--",Xe,...l?[Lt]:[]],`chore: update cc-safety-net plugin to v${I()}`);return Qn(e,"fail"),{path:s,alreadyInstalled:!c}})}async function zc(e,t=Vo){let n=await Hc(t);return Mc(t,async(r)=>{let o=Gc(r,"remove"),i=Zg(r),s=`${n}/${i&&!o?Lt:Ze}`;if(!o&&!i)return Qn(e,"keep"),{path:s,alreadyInstalled:!1};return await Bc(t,r,["git","rm","--",...o?[Xe]:[],...i?[Lt]:[]],`chore: remove cc-safety-net plugin v${I()}`),Qn(e,"keep"),{path:s,alreadyInstalled:!0}})}import{existsSync as Kc,mkdirSync as nh,readFileSync as rh}from"node:fs";import{dirname as oh}from"node:path";var Ko="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 rr(){return{PreToolUse:[{hooks:[{type:"command",command:Ko,timeout:30}]}]}}function Jc(e){try{let t=JSON.parse(rh(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 Wc(e){let t=e[Qe];if(t===void 0){let r=rr();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 Yc(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===Ko))}function ih(e){return Object.values(e).some((t)=>et(t)&&t.enabled!==!1&&Yc(t))}function sh(e){if(e[Qe]===void 0)return!1;let t=Wc(e);if(t.definition.enabled!==!1||!Yc(t.definition))return!1;return t.definition.enabled=!0,!0}function ah(e){if(e[Qe]===void 0){e[Qe]=rr();return}let t=Wc(e);t.definition.enabled=!0,t.preToolUse.push(rr().PreToolUse?.[0]??{hooks:[]})}function lh(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!==Ko);if(o.length!==r.hooks.length)t=!0;return o.length===0?[]:[{...r,hooks:o}]})}return t}function nr(e,t){O(e,`${JSON.stringify(t,null,2)}
206
+ `)}function Zc(e){let t=Gt(e);if(nh(oh(t),{recursive:!0}),!Kc(t))return nr(t,{[Qe]:rr()}),{path:t,alreadyInstalled:!1};let n=Jc(t);if(ih(n))return{path:t,alreadyInstalled:!0};if(sh(n))return nr(t,n),{path:t,alreadyInstalled:!1};return ah(n),nr(t,n),{path:t,alreadyInstalled:!1}}function Xc(e){let t=Gt(e);if(!Kc(t))return{path:t,alreadyInstalled:!1};let n=Jc(t);if(!lh(n))return{path:t,alreadyInstalled:!1};return nr(t,n),{path:t,alreadyInstalled:!0}}import{existsSync as ch,readdirSync as dh,rmSync as uh}from"node:fs";import{join as ph}from"node:path";function Qc(e,t=process.platform,n){if(!ch(e))return;let r=t==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);dh(e).filter((o)=>o!==n&&r.test(o)).forEach((o)=>{uh(ph(e,o),{recursive:!0,force:!0})})}import{spawn as fh}from"node:child_process";var pe=X.map((e)=>({target:e.id,flag:e.flag,label:P(e.id),probeCommand:e.probeCommand}));function Jo(e){let t=new Set(e);return pe.map((n)=>n.target).filter((n)=>t.has(n))}async function ed(e,t){for(let n of e)await t(n)}var mh=5000;function Wo(e){return new Promise((t)=>{let n=ze([...e],process.env),r=fh(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)},mh);r.on("error",()=>i(!1)),r.on("close",(a)=>i(a===0))})}function td(e=Wo,t={}){let n=new Set(t.configuredTargets??[]);return Promise.all(pe.map(async(r)=>({target:r.target,flag:r.flag,label:r.label,...rd(t.action,await e(r.probeCommand),n.has(r.target))})))}function nd(e,t){let n=new Set(t.configuredTargets??[]);return e.map((r)=>({...r,...rd(t.action,r.available,n.has(r.target))}))}function rd(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 od,readdirSync as gh,rmSync as hh}from"node:fs";import{join as kt}from"node:path";function or(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(!od(n))return;gh(n).filter((r)=>od(kt(n,r,"node_modules","cc-safety-net"))).forEach((r)=>{hh(kt(n,r),{recursive:!0,force:!0})})}import{existsSync as sd,mkdirSync as yh,readFileSync as ad}from"node:fs";import{dirname as vh,join as id}from"node:path";var sn="npx -y cc-safety-net hook --kimi-code",Yo=`[[hooks]]
206
207
  event = "PreToolUse"
207
- command = "${Gt}"`,Do=`{ event = "PreToolUse", command = "${Gt}" }`;function fc(e){return dc(process.env.KIMI_CODE_HOME??dc(e,".kimi-code"),"config.toml")}function Bm(e){return e.split(`
208
+ command = "${sn}"`,Zo=`{ event = "PreToolUse", command = "${sn}" }`;function ld(e){return id(process.env.KIMI_CODE_HOME??id(e,".kimi-code"),"config.toml")}function bh(e){return e.split(`
208
209
  `).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(`
209
- `)}function qm(e,t){if(e[t]!=="#")return t;let n=e.indexOf(`
210
- `,t+1);return n===-1?e.length:n+1}function Vm(e,t){return xn(e,t,{skipComment:qm,stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"})}function mc(e){let t=!1,n=0;while(n<e.length){let r=e.indexOf(`
211
- `,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:Vm(e,a)}}}n=r===-1?e.length:r+1}return}function zm(e,t){let n=e.slice(0,t.end).trimEnd(),r=il(e,t.end),o=r===""?" ":`${r} `,i=!n.endsWith("[")&&!n.endsWith(",");return`${n}${i?",":""}
212
- ${o}${Do}${e.slice(t.end)}`}function Km(e){let t=mc(e);if(t&&e.slice(t.start+1,t.end).trim())return zm(e,t);let n=Bm(e).trimEnd();if(n==="")return`${So}
210
+ `)}function Lh(e,t){if(e[t]!=="#")return t;let n=e.indexOf(`
211
+ `,t+1);return n===-1?e.length:n+1}function wh(e,t){return Jn(e,t,{skipComment:Lh,stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"})}function cd(e){let t=!1,n=0;while(n<e.length){let r=e.indexOf(`
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:wh(e,a)}}}n=r===-1?e.length:r+1}return}function kh(e,t){let n=e.slice(0,t.end).trimEnd(),r=ec(e,t.end),o=r===""?" ":`${r} `,i=!n.endsWith("[")&&!n.endsWith(",");return`${n}${i?",":""}
213
+ ${o}${Zo}${e.slice(t.end)}`}function xh(e){let t=cd(e);if(t&&e.slice(t.start+1,t.end).trim())return kh(e,t);let n=bh(e).trimEnd();if(n==="")return`${Yo}
213
214
  `;return`${n}
214
215
 
215
- ${So}
216
- `}function Wm(e){return e.split(/(?=^\s*\[)/m).filter((n)=>!/^\s*\[\[hooks]]\s*$/m.test(n)||!n.includes(Gt)).join("").trimEnd()}function Jm(e,t){let n=e.indexOf(Do,t.start);if(n===-1||n>t.end)return e;return Cn(e,{start:n,end:n+Do.length})}function gc(e){let t=fc(e);if(Um(Gm(t),{recursive:!0}),!uc(t))return I(t,`${So}
217
- `),{path:t,alreadyInstalled:!1};let n=pc(t,"utf-8");if(n.includes(Gt))return{path:t,alreadyInstalled:!0};return I(t,Km(n)),{path:t,alreadyInstalled:!1}}function hc(e){let t=fc(e);if(!uc(t))return{path:t,alreadyInstalled:!1};let n=pc(t,"utf-8");if(!n.includes(Gt))return{path:t,alreadyInstalled:!1};let r=mc(n),o=r?Jm(n,r):`${Wm(n)}
218
- `;return I(t,o),{path:t,alreadyInstalled:!0}}var Ao="safety-net@cc-marketplace",yc=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),Lc=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function Po(e){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(e??"")}function xc(e){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(e??"")}function Xm(e){return/^Marketplace `cc-marketplace`\s*$/m.test(e??"")}var Cc={"claude-code":{installCommands:(e)=>{let t=cn(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"]],...Mr(e).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:cn(e,Ao)?[["claude","plugin","uninstall",Ao]]:[],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 se(["codex","plugin","list"]),r=xc(n);return{commands:[r||Xm(n)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:Po(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 se(["copilot","plugin","list"]),t=[...aa(e)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...la(e)?[["copilot","plugin","uninstall",oa]]:[]];if(ia(e))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",ie]],cleanupCommands:t,update:!0};return{commands:[sa(await se(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",ie]],cleanupCommands:t}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(e)=>{let t=zr(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:io,installCommands:()=>({commands:Za()}),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(`
219
- `)},opencode:{beforeInstall:lo,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 Hn(){return process.env.HOME??Ym()}function Sc(e,t=(n)=>n){try{let n=JSON.parse(t(kc(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 Qm(e){let t=Ro(It(e),"settings.json");if(!Eo(t))return;let n=Sc(t,q),r=n.enabledPlugins;if(!r||typeof r!=="object"||Array.isArray(r))return;if(r[ie]!==!1)return;let o=kc(t,"utf-8"),i=o.replace(new RegExp(`("${ie}"\\s*:\\s*)false`),"$1true");return r[ie]=!0,I(t,i!==o?i:`${JSON.stringify(n,null,2)}
220
- `),`Enabled ${ie} plugin in ${t}`}function eg(e){let t=co(e);if(!Eo(t))return;let n=Sc(t);if(!Array.isArray(n.packages))return;let r=n.packages.find((o)=>!!o&&typeof o==="object"&&!Array.isArray(o)&&uo(o.source)&&("extensions"in o));if(!r)return;return delete r.extensions,I(t,`${JSON.stringify(n,null,2)}
221
- `),`Enabled npm:cc-safety-net extensions in ${t}`}function vc(e,t){let n=_({label:t,booleans:Object.fromEntries(ae.map((i)=>[i.target,[i.flag]]))},e),r=n.errors[0];if(r)throw Error(r);let o=ae.filter((i)=>n.flags[i.target]).map((i)=>i.target);if(o.length!==1)throw Error(`Choose exactly one ${t} target: ${ae.map((i)=>i.flag).join(", ")}`);return o[0]}async function Dc(e=Hn(),t=ot){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:dt(process.cwd(),{homeDir:e,ampPluginListOutput:n,codexPluginListOutput:r,copilotCliVersion:o})}}async function tg(e,t=ot){let n=await Dc(Hn(),t);return n.hooks.filter((r)=>e==="install"?r.configured:r.detected||r.inspectionStatus==="not-inspected").filter((r)=>r.platform!=="codex"||!Po(n.codexPluginListOutput)||xc(n.codexPluginListOutput)).map((r)=>r.platform)}function ng(e,t,n){if(t.length>0)return{finish:async()=>[vc(t,e)]};if(!n.selectTargets&&!Lo(n.input,n.output))return{finish:async()=>[vc(t,e)]};let r=n.detectConfiguredTargets??(()=>tg(e,n.fetchVersion)),o=Promise.all([sc(n.probeTargets),r()]);return{ready:o,finish:async()=>{let[i,s]=await o,a=ac(i,{action:e,configuredTargets:s}),l=n.selectTargets?await n.selectTargets(e,wc(e,a)):await jl(e,wc(e,a),{input:n.input,output:n.output});if(l==="update")return l;if(!l||l.length===0)return null;return xo(l)}}}async function Ge(e,t,n=!1,r){let o=Cc[e];o.beforeInstall?.(t);let i=typeof o.installCommands==="function"?await o.installCommands(t,r):{commands:o.installCommands};return await no(i.commands),await Va(i.cleanupCommands??[]),[`${i.update||n?"Updated":"Installed"} ${R(e)} integration`,o.postInstallMessage].filter(Boolean).join(`
222
- `)}async function mt(e){let t=Cc[e];if(!t.uninstallCommands)throw Error(`${R(e)} uninstall is not supported`);return await no(t.uninstallCommands),`Uninstalled ${R(e)} integration`}function rg(e){let t=hl(e);return t.alreadyInstalled?`Uninstalled OpenCode plugin from ${t.path}`:`OpenCode plugin not installed in ${t.path}`}var og={"antigravity-cli":{install:nc,uninstall:rc},cursor:{install:La,uninstall:va},"grok-build":{install:Ea,uninstall:Pa},"kimi-code":{install:gc,uninstall:hc}};function xe(e,t,n,r=!1){if(e==="install"&&!r)Nn(n);let o=og[t][e](n),i=R(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 ig={amp:{install:Yl,uninstall:Zl,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:$a,uninstall:Na,afterInstall:async(e)=>{let t=Qr(e);return await se(["hermes","plugins","enable",K,"--no-allow-tool-override"]),!t},beforeUninstall:async(e)=>{Xr(e);try{await se(["hermes","plugins","disable",K])}catch(t){console.warn(`${t instanceof Error?t.message:String(t)}
223
- Removing the plugin files anyway; ${K} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Fn(e,t,n,r=!1){let o=ig[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=R(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(`
224
- `)}var sg={amp:{install:(e,t)=>Fn("install","amp",e,t),uninstall:(e)=>Fn("uninstall","amp",e)},"antigravity-cli":{install:(e,t)=>xe("install","antigravity-cli",e,t),uninstall:(e)=>xe("uninstall","antigravity-cli",e)},"claude-code":{install:(e,t)=>Ge("claude-code",e,t),uninstall:()=>mt("claude-code")},codex:{install:(e,t,n)=>Ge("codex",e,t,n),uninstall:()=>mt("codex")},"copilot-cli":{install:async(e,t)=>[await Ge("copilot-cli",e,t),Qm(e)].filter(Boolean).join(`
225
- `),uninstall:()=>mt("copilot-cli")},cursor:{install:(e,t)=>xe("install","cursor",e,t),uninstall:(e)=>xe("uninstall","cursor",e)},"gemini-cli":{install:(e,t)=>Ge("gemini-cli",e,t),uninstall:()=>mt("gemini-cli")},"grok-build":{install:(e,t)=>xe("install","grok-build",e,t),uninstall:(e)=>xe("uninstall","grok-build",e)},"hermes-agent":{install:(e,t)=>{if(!t)Nn(e);return Fn("install","hermes-agent",e,t)},uninstall:(e)=>Fn("uninstall","hermes-agent",e)},"kimi-code":{install:(e,t)=>xe("install","kimi-code",e,t),uninstall:(e)=>xe("uninstall","kimi-code",e)},openclaw:{install:async(e,t)=>{let n=await Ge("openclaw",e,t);return await Xa(),n},uninstall:(e)=>(io(e),mt("openclaw"))},opencode:{install:async(e,t)=>{let n=await Ge("opencode",e,t);return await pl(e),n},uninstall:(e)=>rg(e)},pi:{install:async(e,t)=>[await Ge("pi",e,t),eg(e)].filter(Boolean).join(`
226
- `),uninstall:()=>mt("pi")}},bc=["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(`
227
- `);function ag(e){if(Ft({homeDir:e,cwd:process.cwd()}).status!=="configured")return bc;return[bc,"",h.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(`
216
+ ${Yo}
217
+ `}function Ch(e){return e.split(/(?=^\s*\[)/m).filter((n)=>!/^\s*\[\[hooks]]\s*$/m.test(n)||!n.includes(sn)).join("").trimEnd()}function Sh(e,t){let n=e.indexOf(Zo,t.start);if(n===-1||n>t.end)return e;return Wn(e,{start:n,end:n+Zo.length})}function dd(e){let t=ld(e);if(yh(vh(t),{recursive:!0}),!sd(t))return O(t,`${Yo}
218
+ `),{path:t,alreadyInstalled:!1};let n=ad(t,"utf-8");if(n.includes(sn))return{path:t,alreadyInstalled:!0};return O(t,xh(n)),{path:t,alreadyInstalled:!1}}function ud(e){let t=ld(e);if(!sd(t))return{path:t,alreadyInstalled:!1};let n=ad(t,"utf-8");if(!n.includes(sn))return{path:t,alreadyInstalled:!1};let r=cd(n),o=r?Sh(n,r):`${Ch(n)}
219
+ `;return O(t,o),{path:t,alreadyInstalled:!0}}var Qo="safety-net@cc-marketplace",pd=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),fd=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function ti(e){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(e??"")}function vd(e){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(e??"")}function Ph(e){return/^Marketplace `cc-marketplace`\s*$/m.test(e??"")}var bd={"claude-code":{installCommands:(e)=>{let t=$n(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"]],...uo(e).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:$n(e,Qo)?[["claude","plugin","uninstall",Qo]]:[],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=vd(n);return{commands:[r||Ph(n)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:ti(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=[...nl(e)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...rl(e)?[["copilot","plugin","uninstall",Qa]]:[]];if(el(e))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",de]],cleanupCommands:t,update:!0};return{commands:[tl(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=vo(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:_o,installCommands:()=>({commands:zl()}),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(`
220
+ `)},opencode:{beforeInstall:$o,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 sr(){return process.env.HOME??Rh()}function Ld(e,t=(n)=>n){try{let n=JSON.parse(t(yd(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 Ah(e){let t=Xo(Jt(e),"settings.json");if(!ei(t))return;let n=Ld(t,K),r=n.enabledPlugins;if(!r||typeof r!=="object"||Array.isArray(r))return;if(r[de]!==!1)return;let o=yd(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)}
221
+ `),`Enabled ${de} plugin in ${t}`}function Eh(e){let t=Oo(e);if(!ei(t))return;let n=Ld(t);if(!Array.isArray(n.packages))return;let r=n.packages.find((o)=>!!o&&typeof o==="object"&&!Array.isArray(o)&&Fo(o.source)&&("extensions"in o));if(!r)return;return delete r.extensions,O(t,`${JSON.stringify(n,null,2)}
222
+ `),`Enabled npm:cc-safety-net extensions in ${t}`}function md(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 wd(e=sr(),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 _h(e,t=pt){let n=await wd(sr(),t);return n.hooks.filter((r)=>e==="install"?r.configured:r.detected||r.inspectionStatus==="not-inspected").filter((r)=>r.platform!=="codex"||!ti(n.codexPluginListOutput)||vd(n.codexPluginListOutput)).map((r)=>r.platform)}function Th(e,t,n){if(t.length>0)return{finish:async()=>[md(t,e)]};if(!n.selectTargets&&!Bo(n.input,n.output))return{finish:async()=>[md(t,e)]};let r=n.detectConfiguredTargets??(()=>_h(e,n.fetchVersion)),o=Promise.all([td(n.probeTargets),r()]);return{ready:o,finish:async()=>{let[i,s]=await o,a=nd(i,{action:e,configuredTargets:s}),l=n.selectTargets?await n.selectTargets(e,hd(e,a)):await Oc(e,hd(e,a),{input:n.input,output:n.output});if(l==="update")return l;if(!l||l.length===0)return null;return Jo(l)}}}async function tt(e,t,n=!1,r){let o=bd[e];o.beforeInstall?.(t);let i=typeof o.installCommands==="function"?await o.installCommands(t,r):{commands:o.installCommands};return await Po(i.commands),await Ml(i.cleanupCommands??[]),[`${i.update||n?"Updated":"Installed"} ${P(e)} integration`,o.postInstallMessage].filter(Boolean).join(`
223
+ `)}async function xt(e){let t=bd[e];if(!t.uninstallCommands)throw Error(`${P(e)} uninstall is not supported`);return await Po(t.uninstallCommands),`Uninstalled ${P(e)} integration`}function Ih(e){let t=uc(e);return t.alreadyInstalled?`Uninstalled OpenCode plugin from ${t.path}`:`OpenCode plugin not installed in ${t.path}`}var $h={"antigravity-cli":{install:Zc,uninstall:Xc},cursor:{install:fl,uninstall:ml},"grok-build":{install:Cl,uninstall:Sl},"kimi-code":{install:dd,uninstall:ud}};function Oe(e,t,n,r=!1){if(e==="install"&&!r)or(n);let o=$h[t][e](n),i=P(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 Oh={amp:{install:Vc,uninstall:zc,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:El,uninstall:_l,afterInstall:async(e)=>{let t=So(e);return await ue(["hermes","plugins","enable",Q,"--no-allow-tool-override"]),!t},beforeUninstall:async(e)=>{Co(e);try{await ue(["hermes","plugins","disable",Q])}catch(t){console.warn(`${t instanceof Error?t.message:String(t)}
224
+ Removing the plugin files anyway; ${Q} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function ir(e,t,n,r=!1){let o=Oh[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=P(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(`
225
+ `)}var Fh={amp:{install:(e,t)=>ir("install","amp",e,t),uninstall:(e)=>ir("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),Ah(e)].filter(Boolean).join(`
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)or(e);return ir("install","hermes-agent",e,t)},uninstall:(e)=>ir("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 Kl(),n},uninstall:(e)=>(_o(e),xt("openclaw"))},opencode:{install:async(e,t)=>{let n=await tt("opencode",e,t);return await ac(e),n},uninstall:(e)=>Ih(e)},pi:{install:async(e,t)=>[await tt("pi",e,t),Eh(e)].filter(Boolean).join(`
227
+ `),uninstall:()=>xt("pi")}},gd=["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 jh(e){if(Qt({homeDir:e,cwd:process.cwd()}).status!=="configured")return gd;return[gd,"",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(`
228
229
  `))].join(`
229
- `)}function wc(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 lg(e,t){if(e.selectKimiInstallMethod)return e.selectKimiInstallMethod();if(!Lo(e.input,e.output))return Promise.resolve("global-hook");return Ml({input:e.input,output:e.output,globalHookInstalled:Ft({homeDir:t,cwd:process.cwd()}).status==="configured"})}async function Rc(e,t,n,r=!1,o){return sg[t][e](n,r,o)}function cg(e){let t=_({label:"update"},e).errors[0];if(t)throw Error(t)}async function dg(e,t=ot){let n=await Dc(e,t),r=Ro(It(e),"installed-plugins");return{targets:xo([...n.hooks.filter((i)=>i.platform!=="copilot-cli"&&i.detected).map((i)=>i.platform),...[dn,ra,na].flatMap((i)=>Eo(Ro(r,...i))?["copilot-cli"]:[]),...cn(e,Ao)?["claude-code"]:[],...Po(n.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:n.codexPluginListOutput}}async function ug(e){let t=Hn(),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??be)(),s=async()=>{let u=i&&await i;if(u?.updateAvailable)n.write(`
230
+ `)}function hd(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 Nh(e,t){if(e.selectKimiInstallMethod)return e.selectKimiInstallMethod();if(!Bo(e.input,e.output))return Promise.resolve("global-hook");return $c({input:e.input,output:e.output,globalHookInstalled:Qt({homeDir:t,cwd:process.cwd()}).status==="configured"})}async function kd(e,t,n,r=!1,o){return Fh[t][e](n,r,o)}function Hh(e){let t=E({label:"update"},e).errors[0];if(t)throw Error(t)}async function Mh(e,t=pt){let n=await wd(e,t),r=Xo(Jt(e),"installed-plugins");return{targets:Jo([...n.hooks.filter((i)=>i.platform!=="copilot-cli"&&i.detected).map((i)=>i.platform),...[On,Xa,Za].flatMap((i)=>ei(Xo(r,...i))?["copilot-cli"]:[]),...$n(e,Qo)?["claude-code"]:[],...ti(n.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:n.codexPluginListOutput}}async function Uh(e){let t=sr(),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(`
230
231
  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.
231
- `)},a=dg(t,e.fetchVersion??ot).then(async(u)=>{let m=new Set(u.targets);return{targets:u.targets,codexPluginListOutput:u.codexPluginListOutput,available:new Map(await Promise.all(ae.filter((f)=>m.has(f.target)&&yc.has(f.target)).map(async(f)=>[f.target,await Co(f.probeCommand)])))}}),l=await Tt(e.showBanner??!0,()=>({ready:a,finish:()=>a}),()=>Pt({input:e.input??process.stdin,output:n}),{loadingMessage:"Checking installed integrations…",output:n}),c=await Promise.resolve().then(()=>(oc(Zm(),process.platform,o),null)).catch((u)=>Bt(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)=>Lc.has(u))?await Promise.resolve().then(()=>(Nn(t),null)).catch((u)=>Bt(u)):null,p=await sn(Promise.all(l.targets.map((u)=>{if(yc.has(u)&&!l.available.get(u))return Promise.resolve({message:`${R(u)} not found; skipped`,failed:!1});if(d!==null&&Lc.has(u))return Promise.resolve({message:d,failed:!0});return Rc("install",u,t,!0,l.codexPluginListOutput).then((m)=>({message:m,failed:!1}),(m)=>({message:Bt(m),failed:!0}))})),{loadingMessage:`Updating ${l.targets.length} integration${l.targets.length===1?"":"s"}…`,output:n}),g=c===null?p:[...p,{message:c,failed:!0}];return g.forEach((u)=>{u.failed?console.error(u.message):n.write(`${u.message}
232
- `)}),await s(),g.some((u)=>u.failed)?1:0}function To(e,t={}){return Promise.resolve().then(()=>cg(e)).then(()=>ug(t)).catch((n)=>(console.error(Bt(n)),1))}async function qt(e,t,n={}){try{let r=await Tt(!0,()=>ng(e,t,n),()=>Pt({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.
233
- `),0;if(r==="update")return(n.runUpdate??(()=>To([],{fetchVersion:n.fetchVersion,input:n.input,output:n.output,showBanner:!1})))();let o=Hn(),i=n.output??process.stdout;return await ic(r,async(s)=>{if(s==="kimi-code"&&e==="install"){let l=await lg(n,o);if(l===null){i.write(`Cancelled: Kimi Code integration was not installed.
234
- `);return}if(l==="plugin"){i.write(`${ag(o)}
235
- `);return}}let a=await sn(Rc(e,s,o),{loadingMessage:`${e==="install"?"Installing":"Uninstalling"} ${R(s)} integration…`,output:i});i.write(`${a}
236
- `)}),0}catch(r){return console.error(Bt(r)),1}}function Bt(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}
232
+ `)},a=Mh(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)&&pd.has(f.target)).map(async(f)=>[f.target,await Wo(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(()=>(Qc(Dh(),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)=>fd.has(u))?await Promise.resolve().then(()=>(or(t),null)).catch((u)=>an(u)):null,m=await _n(Promise.all(l.targets.map((u)=>{if(pd.has(u)&&!l.available.get(u))return Promise.resolve({message:`${P(u)} not found; skipped`,failed:!1});if(d!==null&&fd.has(u))return Promise.resolve({message:d,failed:!0});return kd("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}
233
+ `)}),await s(),g.some((u)=>u.failed)?1:0}function ni(e,t={}){return Promise.resolve().then(()=>Hh(e)).then(()=>Uh(t)).catch((n)=>(console.error(an(n)),1))}async function ln(e,t,n={}){try{let r=await Kt(!0,()=>Th(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.
234
+ `),0;if(r==="update")return(n.runUpdate??(()=>ni([],{fetchVersion:n.fetchVersion,input:n.input,output:n.output,showBanner:!1})))();let o=sr(),i=n.output??process.stdout;return await ed(r,async(s)=>{if(s==="kimi-code"&&e==="install"){let l=await Nh(n,o);if(l===null){i.write(`Cancelled: Kimi Code integration was not installed.
235
+ `);return}if(l==="plugin"){i.write(`${jh(o)}
236
+ `);return}}let a=await _n(kd(e,s,o),{loadingMessage:`${e==="install"?"Installing":"Uninstalling"} ${P(s)} integration…`,output:i});i.write(`${a}
237
+ `)}),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}
237
238
  Check file permissions for the target config file and parent directory.`;if(n==="ENOENT")return`${t}
238
239
  Check that the target config path and parent directory exist.`;if(n==="ENOTDIR")return`${t}
239
- Check that every parent path component is a directory.`;return t}import{join as Jg}from"node:path";var Ac="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Cache path | Priority |\n|-------|-------------|---------------|------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | `~/.cc-safety-net/cache/rulebooks/` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | `.cc-safety-net/cache/rulebooks/` | Second |\n| GitHub source | Listed in a local `rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` in the source repository | Consumer local cache | Source order |\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 sync`/`rule verify` report 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- GitHub sources use `owner/repo#ref/<rulebook-name>`.\n- GitHub refs must be one path segment, such as a tag, SHA, or branch name without `/`.\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` |\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### 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. Fixtures are shape-validated only; CC Safety Net does not execute them.\n\n## Matching Behavior\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; it adds the source and syncs it.\n5. Run `cc-safety-net rule sync` after manual `rule.json` changes or local rulebook edits.\n6. Run `cc-safety-net rule verify` to validate config, lock/cache state, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n7. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nAn edited or invalid local rulebook keeps its last synced, digest-verified cached version enforced until `cc-safety-net rule sync` validates the edit. A missing lock entry or cache, a cache digest mismatch, or an invalid cached rulebook makes that source inactive; a missing lockfile or 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. Repair the reported condition, then run `cc-safety-net rule sync`. Run `cc-safety-net status` to see degraded sources.\n";function Vt(e,t){if(!e.ok){gg(e);return}hg(e),console.log(t),console.log("Rule config synced."),console.log(""),pg(e.entries)}function pg(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} (${fg(t.ruleCount??0)})`),console.log(` Source: ${pr(t)}`)}function fg(e){return`${e} ${e===1?"rule":"rules"}`}function Pc(e,t){Be("Active sources",e.rulebooks,(n)=>[`[${n.source}] ${n.name} ${n.version}`,` Source: ${t[n.source].get(n.spec)??n.spec}`]),Be("Active rules",e.rules,(n)=>[`[${mg(e,n.name)}] ${n.name}`,` Command: ${n.subcommand?`${n.command} ${n.subcommand}`:n.command}`,` Block args: ${n.block_args.join(", ")}`,` Reason: ${n.reason}`]),Be("Disabled rules",Ec(e,"off"),(n)=>[n.key]),Be("Reason overrides",Ec(e,"reason"),(n)=>[n.key,` Reason: ${n.value.reason}`]),Be("Transparent wrappers",e.transparent_wrappers,(n)=>[n]),Be("Issues",e.errors,(n)=>[n]),Be("Warnings",e.warnings,(n)=>[n])}function Be(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 mg(e,t){return e.rulebooks.find((n)=>n.rules.includes(t))?.source??"project"}function Ec(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 gg(e){for(let t of e.errors)console.error(t)}function hg(e){if(!e.warnings||e.warnings.length===0)return;for(let t of e.warnings)console.warn(t)}import{dirname as Tc,join as Mn}from"node:path";var yg=".safety-net.json",Lg="~/.cc-safety-net/config.json";async function Oc(e){return[await Ic({legacyPath:_c({cwd:e.cwd}),configPath:Q(e.cwd),defaultRulebookName:"project-rules",migratedFrom:yg,cleanup:e.cleanup,syncOptions:{cwd:e.cwd}}),await Ic({legacyPath:Lt(),configPath:ee(),defaultRulebookName:"user-rules",migratedFrom:Lg,cleanup:e.cleanup,syncOptions:{cwd:e.cwd,global:!0}})].every((n)=>n)?0:1}async function Ic(e){let t=Y(e.syncOptions),n=k(t.filesystemScope,e.legacyPath),r=w(n);if(r===null)return console.log(`No legacy config found at ${e.legacyPath}`),!0;let o=bg(r);if(!o.ok){for(let g of o.errors)console.error(g);return!1}let i=Z(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=wg(Tc(e.configPath),s.rules,e.defaultRulebookName,e.migratedFrom,t.filesystemScope),l=Mn(Tc(e.configPath),a,"rulebook.json"),c=k(t.filesystemScope,l),d=[Io(t.configTarget),Io(c),Io(t.lockTarget)],p=await vg(e,t.configTarget,c,a,o.config.rules,s.rules.includes(a)?s.rules:[...s.rules,a],s.overrides??{},s.transparent_wrappers??[]);if(!p.ok){Cg(d);for(let g of p.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(!xg(t.configTarget,c,a,e.migratedFrom,o.config.rules))return console.error(`Migration cleanup verification failed for ${e.legacyPath}`),!1;return Je(n),console.log(`Deleted legacy config at ${e.legacyPath}`),!0}async function vg(e,t,n,r,o,i,s,a){try{return X(t,{version:1,rules:i,overrides:s,transparent_wrappers:a}),X(n,kg(r,e.migratedFrom,o)),await Ye(e.syncOptions)}catch(l){return{ok:!1,errors:[l instanceof Error?l.message:String(l)]}}}function bg(e){try{let t=JSON.parse(e),n=Qn(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 wg(e,t,n,r,o){let i=t.find((s)=>Sg(k(o,Mn(e,s,"rulebook.json")))===r);if(i)return i;if(w(k(o,Mn(e,n,"rulebook.json")))===null)return n;for(let s=2;;s++){let a=`${n}-${s}`;if(w(k(o,Mn(e,a,"rulebook.json")))===null)return a}}function kg(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 xg(e,t,n,r,o){if(!Z(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 Io(e){return{target:e,content:w(e)}}function Cg(e){for(let t of e){if(t.content===null){Je(t.target);continue}Se(t.target,t.content)}}function Sg(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 Dg,readFile as Rg,writeFile as Ag}from"node:fs/promises";import{dirname as Eg,join as Pg}from"node:path";var Tg=86400000,Ig=604800000;async function Nc(e=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=gr();if(!t)return null;let n=Pg(t,".cc-safety-net","update-check.json"),r=await _g(n,e);if(!r.lastCheck||e-r.lastCheck>Tg){let s=await be();if(r.lastCheck=e,s.latestVersion)r.latestVersion=s.latestVersion;if(!await $c(n,r))return null;if(s.error)return null}let o=r.latestVersion,i=T();if(!o||!Or(o,i))return null;if(r.notifiedVersion===o&&r.notifiedAt!==void 0&&e-r.notifiedAt<Ig)return null;if(r.notifiedVersion=o,r.notifiedAt=e,!await $c(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 _g(e,t){let n=await Rg(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 $c(e,t){return Dg(Eg(e),{recursive:!0,mode:448}).then(()=>Ag(e,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{dirname as Og,join as $g,resolve as _o}from"node:path";var Hc="CC Safety Net Config",Ng="═".repeat(Hc.length),Fg="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Hg=new Set(["rule.json","rule.lock","cache"]);function Mc(e={}){try{return Mg(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}function Mg(e){let t=e.cwd??process.cwd(),n=e.userConfigPath??ee(),r=e.projectConfigPath??Q(t),o=e.legacyUserConfigPath??Lt(),i=e.legacyProjectConfigPath??ni(t),s=_o(t,ur),a=Og(n),l=te({cwd:t,userConfigPath:n,projectConfigPath:r}),c=te({cwd:t}),d=k(l.userScope,n),p=k(l.projectScope,r),g=e.legacyUserConfigPath?gt(e.legacyUserConfigPath,"user policy"):k(c.userScope,o),u=e.legacyProjectConfigPath?gt(e.legacyProjectConfigPath,"project policy"):k(c.projectScope,i),m=!1,f=!1,L=[],v=[],x=jg(k(c.projectScope,s));if(Gg(),w(d)!==null){let y=ce(d);if(y.errors.push(...de(n,Ze({userConfigDir:a}),{userConfigDir:a},l.userScope)),L.push({scope:"User",path:n,result:y,schema:"rules",sourceDisplayMap:Re(n,l.userScope),target:d}),y.errors.length>0)m=!0}if(w(g)!==null)if(f=!0,w(d)!==null)v.push(jn("user","cleanup"));else{let y=er(g);if(L.push({scope:"User",path:o,result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:g}),v.push(jn("user",y.errors.length>0?"fix-or-delete":"migrate")),y.errors.length>0)m=!0}if(w(p)!==null){let y=ce(p);if(y.errors.push(...de(r,Xe(r),{userConfigDir:a},l.projectScope)),L.push({scope:"Project",path:_o(r),result:y,schema:"rules",sourceDisplayMap:Re(r,l.projectScope),target:p}),y.errors.length>0)m=!0;if(w(u)!==null)f=!0,v.push(jn("project","cleanup"))}else if(w(u)!==null){f=!0,m=!0;let y=er(u);L.push({scope:"Project",path:_o(i),result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:u}),v.push(jn("project",y.errors.length>0?"fix-or-delete":"migrate"))}if(x?.result.errors.length)m=!0;if(L.length===0&&!x)return console.log(`
240
- No config files found. Using built-in rules only.`),0;for(let y of L)if(y.inactive)qg(y.scope,y.path,y.result,y.sourceDisplayMap);else if(y.result.errors.length>0)Vg(y.scope,y.path,y.result.errors);else{if(y.schema==="rules"&&Wg(y.target))console.log(`
241
- Added $schema to ${y.scope.toLowerCase()} config.`);Bg(y.scope,y.path,y.result,y.schema,y.sourceDisplayMap)}for(let y of v)console.error(`
242
- ${h.red(y)}`);if(x)if(x.result.errors.length>0)Kg(x.path,x.result.errors);else zg(x.path,x.result);if(m)return console.error(`
243
- Config validation failed.`),1;return console.log(f?`
240
+ Check that every parent path component is a directory.`;return t}import{mkdirSync as Gh}from"node:fs";import{dirname as Bh}from"node:path";import{createInterface as qh}from"node:readline";var xd=new Set(["check","apply"]),Cd="(unset)";async function Rd(e,t={}){let n=E({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},e),r=n.positionals[0],o=[...n.errors,...r&&!xd.has(r)?[`Unknown policy subcommand: ${r}`]:[],...r&&xd.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(kn,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&&Kh(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)Sd(Y(_e(s).value),c,!0);if(!n.flags.global){let u=lt().baseline;console.log("Effective policy (user + project merged):"),Sd(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 Vh(`Apply this policy to ${s}? [y/N] `,d,m))return console.log("Cancelled; nothing was written."),0;return zh(s,a.value,c,n.flags.global),console.log(`Policy applied: ${s}`),0}function Vh(e,t,n){let r=qh({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 zh(e,t,n,r){if(r){cn(n);return}Gh(Bh(e),{recursive:!0}),J(e,jt(t,n))}function Sd(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??Cd} -> ${o.after??Cd}`)}function Kh(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}import{join as Ay}from"node:path";var Dd="# 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 ar(e,t){if(!e.ok){Td(e);return}Ed(e,t)}function Ad(e,t,n){if(e.ok)console.log(n);if(!e.add){ar(e,`Added rulebook source: ${t}`);return}if(!e.ok){Td(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(", ")}.`);Ed(e,"Rule config updated.")}function Ed(e,t){for(let n of e.changes??[])console.log(n);console.log(t),console.log(""),Jh(e.entries)}function Jh(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} (${Wh(t.ruleCount)})`),console.log(` Source: ${t.spec}`)}function Wh(e){return`${e} ${e===1?"rule":"rules"}`}function _d(e){nt("Active sources",e.rulebooks,(t)=>[`[${t.source}] ${t.name} ${t.version}`,` Source: ${t.spec}`]),nt("Active rules",e.rules,(t)=>[`[${Zh(e,t.name)}] ${t.name}`,...Yh(t),` Reason: ${t.reason}`]),nt("Disabled rules",Pd(e,"off"),(t)=>[t.key]),nt("Reason overrides",Pd(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 Yh(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 Zh(e,t){return e.rulebooks.find((n)=>n.rules.includes(t))?.source??"project"}function Pd(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 Td(e){for(let t of e.errors)console.error(t)}import{dirname as Id,join as lr}from"node:path";var Xh=".safety-net.json",Qh="~/.cc-safety-net/config.json";async function jd(e){return[await $d({legacyPath:Fd({cwd:e.cwd}),configPath:oe(e.cwd),defaultRulebookName:"project-rules",migratedFrom:Xh,cleanup:e.cleanup,syncOptions:{cwd:e.cwd}}),await $d({legacyPath:It(),configPath:ie(),defaultRulebookName:"user-rules",migratedFrom:Qh,cleanup:e.cleanup,syncOptions:{cwd:e.cwd,global:!0}})].every((n)=>n)?0:1}async function $d(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=ty(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=ny(Id(e.configPath),s.rules,e.defaultRulebookName,e.migratedFrom,t.filesystemScope),l=lr(Id(e.configPath),a,"rulebook.json"),c=x(t.filesystemScope,l),d=[Od(t.configTarget),Od(c)],m=await ey(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){iy(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(!oy(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 ey(e,t,n,r,o,i,s,a){try{return J(t,{version:1,rules:i,overrides:s,transparent_wrappers:a}),J(n,ry(r,e.migratedFrom,o)),await Tt(e.syncOptions)}catch(l){return{ok:!1,errors:[l instanceof Error?l.message:String(l)]}}}function ty(e){try{let t=JSON.parse(e),n=br(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 ny(e,t,n,r,o){let i=t.find((s)=>sy(x(o,lr(e,s,"rulebook.json")))===r);if(i)return i;if(w(x(o,lr(e,n,"rulebook.json")))===null)return n;for(let s=2;;s++){let a=`${n}-${s}`;if(w(x(o,lr(e,a,"rulebook.json")))===null)return a}}function ry(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 oy(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 Od(e){return{target:e,content:w(e)}}function iy(e){for(let t of e){if(t.content===null){he(t.target);continue}B(t.target,t.content)}}function sy(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 ay,readFile as ly,writeFile as cy}from"node:fs/promises";import{dirname as dy,join as uy}from"node:path";var py=86400000,fy=604800000;async function Hd(e=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=Hr();if(!t)return null;let n=uy(t,".cc-safety-net","update-check.json"),r=await my(n,e);if(!r.lastCheck||e-r.lastCheck>py){let s=await Te();if(r.lastCheck=e,s.latestVersion)r.latestVersion=s.latestVersion;if(!await Nd(n,r))return null;if(s.error)return null}let o=r.latestVersion,i=I();if(!o||!io(o,i))return null;if(r.notifiedVersion===o&&r.notifiedAt!==void 0&&e-r.notifiedAt<fy)return null;if(r.notifiedVersion=o,r.notifiedAt=e,!await Nd(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 my(e,t){let n=await ly(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 Nd(e,t){return ay(dy(e),{recursive:!0,mode:448}).then(()=>cy(e,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as gy,resolve as ri}from"node:path";var Md="CC Safety Net Config",hy="═".repeat(Md.length),yy="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",vy=new Set(["rule.json","rule.lock","cache"]);function Ud(e={}){try{return by(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}function by(e){let t=e.cwd??process.cwd(),n=e.userConfigPath??ie(),r=e.projectConfigPath??oe(t),o=e.legacyUserConfigPath??It(),i=e.legacyProjectConfigPath??Pi(t),s=ri(t,Dt),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=Ly(x(l.projectScope,s));if(ky(),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(cr("user","cleanup"));else{let h=Lr(m);if(f.push({scope:"User",path:o,result:h,schema:"legacy",inactive:!0,target:m}),b.push(cr("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:ri(r),result:h,schema:"rules",target:d}),h.errors.length>0)u=!0;if(w(g)!==null)p=!0,b.push(cr("project","cleanup"))}else if(w(g)!==null){p=!0,u=!0;let h=Lr(g);f.push({scope:"Project",path:ri(i),result:h,schema:"legacy",inactive:!0,target:g}),b.push(cr("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)Cy(h.scope,h.path,h.result);else if(h.result.errors.length>0)Sy(h.scope,h.path,h.result.errors);else{if(h.schema==="rules"&&Py(h.target))console.log(`
242
+ Added $schema to ${h.scope.toLowerCase()} config.`);xy(h.scope,h.path,h.result,h.schema)}for(let h of b)console.error(`
243
+ ${y.red(h)}`);if(L)if(L.result.errors.length>0)Dy(L.path,L.result.errors);else Ry(L.path,L.result);if(u)return console.error(`
244
+ Config validation failed.`),1;return console.log(p?`
244
245
  Configs valid with warnings.`:`
245
- All configs valid.`),0}function jn(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 jg(e){if(De(e)===null)return null;let t=Ug(e);if(t.ruleNames.size===0&&t.errors.length===0)return null;return{path:e.path,result:t}}function Ug(e){let t=[],n=new Set,r=(De(e)??[]).filter((o)=>!Hg.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(!yt.test(o.name)){t.push(`rulebook directory names must match ${yt}: ${o.name}`);continue}if(o.kind!=="directory"){t.push(`${o.name} must be a rulebook directory`);continue}let i=k(e.scope,$g(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=Fc(a);if(l.name!==o.name){t.push(`rulebook name "${l.name}" must match folder "${o.name}"`);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 Gg(){console.log(Hc),console.log(Ng)}function Bg(e,t,n,r,o){if(console.log(`
246
- ✓ ${e} config: ${t}`),console.log(` Schema: ${r==="rules"?"rulebook sources":"legacy inline rules"}`),n.ruleNames.size>0){console.log(` ${r==="rules"?"Sources":"Rules"}:`);let i=1;for(let s of n.ruleNames)console.log(` ${i}. ${o.get(s)??s}`),i++}else console.log(` ${r==="rules"?"Sources":"Rules"}: (none)`)}function qg(e,t,n,r){if(console.error(`
247
- ✗ 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 o=1;for(let i of n.errors)for(let s of i.split("; "))console.error(` ${o}. ${s}`),o++;return}if(n.ruleNames.size>0){console.error(" Rules:");let o=1;for(let i of n.ruleNames)console.error(` ${o}. ${r.get(i)??i}`),o++;return}console.error(" Rules: (none)")}function Vg(e,t,n){jc(`${e} config`,t,n)}function zg(e,t){console.log(`
248
- ✓ GitHub source rules: ${e}`),console.log(" Rulebooks:");let n=1;for(let r of t.ruleNames)console.log(` ${n}. ${r}`),n++}function Kg(e,t){jc("GitHub source rules",e,t)}function jc(e,t,n){console.error(`
249
- ✗ ${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 Wg(e){try{let t=w(e);if(t===null)return!1;let n=JSON.parse(t);if(n.$schema)return!1;return Se(e,JSON.stringify({$schema:Fg,...n},null,2)),!0}catch(t){if(t instanceof H)throw t;return!1}}var Uc=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),Yg=new Set(["add","remove","list"]);async function Bc(e){try{return await Zg(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}async function Zg(e){let t=Qg(e),n=t.help?Xg(t.positionals):null;if(n)return En(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 En(rt,console.error),1;let o=t.positionals[1],i={global:t.global,check:t.check};if(r==="init"){let s=Y(i),a=s.configDir;n1(s.configTarget),Gc(k(s.filesystemScope,Wt({...i,cacheConfigDir:a})));let l=Jg(a,"example-rules","rulebook.json"),c=k(s.filesystemScope,l);if(t.example&&w(c)===null)mr(c,"example-rules");let d=await Ye(i);return Vt(d,"Rule config initialized."),d.ok?0:1}if(r==="add"){if(!o)return console.error("rule add requires a source"),1;let s=await lr(o,i);return Vt(s,`Added rulebook source: ${o}`),s.ok?0:1}if(r==="remove"){if(!o)return console.error("rule remove requires a source"),1;let s=await dr(o,{...i,deleteSource:t.deleteSource});return Vt(s,`Removed rulebook source: ${o}`),s.ok?0:1}if(r==="update"||r==="sync"){let s=await Ye({...i,only:r==="update"?o:void 0});return Vt(s,t.check?"Rule config checked.":"Rule config synced."),s.ok?0:1}if(r==="list"){let s=ve(),a=te({});return Pc(s,{user:Re(s.userConfigPath,a.userScope),project:Re(s.projectConfigPath,a.projectScope)}),s.errors.length>0?1:0}if(r==="wrapper")return r1(t);if(r==="migrate")return Oc({cleanup:t.cleanup,cwd:process.cwd()});if(r==="doc"){console.log(Ac);let s=await Nc();if(s)console.error(s);return 0}if(r==="verify")return Mc();return 1}function Xg(e){if(e.length===0)return rt;let t=rt.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:[]}}function Qg(e){let t=_({label:"rule",booleans:{global:["-g","--global"],check:["--check"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},positionals:"list"},e),n={...t.flags,help:t.help,positionals:t.positionals,errors:t.errors};return e1(n),n}function e1(e){let[t]=e.positionals;if(t&&!Uc.has(t))e.errors.push(`Unknown rule subcommand: ${t}`);if(e.deleteSource&&t!=="remove")if(t&&Uc.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.cleanup&&t!=="migrate")e.errors.push(Un(t,"--cleanup"));if(e.example&&t!=="init")e.errors.push(Un(t,"--example"));if(t==="migrate"){if(e.global)e.errors.push(Un(t,"--global"));if(e.check)e.errors.push(Un(t,"--check"));if(e.positionals.length>1)e.errors.push(`Unexpected rule migrate argument: ${e.positionals[1]}`)}else if(t==="wrapper")t1(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 Un(e,t){return e?`Unknown option for rule ${e}: ${t}`:`Unknown option for rule: ${t}`}function t1(e){let t=e.positionals[1],n=e.positionals[2];if(!t){e.errors.push("rule wrapper requires add, remove, or list");return}if(!Yg.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 n1(e){if(w(e)===null){fr(e);return}let t=Z(e);if(!t.config)return;X(e,{version:1,rules:t.config.rules,overrides:t.config.overrides??{},transparent_wrappers:t.config.transparent_wrappers??[]})}async function r1(e){let t=e.positionals[1],n=e.positionals[2],r=Y({global:e.global}).configTarget;if(t==="list"){let a=Z(r);if(a.errors.length>0){for(let l of a.errors)console.error(l);return 1}return o1(a.config?.transparent_wrappers??[]),0}if(!n||!hr.test(n))return console.error("transparent wrapper must match command pattern"),1;if(Lr(n))return console.error(`reserved command "${n}" cannot be a wrapper`),1;let o=Z(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 X(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 o1(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 qc}from"node:os";import{existsSync as i1,readFileSync as s1}from"node:fs";import{homedir as a1}from"node:os";import{join as l1}from"node:path";async function c1(e){if(e.isTTY)return null;return(await Sr(e).catch(()=>null))?.trim()||null}function d1(){if(process.env.CLAUDE_SETTINGS_PATH)return process.env.CLAUDE_SETTINGS_PATH;return l1(a1(),".claude","settings.json")}function Oo(){let e=d1();if(!i1(e))return!1;try{let t=s1(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(wt(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 $o(e=process.stdin){let t=Oo(),n;if(!t)n="\uD83D\uDEE1️ CC Safety Net ❌";else{let o=B({cwd:process.cwd()}),i=o.policy,s=ue(i),a=Object.values(Pe(i,s.capabilities)).some((c)=>c.changesInherited);n=`\uD83D\uDEE1️ CC Safety Net ${{standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[a?"custom":s.effectiveLevel]}${s.worktreeMode?"\uD83C\uDF33":""}${o.state==="degraded"?"⚠️":""}`}let r=await c1(e);if(r&&!r.startsWith("{"))console.log(`${r} | ${n}`);else console.log(n)}function Vc(){let e=B({cwd:process.cwd()}),t=e.policy,n=ue(t),r=!!process.env.NO_COLOR||!process.stdout.isTTY,o=Math.min(process.stdout.columns||80,100),i=r?"ok":"✔",s=r?"OFF":"✘",a=(u,m)=>{let f=` ${u.padEnd(13)}${m}`;return(f.length>o?`${f.slice(0,o-1)}…`:f).replaceAll(s,h.red(s))},l=Object.values(Pe(t,n.capabilities)).some((u)=>u.changesInherited),c=kt(),d={ready:h.green,degraded:h.yellow}[e.state],p=[...Oo()?[]:["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],g=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.startsWith(qc())?`~${c.slice(qc().length)}`:c),...n.worktreeMode?[a("Worktree","relaxations active")]:[],"",...p.length===0?[" Everything configured is active."]:[" Not active",...p.flatMap((u)=>An(u," ",o-6).map((m,f)=>f===0?` ${g} ${m}`:m)),""," Full report: cc-safety-net doctor"]].join(`
250
- `))}import{spawn as dd}from"node:child_process";import{randomBytes as w1}from"node:crypto";import{createServer as k1}from"node:http";import{Writable as x1}from"node:stream";import{homedir as u1}from"node:os";var Gn=500;function p1(e){let t=e.filter((o)=>o.decision!=="allow"),n=e.filter((o)=>o.decision==="allow"),r=Math.min(t.length,Math.max(Gn-n.length,Math.ceil(Gn/2)));return[...t.slice(0,r),...n.slice(0,Gn-r)]}function zc(e,t=pe()){if(t)Ae(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?Le(t,a):[])for(let L of Ce(f,a)){if(!L||typeof L.ts!=="string"||typeof L.command!=="string")continue;let v=new Date(L.ts).getTime();if(!Number.isFinite(v))continue;if(v>=i)s.push(L)}s.sort((f,L)=>new Date(L.ts).getTime()-new Date(f.ts).getTime());let l=Array.from({length:e},()=>0),c=Array.from({length:e},()=>0),d={},p={},g={},u=0,m=0;for(let f of s){let L=f.agent||"unknown";d[L]=(d[L]??0)+1;let v=Math.round((r-n(new Date(f.ts)))/86400000),x=e-1-v,y=v>=0&&v<e;if(y)c[x]=(c[x]??0)+1;if(f.decision!=="allow"){if(u++,f.ruleId)p[f.ruleId]=(p[f.ruleId]??0)+1;let C=qe(f.segment||f.command);if(C)g[C]=(g[C]??0)+1;if(f.failureStage)m++;if(y)l[x]=(l[x]??0)+1}}return{days:e,logsDir:t,homeDir:u1(),totalInWindow:s.length,truncated:s.length>Gn,unreadable:a.count,counts:{blocked:u,allowed:s.length-u,agents:d,blockedByDay:l,analyzedByDay:c,rules:p,commands:g,errors:m},entries:p1(s).sort((f,L)=>new Date(L.ts).getTime()-new Date(f.ts).getTime())}}import{spawn as f1}from"node:child_process";import{existsSync as m1,statSync as Kc}from"node:fs";import{delimiter as g1,join as h1}from"node:path";var y1=120000,Bn="Choose the project folder",L1=`try
251
- return POSIX path of (choose folder with prompt "${Bn}")
246
+ All configs valid.`),0}function cr(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 Ly(e){if(it(e)===null)return null;let t=wy(e);if(t.ruleNames.size===0&&t.errors.length===0)return null;return{path:e.path,result:t}}function wy(e){let t=[],n=new Set,r=(it(e)??[]).filter((o)=>!vy.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(!De.test(o.name)){t.push(`rulebook directory names must match ${De}: ${o.name}`);continue}if(o.kind!=="directory"){t.push(`${o.name} must be a rulebook directory`);continue}let i=x(e.scope,gy(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=Pt(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 ky(){console.log(Md),console.log(hy)}function xy(e,t,n,r){if(console.log(`
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 Cy(e,t,n){if(console.error(`
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 Sy(e,t,n){Gd(`${e} config`,t,n)}function Ry(e,t){console.log(`
249
+ ✓ GitHub source rules: ${e}`),console.log(" Rulebooks:");let n=1;for(let r of t.ruleNames)console.log(` ${n}. ${r}`),n++}function Dy(e,t){Gd("GitHub source rules",e,t)}function Gd(e,t,n){console.error(`
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 Py(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:yy,...n},null,2)),!0}catch(t){if(t instanceof H)throw t;return!1}}var Bd=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),Ey=new Set(["add","remove","list"]),_y="cc-safety-net/rulebooks";async function qd(e){try{return await Ty(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}async function Ty(e){let t=$y(e),n=t.help?Iy(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);Ny(s.configTarget);let a=Ay(s.configDir,"example-rules","rulebook.json"),l=x(s.filesystemScope,a);if(t.example&&w(l)===null)Fr(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=Vd(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 Tr(s,{...i,ref:t.ref,rulebooks:t.only.length>0?t.only:void 0});return Ad(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 $r(o,{...i,deleteSource:t.deleteSource});return ar(s,`Removed rulebook source: ${o}`),s.ok?0:1}if(r==="update"){let s=await Tt({...i,only:o,refresh:!0});return ar(s,"Rule config updated."),s.ok?0:1}if(r==="sync")return Na({global:t.global});if(r==="list"){let s=Pe();return _d(s),s.errors.length>0?1:0}if(r==="wrapper")return Hy(t);if(r==="migrate")return jd({cleanup:t.cleanup,cwd:process.cwd()});if(r==="doc"){console.log(Dd);let s=await Hd();if(s)console.error(s);return 0}if(r==="verify")return Ud();return 1}function Iy(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"?Qr:[],examples:e[0]==="add"?eo:void 0}}function $y(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 Oy(n),n}function Oy(e){let[t]=e.positionals;if(t&&!Bd.has(t))e.errors.push(`Unknown rule subcommand: ${t}`);if(e.deleteSource&&t!=="remove")if(t&&Bd.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")Fy(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")jy(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 Vd(e){if(e.positionals[1])return e.positionals[1];if(e.ref||e.only.length>0)return _y;return}function Fy(e){let t=Vd(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)=>!De.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 jy(e){let t=e.positionals[1],n=e.positionals[2];if(!t){e.errors.push("rule wrapper requires add, remove, or list");return}if(!Ey.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 Ny(e){if(w(e)===null){Or(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 Hy(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 My(a.config?.transparent_wrappers??[]),0}if(!n||!Mr.test(n))return console.error("transparent wrapper must match command pattern"),1;if(Gr(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 My(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 si}from"node:os";import{sep as Ky}from"node:path";import{existsSync as Uy,readFileSync as Gy}from"node:fs";import{homedir as By}from"node:os";import{join as qy}from"node:path";async function Vy(e){if(e.isTTY)return null;return(await Jr(e).catch(()=>null))?.trim()||null}function zy(){if(process.env.CLAUDE_SETTINGS_PATH)return process.env.CLAUDE_SETTINGS_PATH;return qy(By(),".claude","settings.json")}function oi(){let e=zy();if(!Uy(e))return!1;try{let t=Gy(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 ii(e=process.stdin){let t=oi(),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 Vy(e);if(r&&!r.startsWith("{"))console.log(`${r} | ${n}`);else console.log(n)}function zd(){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===si()||p.startsWith(`${si()}${Ky}`)?`~${p.slice(si().length)}`:p,d={ready:y.green,degraded:y.yellow}[e.state],m=e.policyScopes?.weakenings??[],g=[...oi()?[]:["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(`
251
+ `))}import{spawn as uu}from"node:child_process";import{randomBytes as o0}from"node:crypto";import{existsSync as i0}from"node:fs";import{createServer as s0}from"node:http";import{Writable as a0}from"node:stream";import{homedir as Jy}from"node:os";var dr=500;function Wy(e){let t=e.filter((o)=>o.decision!=="allow"),n=e.filter((o)=>o.decision==="allow"),r=Math.min(t.length,Math.max(dr-n.length,Math.ceil(dr/2)));return[...t.slice(0,r),...n.slice(0,dr-r)]}function Kd(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:Jy(),totalInWindow:s.length,truncated:s.length>dr,unreadable:a.count,counts:{blocked:u,allowed:s.length-u,agents:d,blockedByDay:l,analyzedByDay:c,rules:m,commands:g,errors:p},entries:Wy(s).sort((f,b)=>new Date(b.ts).getTime()-new Date(f.ts).getTime())}}import{spawn as Yy}from"node:child_process";import{existsSync as Zy,statSync as Jd}from"node:fs";import{delimiter as Xy,join as Qy}from"node:path";var e0=120000,ur="Choose the project folder",t0=`try
252
+ return POSIX path of (choose folder with prompt "${ur}")
252
253
  on error number -128
253
254
  return ""
254
- end try`,v1=`Add-Type -AssemblyName System.Windows.Forms
255
+ end try`,n0=`Add-Type -AssemblyName System.Windows.Forms
255
256
  $dialog = New-Object System.Windows.Forms.FolderBrowserDialog
256
- $dialog.Description = '${Bn}'
257
- if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Wc=[{binary:"zenity",args:["--file-selection","--directory",`--title=${Bn}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",Bn]}],Jc=(e,t)=>(t.PATH??"").split(g1).some((n)=>{if(n.length===0)return!1;try{let r=Kc(h1(n,e));return r.isFile()&&(r.mode&73)!==0}catch{return!1}});function Yc(e,t){if(e==="darwin"||e==="win32")return!0;if(e!=="linux")return!1;if(!t.DISPLAY&&!t.WAYLAND_DISPLAY)return!1;return Wc.some((n)=>Jc(n.binary,t))}function b1(e,t){if(e==="darwin")return{cmd:"osascript",args:["-e",L1]};if(e==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",v1]};let n=Wc.find((r)=>Jc(r.binary,t));return n?{cmd:n.binary,args:n.args}:null}function Zc(e=process.platform,t=process.env){let n=b1(e,t);if(!n)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((r)=>{let o=f1(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"})},y1);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(!m1(c)||!Kc(c).isDirectory())return a({error:"That selection is not a folder on disk"});a({path:c})})})}var Xc=`<!doctype html>
257
+ $dialog.Description = '${ur}'
258
+ if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Wd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${ur}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",ur]}],Yd=(e,t)=>(t.PATH??"").split(Xy).some((n)=>{if(n.length===0)return!1;try{let r=Jd(Qy(n,e));return r.isFile()&&(r.mode&73)!==0}catch{return!1}});function ai(e,t){if(e==="darwin"||e==="win32")return!0;if(e!=="linux")return!1;if(!t.DISPLAY&&!t.WAYLAND_DISPLAY)return!1;return Wd.some((n)=>Yd(n.binary,t))}function r0(e,t){if(e==="darwin")return{cmd:"osascript",args:["-e",t0]};if(e==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",n0]};let n=Wd.find((r)=>Yd(r.binary,t));return n?{cmd:n.binary,args:n.args}:null}function li(e=process.platform,t=process.env){let n=r0(e,t);if(!n)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((r)=>{let o=Yy(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"})},e0);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(!Zy(c)||!Jd(c).isDirectory())return a({error:"That selection is not a folder on disk"});a({path:c})})})}var Zd=`<!doctype html>
258
259
  <html lang="en">
259
260
  <head>
260
261
  <meta charset="utf-8">
@@ -1584,6 +1585,144 @@ button.rule-id:hover {
1584
1585
  width: min(680px, calc(100vw - 32px));
1585
1586
  }
1586
1587
 
1588
+ /* The before/after rows need more room than a text-only confirmation. */
1589
+ .confirm-dialog:has(.dialog-rows:not([hidden])) {
1590
+ width: min(620px, calc(100vw - 32px));
1591
+ }
1592
+
1593
+ .dialog-rows {
1594
+ max-height: 46vh;
1595
+ overflow: auto;
1596
+ }
1597
+
1598
+ .diff-table {
1599
+ width: 100%;
1600
+ border-collapse: collapse;
1601
+ font-size: 12px;
1602
+ text-align: left;
1603
+ }
1604
+
1605
+ .diff-table th {
1606
+ padding: 4px 8px;
1607
+ border-bottom: 1px solid var(--border);
1608
+ color: var(--muted);
1609
+ font-weight: 600;
1610
+ }
1611
+
1612
+ .diff-table td {
1613
+ padding: 5px 8px;
1614
+ border-bottom: 1px solid var(--border);
1615
+ overflow-wrap: anywhere;
1616
+ vertical-align: top;
1617
+ }
1618
+
1619
+ .diff-table code {
1620
+ font-family: var(--font-mono);
1621
+ font-size: 11.5px;
1622
+ }
1623
+
1624
+ .diff-before {
1625
+ color: var(--muted);
1626
+ text-decoration: line-through;
1627
+ }
1628
+
1629
+ .diff-after {
1630
+ color: var(--ink);
1631
+ font-weight: 650;
1632
+ }
1633
+
1634
+ .diff-warning {
1635
+ margin: 8px 0 0;
1636
+ padding: 7px 10px;
1637
+ border-left: 3px solid var(--warn-border);
1638
+ border-radius: var(--radius-sm);
1639
+ background: var(--warn-bg);
1640
+ color: var(--warn-fg);
1641
+ font-size: 12px;
1642
+ }
1643
+
1644
+ .view-head-actions {
1645
+ display: flex;
1646
+ align-items: center;
1647
+ justify-content: space-between;
1648
+ gap: 12px;
1649
+ }
1650
+
1651
+ .project-draft-bar {
1652
+ display: flex;
1653
+ align-items: center;
1654
+ justify-content: space-between;
1655
+ gap: 16px;
1656
+ padding: 12px 14px;
1657
+ border: 1px solid var(--master-border);
1658
+ border-radius: var(--radius);
1659
+ background: var(--master-bg);
1660
+ }
1661
+
1662
+ .project-draft-bar[hidden] {
1663
+ display: none;
1664
+ }
1665
+
1666
+ .project-draft-target strong {
1667
+ display: block;
1668
+ font-size: 13px;
1669
+ }
1670
+
1671
+ .project-draft-target code {
1672
+ font-family: var(--font-mono);
1673
+ font-size: 12px;
1674
+ overflow-wrap: anywhere;
1675
+ }
1676
+
1677
+ .project-draft-target p {
1678
+ margin: 4px 0 0;
1679
+ font-size: 12px;
1680
+ }
1681
+
1682
+ /* Says whose value a control is showing: the project's, or the one it inherits
1683
+ from each member's own user policy. */
1684
+ .project-chip {
1685
+ flex: none;
1686
+ align-self: center;
1687
+ margin-left: auto;
1688
+ padding: 2px 9px;
1689
+ border: 1px solid var(--master-border);
1690
+ border-radius: 999px;
1691
+ background: var(--master-bg);
1692
+ color: var(--master-fg);
1693
+ font-size: 11px;
1694
+ font-weight: 700;
1695
+ white-space: nowrap;
1696
+ }
1697
+
1698
+ .project-chip.inherited {
1699
+ border-color: var(--border);
1700
+ background: var(--surface-2);
1701
+ color: var(--muted);
1702
+ font-weight: 600;
1703
+ }
1704
+
1705
+ .rule-row > .project-chip {
1706
+ grid-column: 1 / -1;
1707
+ justify-self: end;
1708
+ margin-left: 0;
1709
+ }
1710
+
1711
+ .project-field-line {
1712
+ grid-column: 1 / -1;
1713
+ display: flex;
1714
+ justify-content: flex-end;
1715
+ }
1716
+
1717
+ .project-chip-slot:empty {
1718
+ display: none;
1719
+ }
1720
+
1721
+ /* An inherited control is showing someone else's value, so it reads quieter. */
1722
+ .row:has(.project-chip.inherited) strong {
1723
+ color: var(--muted);
1724
+ }
1725
+
1587
1726
  .report-field {
1588
1727
  display: grid;
1589
1728
  gap: 6px;
@@ -2773,9 +2912,22 @@ M 1506 121 L 1499 127 L 1497 131 L 1497 138 L 1496 139 L 1496 143 L 1495 144 L 1
2773
2912
  </section>
2774
2913
 
2775
2914
  <section class="view" data-view="policy" hidden>
2776
- <div class="view-head">
2915
+ <div class="view-head view-head-actions">
2777
2916
  <p class="panel-sub muted">Choose what CC Safety Net blocks. Changes apply after you save.</p>
2917
+ <button type="button" id="project-draft-enter">Draft project policy</button>
2778
2918
  </div>
2919
+ <div class="project-draft-bar" id="project-draft-bar" hidden>
2920
+ <div class="project-draft-target">
2921
+ <strong>Project policy draft</strong>
2922
+ <code id="project-draft-path"></code>
2923
+ <p class="muted">Only the fields you mark are written here; everything else keeps inheriting from each member's own policy.</p>
2924
+ </div>
2925
+ <div class="savebar-actions">
2926
+ <button type="button" id="project-draft-change" hidden>Change…</button>
2927
+ <button type="button" id="project-draft-exit">Exit draft</button>
2928
+ </div>
2929
+ </div>
2930
+ <p class="status error" id="project-draft-diagnostics" hidden></p>
2779
2931
  <div class="policy-savebar" id="policy-savebar" hidden><span>Unsaved changes</span><div class="savebar-actions"><button type="button" id="discard-changes">Discard</button><button class="primary" id="save">Save</button></div></div>
2780
2932
  <div class="recovery" id="recovery" hidden>
2781
2933
  <div>
@@ -2840,6 +2992,16 @@ M 1506 121 L 1499 127 L 1497 131 L 1497 138 L 1496 139 L 1496 143 L 1495 144 L 1
2840
2992
  </header>
2841
2993
  <div id="secret"></div>
2842
2994
  </section>
2995
+ <section class="panel">
2996
+ <div class="panel-head raw-json-head">
2997
+ <div class="panel-title">
2998
+ <h2>Policy JSON</h2>
2999
+ <p class="panel-sub muted" id="raw-source">Read-only mirror of the policy controls.</p>
3000
+ </div>
3001
+ <button class="icon-button" id="raw-copy" type="button" aria-label="Copy raw JSON to clipboard"></button>
3002
+ </div>
3003
+ <textarea id="raw" aria-label="Raw policy JSON" aria-describedby="raw-source" readonly></textarea>
3004
+ </section>
2843
3005
  </section>
2844
3006
 
2845
3007
  <section class="view" data-view="rules" hidden>
@@ -2871,7 +3033,7 @@ M 1506 121 L 1499 127 L 1497 131 L 1497 138 L 1496 139 L 1496 143 L 1495 144 L 1
2871
3033
  <div class="field">
2872
3034
  <span id="rules-composer-label">Request</span>
2873
3035
  <textarea id="rules-composer-input" spellcheck="false" placeholder="Describe the custom rules you want..." aria-labelledby="rules-composer-label" aria-describedby="rules-composer-hint"></textarea>
2874
- <small id="rules-composer-hint">Rules match a command, an optional subcommand, and exact arguments - not file paths or patterns.</small>
3036
+ <small id="rules-composer-hint">Rules match a command, its subcommand path, and exact arguments - not file paths or patterns.</small>
2875
3037
  </div>
2876
3038
  <div class="field">
2877
3039
  <span>Examples</span>
@@ -2928,8 +3090,10 @@ M 1506 121 L 1499 127 L 1497 131 L 1497 138 L 1496 139 L 1496 143 L 1495 144 L 1
2928
3090
  </div>
2929
3091
  <div class="info-rows">
2930
3092
  <div class="info-row"><span>Policy file</span><code id="policy-path"></code></div>
3093
+ <div class="info-row" id="project-policy-row" hidden><span>Project policy</span><code id="project-policy-path"></code></div>
2931
3094
  <div class="info-row"><span>Audit logs</span><code id="logs-path"></code></div>
2932
3095
  </div>
3096
+ <p class="status" id="project-policy-notice" hidden></p>
2933
3097
  </section>
2934
3098
  <section class="panel">
2935
3099
  <div class="panel-head">
@@ -2945,16 +3109,6 @@ M 1506 121 L 1499 127 L 1497 131 L 1497 138 L 1496 139 L 1496 143 L 1495 144 L 1
2945
3109
  </label>
2946
3110
  <p class="muted retention-note" id="retention-note"></p>
2947
3111
  </section>
2948
- <section class="panel">
2949
- <div class="panel-head raw-json-head">
2950
- <div class="panel-title">
2951
- <h2>Policy JSON</h2>
2952
- <p class="panel-sub muted" id="raw-source">Read-only mirror of the policy controls.</p>
2953
- </div>
2954
- <button class="icon-button" id="raw-copy" type="button" aria-label="Copy raw JSON to clipboard"></button>
2955
- </div>
2956
- <textarea id="raw" aria-label="Raw policy JSON" aria-describedby="raw-source" readonly></textarea>
2957
- </section>
2958
3112
  <section class="panel">
2959
3113
  <div class="panel-head">
2960
3114
  <div class="panel-title">
@@ -3026,6 +3180,7 @@ M 1506 121 L 1499 127 L 1497 131 L 1497 138 L 1496 139 L 1496 143 L 1495 144 L 1
3026
3180
  <form method="dialog">
3027
3181
  <h2 id="confirm-dialog-title"></h2>
3028
3182
  <p class="muted" id="confirm-dialog-body"></p>
3183
+ <div class="dialog-rows" id="confirm-dialog-rows" hidden></div>
3029
3184
  <p class="dialog-detail"><code id="confirm-dialog-detail"></code></p>
3030
3185
  <div class="dialog-actions">
3031
3186
  <button type="submit" id="confirm-dialog-cancel" value="cancel">Cancel</button>
@@ -3279,6 +3434,13 @@ var runtimeHookIntegrationMetadata = catalog.filter((integration) => ("runtime"
3279
3434
  var installIntegrationMetadata = catalog.slice().sort((a, b) => a.install.order - b.install.order).map((integration) => ({ id: integration.id, ...integration.install })).map(({ order: _, ...integration }) => integration);
3280
3435
  var integrationDisplayNames = Object.fromEntries(catalog.map((integration) => [integration.id, integration.displayName]));
3281
3436
 
3437
+ // src/ir/safety-level.ts
3438
+ var SAFETY_LEVEL_CAPABILITIES = {
3439
+ standard: { fail_closed: false, paranoid_rm: false, paranoid_interpreters: false },
3440
+ strict: { fail_closed: true, paranoid_rm: false, paranoid_interpreters: false },
3441
+ paranoid: { fail_closed: true, paranoid_rm: true, paranoid_interpreters: true }
3442
+ };
3443
+
3282
3444
  // src/gui/frontend/main.ts
3283
3445
  var token = JSON.parse(document.getElementById("ccsn-data").textContent).token;
3284
3446
  var fallbackRepoUrl = "https://github.com/kenryu42/cc-safety-net";
@@ -3316,6 +3478,8 @@ var pathListIcons = {
3316
3478
  };
3317
3479
  var state;
3318
3480
  var draftPolicy;
3481
+ var projectDraft = null;
3482
+ var markedFields = new Set;
3319
3483
  var preview;
3320
3484
  var previewRequestId = 0;
3321
3485
  var dirty = false;
@@ -3435,6 +3599,85 @@ var pathLines = (value) => value.split(\`
3435
3599
  \`).map((line) => line.trim()).filter(Boolean);
3436
3600
  var formatPolicy = (policy) => \`\${JSON.stringify(policy, null, 2)}
3437
3601
  \`;
3602
+ var markedOverrides = (marked, section, overrides) => Object.fromEntries(Object.entries(overrides).filter(([key, value]) => value !== undefined && marked.has(\`\${section}.overrides.\${key}\`)));
3603
+ var withOverrides = (overrides) => Object.keys(overrides).length > 0 ? { overrides } : {};
3604
+ var collectProjectProposal = (marked, policy) => {
3605
+ const sections = {
3606
+ safety: {
3607
+ ...marked.has("safety.level") ? { level: policy.safety.level } : {},
3608
+ ...withOverrides(markedOverrides(marked, "safety", policy.safety.overrides))
3609
+ },
3610
+ workflow: marked.has("workflow.worktree_mode") ? { worktree_mode: policy.workflow.worktree_mode } : {},
3611
+ destructive_command_protection: {
3612
+ ...marked.has("destructive_command_protection.enabled") ? { enabled: policy.destructive_command_protection.enabled } : {},
3613
+ ...withOverrides(markedOverrides(marked, "destructive_command_protection", policy.destructive_command_protection.overrides)),
3614
+ ...marked.has("destructive_command_protection.allow_paths") ? { allow_paths: policy.destructive_command_protection.allow_paths } : {}
3615
+ },
3616
+ secret_protection: {
3617
+ ...marked.has("secret_protection.enabled") ? { enabled: policy.secret_protection.enabled } : {},
3618
+ ...withOverrides(markedOverrides(marked, "secret_protection", policy.secret_protection.overrides)),
3619
+ ...marked.has("secret_protection.deny_paths") ? { deny_paths: policy.secret_protection.deny_paths } : {},
3620
+ ...marked.has("secret_protection.allow_paths") ? { allow_paths: policy.secret_protection.allow_paths } : {}
3621
+ }
3622
+ };
3623
+ return {
3624
+ version: 1,
3625
+ ...Object.fromEntries(Object.entries(sections).filter(([, fields]) => Object.keys(fields).length > 0))
3626
+ };
3627
+ };
3628
+ var projectMarkedFields = (projection) => {
3629
+ const destructive = projection.destructive_command_protection ?? {};
3630
+ const secret = projection.secret_protection ?? {};
3631
+ return [
3632
+ ...projection.safety?.level === undefined ? [] : ["safety.level"],
3633
+ ...Object.keys(projection.safety?.overrides ?? {}).map((key) => \`safety.overrides.\${key}\`),
3634
+ ...projection.workflow?.worktree_mode === undefined ? [] : ["workflow.worktree_mode"],
3635
+ ...destructive.enabled === undefined ? [] : ["destructive_command_protection.enabled"],
3636
+ ...Object.keys(destructive.overrides ?? {}).map((id) => \`destructive_command_protection.overrides.\${id}\`),
3637
+ ...destructive.allow_paths === undefined ? [] : ["destructive_command_protection.allow_paths"],
3638
+ ...secret.enabled === undefined ? [] : ["secret_protection.enabled"],
3639
+ ...Object.keys(secret.overrides ?? {}).map((id) => \`secret_protection.overrides.\${id}\`),
3640
+ ...secret.deny_paths === undefined ? [] : ["secret_protection.deny_paths"],
3641
+ ...secret.allow_paths === undefined ? [] : ["secret_protection.allow_paths"]
3642
+ ];
3643
+ };
3644
+ var overlayProjectProposal = (baseline, proposal) => {
3645
+ const displayed = clonePolicy(baseline);
3646
+ const destructive = proposal.destructive_command_protection ?? {};
3647
+ const secret = proposal.secret_protection ?? {};
3648
+ if (proposal.safety?.level)
3649
+ displayed.safety.level = proposal.safety.level;
3650
+ Object.assign(displayed.safety.overrides, proposal.safety?.overrides ?? {});
3651
+ if (proposal.workflow?.worktree_mode !== undefined)
3652
+ displayed.workflow.worktree_mode = proposal.workflow.worktree_mode;
3653
+ if (destructive.enabled !== undefined)
3654
+ displayed.destructive_command_protection.enabled = destructive.enabled;
3655
+ Object.assign(displayed.destructive_command_protection.overrides, destructive.overrides ?? {});
3656
+ if (destructive.allow_paths)
3657
+ displayed.destructive_command_protection.allow_paths = destructive.allow_paths;
3658
+ if (secret.enabled !== undefined)
3659
+ displayed.secret_protection.enabled = secret.enabled;
3660
+ Object.assign(displayed.secret_protection.overrides, secret.overrides ?? {});
3661
+ if (secret.deny_paths)
3662
+ displayed.secret_protection.deny_paths = secret.deny_paths;
3663
+ if (secret.allow_paths)
3664
+ displayed.secret_protection.allow_paths = secret.allow_paths;
3665
+ return displayed;
3666
+ };
3667
+ var seedProjectDraft = (data) => {
3668
+ if (!data.baseline)
3669
+ return null;
3670
+ if (!Array.isArray(data.userPolicyDiagnostics) || data.userPolicyDiagnostics.length > 0)
3671
+ return null;
3672
+ const marked = new Set(projectMarkedFields(data.projection ?? {}));
3673
+ const policy = overlayProjectProposal(data.baseline, data.projection ?? {});
3674
+ return {
3675
+ baseline: data.baseline,
3676
+ marked,
3677
+ policy,
3678
+ snapshot: JSON.stringify(collectProjectProposal(marked, policy))
3679
+ };
3680
+ };
3438
3681
  var collectFormPolicy = () => ({
3439
3682
  version: 1,
3440
3683
  safety: {
@@ -3451,10 +3694,71 @@ var collectFormPolicy = () => ({
3451
3694
  },
3452
3695
  audit: draftPolicy.audit
3453
3696
  });
3697
+ var effectivePreviewPolicy = (policy, baseline) => {
3698
+ if (!baseline)
3699
+ return policy;
3700
+ const union = (user, project) => [...new Set([...user, ...project])];
3701
+ return {
3702
+ ...policy,
3703
+ destructive_command_protection: {
3704
+ ...policy.destructive_command_protection,
3705
+ allow_paths: union(baseline.destructive_command_protection.allow_paths, policy.destructive_command_protection.allow_paths)
3706
+ },
3707
+ secret_protection: {
3708
+ ...policy.secret_protection,
3709
+ deny_paths: union(baseline.secret_protection.deny_paths, policy.secret_protection.deny_paths),
3710
+ allow_paths: union(baseline.secret_protection.allow_paths, policy.secret_protection.allow_paths)
3711
+ }
3712
+ };
3713
+ };
3454
3714
  var requestPolicyPreview = (policy = collectFormPolicy()) => requestJson("/api/policy/preview", {
3455
3715
  method: "POST",
3456
3716
  body: JSON.stringify(policy)
3457
3717
  });
3718
+ var policyScopeMode = () => projectDraft ? "project" : "user";
3719
+ var projectFieldChip = (field, compact = false) => {
3720
+ if (policyScopeMode() !== "project")
3721
+ return "";
3722
+ if (!markedFields.has(field))
3723
+ return '<span class="project-chip inherited">Inherited</span>';
3724
+ return \`<button type="button" class="project-chip" data-unmark-field="\${escapeHtml(field)}" title="Set by project - click to inherit again" aria-label="Set by project: \${escapeHtml(field)}. Activate to inherit again.">\${compact ? "Project" : "Set by project"}</button>\`;
3725
+ };
3726
+ var projectFieldLine = (field) => {
3727
+ const chip = projectFieldChip(field);
3728
+ return chip ? \`<div class="project-field-line">\${chip}</div>\` : "";
3729
+ };
3730
+ var projectChipSlots = [
3731
+ ["destructive-enabled-chip", "destructive_command_protection.enabled"],
3732
+ ["secret-enabled-chip", "secret_protection.enabled"],
3733
+ ["allow-paths-chip", "destructive_command_protection.allow_paths"],
3734
+ ["deny-paths-chip", "secret_protection.deny_paths"],
3735
+ ["secret-allow-paths-chip", "secret_protection.allow_paths"]
3736
+ ];
3737
+ var syncProjectChips = () => {
3738
+ projectChipSlots.forEach(([id, field]) => {
3739
+ qs(id).innerHTML = projectFieldChip(field);
3740
+ });
3741
+ };
3742
+ var markProjectField = (field) => {
3743
+ if (!projectDraft || markedFields.has(field))
3744
+ return;
3745
+ markedFields.add(field);
3746
+ renderSafety();
3747
+ syncProjectChips();
3748
+ };
3749
+ var rebuildProjectDisplay = () => {
3750
+ if (!projectDraft)
3751
+ return;
3752
+ draftPolicy = overlayProjectProposal(projectDraft.baseline, collectProjectProposal(markedFields, draftPolicy));
3753
+ renderPolicySections();
3754
+ refreshPolicyPreview();
3755
+ };
3756
+ var unmarkProjectField = (field) => {
3757
+ if (!projectDraft || !markedFields.has(field))
3758
+ return;
3759
+ markedFields.delete(field);
3760
+ rebuildProjectDisplay();
3761
+ };
3458
3762
  var viewNames = ["overview", "activity", "policy", "rules", "integrations", "settings"];
3459
3763
  var viewTitles = {
3460
3764
  overview: "Overview",
@@ -3588,7 +3892,7 @@ var renderProtectionCard = () => {
3588
3892
  return;
3589
3893
  }
3590
3894
  const policy = state.policy;
3591
- const customized = state.preview.counts.effectiveCustomizations > 0 || Object.entries(policy.safety.overrides).some(([key, value]) => value !== levelCapabilities(policy.safety.level)[key]);
3895
+ const customized = state.preview.counts.effectiveCustomizations > 0 || Object.entries(policy.safety.overrides).some(([key, value]) => value !== SAFETY_LEVEL_CAPABILITIES[policy.safety.level][key]);
3592
3896
  const commandsOn = policy.destructive_command_protection.enabled;
3593
3897
  const secretsOn = policy.secret_protection.enabled;
3594
3898
  const off = [
@@ -3991,6 +4295,8 @@ var confirmDialog = (() => {
3991
4295
  const detailRow = qs("confirm-dialog-detail").parentElement;
3992
4296
  if (detailRow)
3993
4297
  detailRow.hidden = !options.detail;
4298
+ qs("confirm-dialog-rows").innerHTML = options.rowsHtml ?? "";
4299
+ qs("confirm-dialog-rows").hidden = !options.rowsHtml;
3994
4300
  confirm.textContent = options.confirmLabel;
3995
4301
  confirm.className = options.confirmClass ?? "danger";
3996
4302
  dialog.returnValue = "cancel";
@@ -4024,6 +4330,10 @@ var syncSearchState = () => {
4024
4330
  searchCollapsedSecretGroups.clear();
4025
4331
  };
4026
4332
  var updateRawSource = () => {
4333
+ if (projectDraft) {
4334
+ qs("raw-source").textContent = \`Only the fields marked for this project. Writes to \${projectDraft.path}.\`;
4335
+ return;
4336
+ }
4027
4337
  qs("raw-source").textContent = state?.errors.length ? "Read-only original policy JSON. Repair preserves valid settings and writes canonical JSON." : "Read-only mirror of the controls.";
4028
4338
  };
4029
4339
  var setRawCopyCopied = (copied) => {
@@ -4201,12 +4511,20 @@ var loadStarContext = async () => {
4201
4511
  var syncRawFromForm = () => {
4202
4512
  if (state?.errors.length)
4203
4513
  return;
4204
- qs("raw").value = formatPolicy(collectFormPolicy());
4514
+ qs("raw").value = formatPolicy(projectDraft ? collectProjectProposal(markedFields, draftPolicy) : collectFormPolicy());
4205
4515
  updateRawSource();
4206
4516
  };
4207
4517
  var updateDirtyStatus = () => {
4208
4518
  if (!state || state.errors.length)
4209
4519
  return;
4520
+ if (projectDraft) {
4521
+ dirty = JSON.stringify(collectProjectProposal(markedFields, draftPolicy)) !== projectDraft.snapshot;
4522
+ qs("policy-savebar").hidden = !dirty;
4523
+ qs("dirty-chip").hidden = !dirty || currentView() === "policy";
4524
+ setDetailStatus("");
4525
+ updateActions();
4526
+ return;
4527
+ }
4210
4528
  const draftJson = JSON.stringify(collectFormPolicy());
4211
4529
  dirty = draftJson !== JSON.stringify(state.policy);
4212
4530
  qs("policy-savebar").hidden = !dirty;
@@ -4234,6 +4552,13 @@ var createPathList = (prefix, config) => {
4234
4552
  <button type="button" class="icon-button" data-path-list="\${prefix}" data-path-remove="\${index}" \${disabled ? "disabled" : ""} aria-label="Remove \${config.itemLabel} \${escapeHtml(path)}">\${pathListIcons.remove}</button>
4235
4553
  </li>\`).join("");
4236
4554
  };
4555
+ const claimForProject = () => {
4556
+ if (!projectDraft || markedFields.has(config.field))
4557
+ return;
4558
+ markedFields.add(config.field);
4559
+ config.setPaths([]);
4560
+ syncProjectChips();
4561
+ };
4237
4562
  let adding = false;
4238
4563
  const add = async (value) => {
4239
4564
  if (adding)
@@ -4241,14 +4566,25 @@ var createPathList = (prefix, config) => {
4241
4566
  const entries = [...new Set(pathLines(value))];
4242
4567
  if (entries.length === 0)
4243
4568
  return;
4569
+ const scope = projectDraft;
4570
+ const claimed = projectDraft !== null && !markedFields.has(config.field);
4571
+ const previousPaths = config.getPaths();
4572
+ claimForProject();
4244
4573
  const submitted = qs(\`\${prefix}-input\`).value;
4245
4574
  const additions = entries.filter((entry) => !config.getPaths().includes(entry));
4246
4575
  if (config.validateAdditions && additions.length) {
4247
4576
  adding = true;
4248
4577
  try {
4249
4578
  const error = await config.validateAdditions([...config.getPaths(), ...additions]);
4579
+ if (projectDraft !== scope)
4580
+ return;
4250
4581
  if (error) {
4251
4582
  setHint(\`Not added: \${additions.join(", ")} — \${error}\`);
4583
+ if (claimed) {
4584
+ markedFields.delete(config.field);
4585
+ config.setPaths(previousPaths);
4586
+ syncProjectChips();
4587
+ }
4252
4588
  return;
4253
4589
  }
4254
4590
  } finally {
@@ -4267,6 +4603,7 @@ var createPathList = (prefix, config) => {
4267
4603
  qs(\`\${prefix}-input\`).focus();
4268
4604
  };
4269
4605
  const remove = (index) => {
4606
+ claimForProject();
4270
4607
  config.setPaths(config.getPaths().filter((_, position) => position !== index));
4271
4608
  setHint("");
4272
4609
  render();
@@ -4285,6 +4622,7 @@ var validatePathAdditions = async (patch) => {
4285
4622
  };
4286
4623
  var pathLists = {
4287
4624
  "deny-paths": createPathList("deny-paths", {
4625
+ field: "secret_protection.deny_paths",
4288
4626
  getPaths: () => draftPolicy.secret_protection.deny_paths,
4289
4627
  setPaths: (paths) => {
4290
4628
  draftPolicy.secret_protection.deny_paths = paths;
@@ -4296,6 +4634,7 @@ var pathLists = {
4296
4634
  })
4297
4635
  }),
4298
4636
  "secret-allow-paths": createPathList("secret-allow-paths", {
4637
+ field: "secret_protection.allow_paths",
4299
4638
  getPaths: () => draftPolicy.secret_protection.allow_paths,
4300
4639
  setPaths: (paths) => {
4301
4640
  draftPolicy.secret_protection.allow_paths = paths;
@@ -4307,6 +4646,7 @@ var pathLists = {
4307
4646
  })
4308
4647
  }),
4309
4648
  "allow-paths": createPathList("allow-paths", {
4649
+ field: "destructive_command_protection.allow_paths",
4310
4650
  getPaths: () => draftPolicy.destructive_command_protection.allow_paths,
4311
4651
  setPaths: (paths) => {
4312
4652
  draftPolicy.destructive_command_protection.allow_paths = paths;
@@ -4323,12 +4663,29 @@ var pathLists = {
4323
4663
  };
4324
4664
  var pathListFor = (name) => name === "deny-paths" || name === "allow-paths" || name === "secret-allow-paths" ? pathLists[name] : null;
4325
4665
  var secretRuleIsActive = (rule, overrides) => overrides[rule.id] ? overrides[rule.id] === "on" : !rule.defaultOff;
4666
+ var markProjectOverride = (section, ruleId) => {
4667
+ if (!projectDraft)
4668
+ return;
4669
+ markedFields.add(\`\${section}.overrides.\${ruleId}\`);
4670
+ };
4671
+ var clearProjectOverrideMarks = (section) => {
4672
+ markedFields = new Set([...markedFields].filter((field) => !field.startsWith(\`\${section}.overrides.\`)));
4673
+ };
4326
4674
  var setSecretOverride = (rule, active) => {
4327
- if (active === !rule.defaultOff) {
4675
+ if (!projectDraft && active === !rule.defaultOff) {
4328
4676
  delete draftPolicy.secret_protection.overrides[rule.id];
4329
4677
  return;
4330
4678
  }
4331
4679
  draftPolicy.secret_protection.overrides[rule.id] = active ? "on" : "off";
4680
+ markProjectOverride("secret_protection", rule.id);
4681
+ };
4682
+ var setDestructiveOverride = (ruleId, active, inheritedEnabled) => {
4683
+ if (!projectDraft && active === inheritedEnabled) {
4684
+ delete draftPolicy.destructive_command_protection.overrides[ruleId];
4685
+ return;
4686
+ }
4687
+ draftPolicy.destructive_command_protection.overrides[ruleId] = active ? "on" : "off";
4688
+ markProjectOverride("destructive_command_protection", ruleId);
4332
4689
  };
4333
4690
  var groupRules = (rules) => rules.reduce((groups, rule) => {
4334
4691
  const group = groups.find((item) => item.category === rule.category);
@@ -4377,12 +4734,14 @@ var renderSecretPatterns = () => {
4377
4734
  <button type="button" class="rule-id" data-rule-activity="\${escapeHtml(rule.id)}" title="Show recent blocks in Activity">\${escapeHtml(rule.id)}</button>
4378
4735
  <small><span class="\${ruleState.className}">\${ruleState.label}</span> \${escapeHtml(rule.description ?? "")}</small>
4379
4736
  </span>\`;
4737
+ const chip = projectFieldChip(\`secret_protection.overrides.\${rule.id}\`, true);
4380
4738
  if (!rule.paths) {
4381
- return \`<label class="row \${disabled ? "row-disabled" : ""}">\${control}</label>\`;
4739
+ return \`<label class="row \${disabled ? "row-disabled" : ""}">\${control}\${chip}</label>\`;
4382
4740
  }
4383
4741
  return \`<div class="row rule-row \${disabled ? "row-disabled" : ""}">
4384
4742
  <label class="rule-control">\${control}</label>
4385
4743
  <button type="button" class="rule-example-button" data-secret-paths="\${escapeHtml(rule.id)}" aria-label="\${escapeHtml(\`Show protected paths for \${rule.label}\`)}" aria-haspopup="dialog" aria-controls="rule-example-popover">?</button>
4744
+ \${chip}
4386
4745
  </div>\`;
4387
4746
  }).join("")}</div>
4388
4747
  </div>
@@ -4390,16 +4749,11 @@ var renderSecretPatterns = () => {
4390
4749
  \`;
4391
4750
  }).join("");
4392
4751
  };
4393
- var levelCapabilities = (level) => ({
4394
- fail_closed: level === "strict" || level === "paranoid",
4395
- paranoid_rm: level === "paranoid",
4396
- paranoid_interpreters: level === "paranoid"
4397
- });
4398
4752
  var presetName = () => safetyLevels[draftPolicy.safety.level][0];
4399
4753
  var renderPresetStatus = () => {
4400
4754
  if (!preview)
4401
4755
  return;
4402
- const customized = preview.counts.effectiveCustomizations > 0 || Object.entries(draftPolicy.safety.overrides).some(([key, value]) => value !== levelCapabilities(draftPolicy.safety.level)[key]);
4756
+ const customized = preview.counts.effectiveCustomizations > 0 || Object.entries(draftPolicy.safety.overrides).some(([key, value]) => value !== SAFETY_LEVEL_CAPABILITIES[draftPolicy.safety.level][key]);
4403
4757
  qs("safety-preset-status").textContent = customized ? \`\${presetName()} · Customized\` : "";
4404
4758
  qs("safety-preset-status").classList.toggle("customized", customized);
4405
4759
  };
@@ -4409,8 +4763,8 @@ var renderSafety = () => {
4409
4763
  ] : [];
4410
4764
  qs("environment-overrides").hidden = environmentSources.length === 0;
4411
4765
  qs("environment-overrides").textContent = environmentSources.length ? \`Environment-raised protection: \${environmentSources.join(", ")}\` : "";
4412
- qs("safety-level").innerHTML = Object.entries(safetyLevels).map(([level, meta]) => \`<label class="row preset-\${level}"><input type="radio" name="safety-level" value="\${level}" \${checkbox(draftPolicy.safety.level === level)}><span><strong>\${meta[0]}</strong><small>\${meta[1]}</small></span></label>\`).join("");
4413
- const inherited = levelCapabilities(draftPolicy.safety.level);
4766
+ qs("safety-level").innerHTML = projectFieldLine("safety.level") + Object.entries(safetyLevels).map(([level, meta]) => \`<label class="row preset-\${level}"><input type="radio" name="safety-level" value="\${level}" \${checkbox(draftPolicy.safety.level === level)}><span><strong>\${meta[0]}</strong><small>\${meta[1]}</small></span></label>\`).join("");
4767
+ const inherited = SAFETY_LEVEL_CAPABILITIES[draftPolicy.safety.level];
4414
4768
  qs("safety-overrides").innerHTML = Object.entries(safetyOverrides).map(([key, meta]) => {
4415
4769
  const value = draftPolicy.safety.overrides[key];
4416
4770
  const inheritedText = inherited[key] ? "on" : "off";
@@ -4418,9 +4772,9 @@ var renderSafety = () => {
4418
4772
  <option value="inherit" \${value === undefined ? "selected" : ""}>Inherit from preset (\${inheritedText})</option>
4419
4773
  <option value="true" \${value === true ? "selected" : ""}>Force on</option>
4420
4774
  <option value="false" \${value === false ? "selected" : ""}>Force off</option>
4421
- </select></label>\`;
4775
+ </select>\${projectFieldChip(\`safety.overrides.\${key}\`, true)}</label>\`;
4422
4776
  }).join("");
4423
- qs("workflow").innerHTML = \`<label class="row"><input type="checkbox" data-workflow-worktree \${checkbox(draftPolicy.workflow.worktree_mode)}><span><strong>Allow discarding local changes in linked git worktrees</strong><small>Only relaxes linked worktree discard checks.</small></span></label>\`;
4777
+ qs("workflow").innerHTML = \`<label class="row"><input type="checkbox" data-workflow-worktree \${checkbox(draftPolicy.workflow.worktree_mode)}><span><strong>Allow discarding local changes in linked git worktrees</strong><small>Only relaxes linked worktree discard checks.</small></span>\${projectFieldChip("workflow.worktree_mode")}</label>\`;
4424
4778
  renderPresetStatus();
4425
4779
  };
4426
4780
  var tierForRule = (rule) => {
@@ -4559,6 +4913,7 @@ var renderDestructiveCommands = () => {
4559
4913
  </label>
4560
4914
  <button type="button" class="rule-example-button" data-rule-example="\${escapeHtml(rule.id)}" aria-label="\${escapeHtml(\`Show blocked example for \${rule.label}\`)}" aria-haspopup="dialog" aria-controls="rule-example-popover">?</button>
4561
4915
  \${override && !effective.changesInherited ? \`<button type="button" class="inherit-button" data-use-inherited="\${escapeHtml(rule.id)}">Use inherited setting</button>\` : ""}
4916
+ \${projectFieldChip(\`destructive_command_protection.overrides.\${rule.id}\`, true)}
4562
4917
  </div>\`;
4563
4918
  }).join("")}</div>
4564
4919
  </section>\`).join("")}
@@ -4568,7 +4923,7 @@ var renderDestructiveCommands = () => {
4568
4923
  };
4569
4924
  var refreshPolicyPreview = async () => {
4570
4925
  const requestId = ++previewRequestId;
4571
- const result = await requestPolicyPreview();
4926
+ const result = await requestPolicyPreview(effectivePreviewPolicy(collectFormPolicy(), projectDraft?.baseline ?? null));
4572
4927
  if (requestId !== previewRequestId)
4573
4928
  return false;
4574
4929
  if (!result.ok || !result.data?.preview) {
@@ -4593,7 +4948,10 @@ var runCommandTest = async () => {
4593
4948
  const requestId = ++testerRequestId;
4594
4949
  const result = await requestJson("/api/policy/explain", {
4595
4950
  method: "POST",
4596
- body: JSON.stringify({ command, policy: collectFormPolicy() })
4951
+ body: JSON.stringify({
4952
+ command,
4953
+ policy: effectivePreviewPolicy(collectFormPolicy(), projectDraft?.baseline ?? null)
4954
+ })
4597
4955
  });
4598
4956
  if (requestId !== testerRequestId)
4599
4957
  return;
@@ -4625,10 +4983,16 @@ function render() {
4625
4983
  qs("policy-savebar").hidden = true;
4626
4984
  qs("dirty-chip").hidden = true;
4627
4985
  qs("policy-path").textContent = state.path + (state.exists ? "" : " (not created yet)");
4986
+ const projectPolicy = state.projectPolicy;
4987
+ qs("project-policy-row").hidden = !projectPolicy;
4988
+ qs("project-policy-path").textContent = projectPolicy?.path ?? "";
4989
+ qs("project-policy-notice").hidden = !projectPolicy || projectPolicy.weakenings.length === 0;
4990
+ qs("project-policy-notice").textContent = projectPolicy ? ["Merged on top of this file:", ...projectPolicy.weakenings].join(\`
4991
+ \`) : "";
4628
4992
  qs("app-version").textContent = state.version;
4629
4993
  renderSafety();
4630
- qs("destructive-command").innerHTML = '<label class="row master"><input type="checkbox" data-destructive-command-enabled ' + checkbox(state.policy.destructive_command_protection.enabled) + '><span><strong>Destructive command protection</strong><small>Block configurable destructive git, filesystem, and execution patterns. Catastrophic and custom rules remain active when disabled.</small></span><span class="master-badge">' + (state.policy.destructive_command_protection.enabled ? "On" : "Off") + "</span></label>" + '<div id="destructive-command-rules"></div>' + '<section class="rule-tier">' + '<button type="button" class="rule-tier-head" aria-expanded="false" aria-controls="allow-paths-content"><span class="panel-chevron" aria-hidden="true"></span><span class="tier-label"><strong id="allow-paths-label">Allow paths</strong><small>Recursive deletes targeting these paths are not blocked, like /tmp. The home directory, or any path containing it, is rejected.</small></span><span class="tier-counts" id="allow-paths-count"></span></button>' + '<div class="tier-content paths-content" id="allow-paths-content" hidden>' + '<p class="muted">Use an absolute path or a ~/ path. Paste multiple lines to add several paths at once.</p>' + '<div class="paths-add"><input type="text" id="allow-paths-input" data-path-input="allow-paths" autocomplete="off" spellcheck="false" placeholder="/absolute/path or ~/path" aria-labelledby="allow-paths-label"><button type="button" class="icon-button" id="allow-paths-add-button" data-path-add="allow-paths" aria-label="Add allow path">' + pathListIcons.add + "</button></div>" + '<p class="paths-hint" id="allow-paths-hint" hidden></p>' + '<ul class="paths-list" id="allow-paths-list"></ul>' + "</div></section>";
4631
- qs("secret").innerHTML = '<label class="row master"><input type="checkbox" id="secret-enabled" ' + checkbox(state.policy.secret_protection.enabled) + '><span><strong>Secret protection</strong><small>Block default sensitive paths, coding CLI credential locations, and configured deny paths.</small></span><span class="master-badge">' + (state.policy.secret_protection.enabled ? "On" : "Off") + "</span></label>" + '<div id="secret-patterns"></div>' + '<section class="rule-tier">' + '<button type="button" class="rule-tier-head" aria-expanded="false" aria-controls="deny-paths-content"><span class="panel-chevron" aria-hidden="true"></span><span class="tier-label"><strong id="deny-paths-label">Deny paths</strong><small>Configured paths and everything inside them are blocked while Secret protection is on.</small></span><span class="tier-counts" id="deny-paths-count"></span></button>' + '<div class="tier-content paths-content" id="deny-paths-content" hidden>' + '<p class="muted">Paste multiple lines to add several paths at once.</p>' + '<div class="paths-add"><input type="text" id="deny-paths-input" data-path-input="deny-paths" autocomplete="off" spellcheck="false" placeholder="path/to/protect" aria-labelledby="deny-paths-label"><button type="button" class="icon-button" id="deny-paths-add-button" data-path-add="deny-paths" aria-label="Add deny path">' + pathListIcons.add + "</button></div>" + '<p class="paths-hint" id="deny-paths-hint" hidden></p>' + '<ul class="paths-list" id="deny-paths-list"></ul>' + "</div></section>" + '<section class="rule-tier">' + '<button type="button" class="rule-tier-head" aria-expanded="false" aria-controls="secret-allow-paths-content"><span class="panel-chevron" aria-hidden="true"></span><span class="tier-label"><strong id="secret-allow-paths-label">Allow paths</strong><small>Configured files and subtrees are exempt from the pattern rules. Deny paths and coding CLI protections still apply. Entries covering the home directory are rejected, and glob patterns are not supported.</small></span><span class="tier-counts" id="secret-allow-paths-count"></span></button>' + '<div class="tier-content paths-content" id="secret-allow-paths-content" hidden>' + '<p class="muted">Paste multiple lines to add several paths at once.</p>' + '<div class="paths-add"><input type="text" id="secret-allow-paths-input" data-path-input="secret-allow-paths" autocomplete="off" spellcheck="false" placeholder="~/project/.env.test or ~/project/fixtures" aria-labelledby="secret-allow-paths-label"><button type="button" class="icon-button" id="secret-allow-paths-add-button" data-path-add="secret-allow-paths" aria-label="Add allow path">' + pathListIcons.add + "</button></div>" + '<p class="paths-hint" id="secret-allow-paths-hint" hidden></p>' + '<ul class="paths-list" id="secret-allow-paths-list"></ul>' + "</div></section>";
4994
+ qs("destructive-command").innerHTML = '<label class="row master"><input type="checkbox" data-destructive-command-enabled ' + checkbox(state.policy.destructive_command_protection.enabled) + '><span><strong>Destructive command protection</strong><small>Block configurable destructive git, filesystem, and execution patterns. Catastrophic and custom rules remain active when disabled.</small></span><span class="master-badge">' + (state.policy.destructive_command_protection.enabled ? "On" : "Off") + '</span><span class="project-chip-slot" id="destructive-enabled-chip"></span></label>' + '<div id="destructive-command-rules"></div>' + '<section class="rule-tier">' + '<button type="button" class="rule-tier-head" aria-expanded="false" aria-controls="allow-paths-content"><span class="panel-chevron" aria-hidden="true"></span><span class="tier-label"><strong id="allow-paths-label">Allow paths</strong><small>Recursive deletes targeting these paths are not blocked, like /tmp. The home directory, or any path containing it, is rejected.</small></span><span class="tier-counts" id="allow-paths-count"></span></button>' + '<div class="tier-content paths-content" id="allow-paths-content" hidden>' + '<p class="muted">Use an absolute path or a ~/ path. Paste multiple lines to add several paths at once.</p>' + '<div class="paths-add"><input type="text" id="allow-paths-input" data-path-input="allow-paths" autocomplete="off" spellcheck="false" placeholder="/absolute/path or ~/path" aria-labelledby="allow-paths-label"><button type="button" class="icon-button" id="allow-paths-add-button" data-path-add="allow-paths" aria-label="Add allow path">' + pathListIcons.add + "</button></div>" + '<p class="paths-hint" id="allow-paths-hint" hidden></p>' + '<span class="project-chip-slot" id="allow-paths-chip"></span>' + '<ul class="paths-list" id="allow-paths-list"></ul>' + "</div></section>";
4995
+ qs("secret").innerHTML = '<label class="row master"><input type="checkbox" id="secret-enabled" ' + checkbox(state.policy.secret_protection.enabled) + '><span><strong>Secret protection</strong><small>Block default sensitive paths, coding CLI credential locations, and configured deny paths.</small></span><span class="master-badge">' + (state.policy.secret_protection.enabled ? "On" : "Off") + '</span><span class="project-chip-slot" id="secret-enabled-chip"></span></label>' + '<div id="secret-patterns"></div>' + '<section class="rule-tier">' + '<button type="button" class="rule-tier-head" aria-expanded="false" aria-controls="deny-paths-content"><span class="panel-chevron" aria-hidden="true"></span><span class="tier-label"><strong id="deny-paths-label">Deny paths</strong><small>Configured paths and everything inside them are blocked while Secret protection is on.</small></span><span class="tier-counts" id="deny-paths-count"></span></button>' + '<div class="tier-content paths-content" id="deny-paths-content" hidden>' + '<p class="muted">Paste multiple lines to add several paths at once.</p>' + '<div class="paths-add"><input type="text" id="deny-paths-input" data-path-input="deny-paths" autocomplete="off" spellcheck="false" placeholder="path/to/protect" aria-labelledby="deny-paths-label"><button type="button" class="icon-button" id="deny-paths-add-button" data-path-add="deny-paths" aria-label="Add deny path">' + pathListIcons.add + "</button></div>" + '<p class="paths-hint" id="deny-paths-hint" hidden></p>' + '<span class="project-chip-slot" id="deny-paths-chip"></span>' + '<ul class="paths-list" id="deny-paths-list"></ul>' + "</div></section>" + '<section class="rule-tier">' + '<button type="button" class="rule-tier-head" aria-expanded="false" aria-controls="secret-allow-paths-content"><span class="panel-chevron" aria-hidden="true"></span><span class="tier-label"><strong id="secret-allow-paths-label">Allow paths</strong><small>Configured files and subtrees are exempt from the pattern rules. Deny paths and coding CLI protections still apply. Entries covering the home directory are rejected, and glob patterns are not supported.</small></span><span class="tier-counts" id="secret-allow-paths-count"></span></button>' + '<div class="tier-content paths-content" id="secret-allow-paths-content" hidden>' + '<p class="muted">Paste multiple lines to add several paths at once.</p>' + '<div class="paths-add"><input type="text" id="secret-allow-paths-input" data-path-input="secret-allow-paths" autocomplete="off" spellcheck="false" placeholder="~/project/.env.test or ~/project/fixtures" aria-labelledby="secret-allow-paths-label"><button type="button" class="icon-button" id="secret-allow-paths-add-button" data-path-add="secret-allow-paths" aria-label="Add allow path">' + pathListIcons.add + "</button></div>" + '<p class="paths-hint" id="secret-allow-paths-hint" hidden></p>' + '<span class="project-chip-slot" id="secret-allow-paths-chip"></span>' + '<ul class="paths-list" id="secret-allow-paths-list"></ul>' + "</div></section>";
4632
4996
  qs("raw").value = state.errors.length ? state.raw : formatPolicy(draftPolicy);
4633
4997
  qs("policy-search").value = "";
4634
4998
  syncSearchState();
@@ -4637,6 +5001,7 @@ function render() {
4637
5001
  pathLists["deny-paths"].render();
4638
5002
  pathLists["secret-allow-paths"].render();
4639
5003
  pathLists["allow-paths"].render();
5004
+ syncProjectChips();
4640
5005
  updateRawSource();
4641
5006
  renderRetention(state);
4642
5007
  qs("recovery").hidden = state.errors.length === 0;
@@ -4678,6 +5043,11 @@ var restoreDraft = () => {
4678
5043
  draft.secret_protection.deny_paths ??= [];
4679
5044
  draft.secret_protection.allow_paths ??= [];
4680
5045
  draftPolicy = draft;
5046
+ renderPolicySections();
5047
+ refreshPolicyPreview();
5048
+ setAppStatus("Restored unsaved draft", "ok");
5049
+ };
5050
+ function renderPolicySections() {
4681
5051
  const masterToggle = document.querySelector("[data-destructive-command-enabled]");
4682
5052
  if (masterToggle)
4683
5053
  masterToggle.checked = draftPolicy.destructive_command_protection.enabled;
@@ -4689,11 +5059,10 @@ var restoreDraft = () => {
4689
5059
  pathLists["deny-paths"].render();
4690
5060
  pathLists["secret-allow-paths"].render();
4691
5061
  pathLists["allow-paths"].render();
5062
+ syncProjectChips();
4692
5063
  syncRawFromForm();
4693
5064
  updateDirtyStatus();
4694
- refreshPolicyPreview();
4695
- setAppStatus("Restored unsaved draft", "ok");
4696
- };
5065
+ }
4697
5066
  async function load() {
4698
5067
  const result = await requestJson("/api/policy");
4699
5068
  if (!result.ok || !result.data) {
@@ -4772,6 +5141,203 @@ var reloadAfterWrite = async () => {
4772
5141
  setDetailStatus("");
4773
5142
  return true;
4774
5143
  };
5144
+ var setProjectDraftDiagnostics = (messages) => {
5145
+ qs("project-draft-diagnostics").textContent = messages.join(\`
5146
+ \`);
5147
+ qs("project-draft-diagnostics").hidden = messages.length === 0;
5148
+ };
5149
+ var renderProjectDraftBar = () => {
5150
+ qs("project-draft-enter").hidden = projectDraft !== null;
5151
+ qs("project-draft-bar").hidden = projectDraft === null;
5152
+ qs("save").textContent = projectDraft ? "Review & apply" : "Save";
5153
+ if (!projectDraft)
5154
+ return;
5155
+ qs("project-draft-path").textContent = projectDraft.path;
5156
+ qs("project-draft-change").hidden = !projectDraft.canPickDirectory;
5157
+ };
5158
+ var exitProjectDraft = () => {
5159
+ projectDraft = null;
5160
+ markedFields = new Set;
5161
+ setProjectDraftDiagnostics([]);
5162
+ if (state)
5163
+ draftPolicy = clonePolicy(state.policy);
5164
+ renderProjectDraftBar();
5165
+ renderPolicySections();
5166
+ };
5167
+ var ingestProjectState = async (okStatus) => {
5168
+ const result = await requestJson("/api/policy/project");
5169
+ if (!result.ok || !result.data) {
5170
+ setAppStatus("Project draft unavailable", "error");
5171
+ setDetailStatus(\`Error: \${errorText(result)}\`, "error");
5172
+ return false;
5173
+ }
5174
+ const seeded = seedProjectDraft(result.data);
5175
+ if (!seeded) {
5176
+ exitProjectDraft();
5177
+ await load();
5178
+ setAppStatus("Repair required", "error");
5179
+ setDetailStatus([
5180
+ "Error: repair your user policy before drafting a project policy.",
5181
+ ...Array.isArray(result.data.userPolicyDiagnostics) ? result.data.userPolicyDiagnostics : []
5182
+ ].join(\`
5183
+ \`), "error");
5184
+ return false;
5185
+ }
5186
+ projectDraft = {
5187
+ dir: result.data.dir,
5188
+ path: result.data.path,
5189
+ revision: result.data.revision,
5190
+ canPickDirectory: result.data.canPickDirectory === true,
5191
+ baseline: seeded.baseline,
5192
+ snapshot: seeded.snapshot
5193
+ };
5194
+ markedFields = seeded.marked;
5195
+ draftPolicy = seeded.policy;
5196
+ setProjectDraftDiagnostics(Array.isArray(result.data.projectionDiagnostics) ? result.data.projectionDiagnostics : []);
5197
+ renderProjectDraftBar();
5198
+ renderPolicySections();
5199
+ refreshPolicyPreview();
5200
+ setAppStatus(okStatus, "ok");
5201
+ return true;
5202
+ };
5203
+ var enterProjectDraft = async () => {
5204
+ if (!state) {
5205
+ setAppStatus("Load failed", "error");
5206
+ setDetailStatus("Error: Policy is not loaded yet. Reload the page.", "error");
5207
+ return;
5208
+ }
5209
+ if (state.errors.length) {
5210
+ setAppStatus("Repair required", "error");
5211
+ setDetailStatus("Error: repair your user policy before drafting a project policy.", "error");
5212
+ return;
5213
+ }
5214
+ if (dirty) {
5215
+ if (!await confirmDialog({
5216
+ title: "Discard unsaved policy changes?",
5217
+ body: "A project draft starts from your saved user policy. Save your changes first, or discard them here.",
5218
+ confirmLabel: "Discard changes",
5219
+ confirmClass: ""
5220
+ }))
5221
+ return;
5222
+ sessionStorage.removeItem("cc-safety-net-draft");
5223
+ if (!await load())
5224
+ return;
5225
+ }
5226
+ await ingestProjectState("Drafting a project policy.");
5227
+ };
5228
+ var confirmDiscardProjectDraft = async (body) => !dirty || await confirmDialog({
5229
+ title: "Discard this project draft?",
5230
+ body,
5231
+ confirmLabel: "Discard draft",
5232
+ confirmClass: ""
5233
+ });
5234
+ var changeProjectDirectory = async () => {
5235
+ if (!await confirmDiscardProjectDraft("Switching projects discards this draft."))
5236
+ return;
5237
+ const result = await requestJson("/api/policy/project/choose-directory", { method: "POST" });
5238
+ if (!result.ok) {
5239
+ setAppStatus("Could not open the folder picker", "error");
5240
+ setDetailStatus(\`Error: \${errorText(result)}\`, "error");
5241
+ return;
5242
+ }
5243
+ if (result.data.error) {
5244
+ setAppStatus(result.data.error, "error");
5245
+ return;
5246
+ }
5247
+ if (result.data.cancelled)
5248
+ return;
5249
+ await ingestProjectState("Drafting a project policy.");
5250
+ };
5251
+ var leaveProjectDraft = async () => {
5252
+ if (!await confirmDiscardProjectDraft("The fields you marked are not written anywhere yet."))
5253
+ return;
5254
+ exitProjectDraft();
5255
+ if (await load())
5256
+ setAppStatus("Left the project draft.", "ok");
5257
+ };
5258
+ var discardProjectDraft = async () => {
5259
+ const draft = projectDraft;
5260
+ if (!draft)
5261
+ return;
5262
+ if (!await confirmDialog({
5263
+ title: "Discard changes to this draft?",
5264
+ body: "The draft returns to the fields this project already sets.",
5265
+ confirmLabel: "Discard changes",
5266
+ confirmClass: ""
5267
+ }))
5268
+ return;
5269
+ const snapshot = JSON.parse(draft.snapshot);
5270
+ markedFields = new Set(projectMarkedFields(snapshot));
5271
+ draftPolicy = overlayProjectProposal(draft.baseline, snapshot);
5272
+ renderPolicySections();
5273
+ refreshPolicyPreview();
5274
+ setAppStatus("Changes discarded.", "ok");
5275
+ };
5276
+ var handleStaleProjectDraft = async () => {
5277
+ if (!await ingestProjectState("Project draft reloaded."))
5278
+ return;
5279
+ setAppStatus("Project target changed", "error");
5280
+ setDetailStatus("Error: the project directory changed, so this draft was reloaded for the new target. Review it again before applying.", "error");
5281
+ };
5282
+ var projectDiffHtml = (data) => {
5283
+ const rows = Array.isArray(data.rows) ? data.rows : [];
5284
+ const warnings = [
5285
+ ...data.existingFileDiagnostics?.length ? ["The existing project policy file is invalid and will be replaced."] : [],
5286
+ ...data.weakenings ?? []
5287
+ ];
5288
+ const table = rows.length === 0 ? '<p class="empty">No change to the effective policy.</p>' : \`<table class="diff-table"><thead><tr><th>Setting</th><th>Now</th><th>After</th></tr></thead><tbody>\${rows.map((row) => \`<tr><td><code>\${escapeHtml(row.field)}</code></td><td class="diff-before">\${escapeHtml(row.before ?? "(unset)")}</td><td class="diff-after">\${escapeHtml(row.after ?? "(unset)")}</td></tr>\`).join("")}</tbody></table>\`;
5289
+ return table + warnings.map((text) => \`<p class="diff-warning">\${escapeHtml(text)}</p>\`).join("");
5290
+ };
5291
+ var reviewProjectDraft = async () => {
5292
+ const draft = projectDraft;
5293
+ if (!draft)
5294
+ return;
5295
+ const proposal = collectProjectProposal(markedFields, draftPolicy);
5296
+ const serialized = JSON.stringify(proposal);
5297
+ const body = JSON.stringify({ revision: draft.revision, proposal });
5298
+ const diff = await requestJson("/api/policy/project/diff", { method: "POST", body });
5299
+ if (projectDraft !== draft)
5300
+ return;
5301
+ if (diff.status === 409) {
5302
+ await handleStaleProjectDraft();
5303
+ return;
5304
+ }
5305
+ if (!diff.ok) {
5306
+ setAppStatus("Review failed", "error");
5307
+ setDetailStatus(\`Error: \${errorText(diff)}\`, "error");
5308
+ return;
5309
+ }
5310
+ if (JSON.stringify(collectProjectProposal(markedFields, draftPolicy)) !== serialized) {
5311
+ setAppStatus("Review again", "error");
5312
+ setDetailStatus("Error: the draft changed while the review was loading. Review it again.", "error");
5313
+ return;
5314
+ }
5315
+ if (!await confirmDialog({
5316
+ title: "Apply this project policy?",
5317
+ body: "Everyone who works in this project gets these changes on top of their own user policy.",
5318
+ detail: draft.path,
5319
+ rowsHtml: projectDiffHtml(diff.data),
5320
+ confirmLabel: "Apply project policy",
5321
+ confirmClass: "primary"
5322
+ }))
5323
+ return;
5324
+ await runExclusive("Applying...", async () => {
5325
+ const applied = await requestJson("/api/policy/project/apply", { method: "POST", body });
5326
+ if (applied.status === 409) {
5327
+ await handleStaleProjectDraft();
5328
+ return;
5329
+ }
5330
+ if (!isWriteSuccess(applied)) {
5331
+ setAppStatus("Apply failed", "error");
5332
+ setDetailStatus(\`Error: \${errorText(applied)}\`, "error");
5333
+ return;
5334
+ }
5335
+ const path = applied.data.path;
5336
+ exitProjectDraft();
5337
+ if (await load())
5338
+ setAppStatus(\`Applied \${path}.\`, "ok");
5339
+ });
5340
+ };
4775
5341
  var saveRetentionDays = async (days) => {
4776
5342
  const saved = state;
4777
5343
  if (!saved)
@@ -4785,6 +5351,12 @@ var saveRetentionDays = async (days) => {
4785
5351
  }
4786
5352
  if (days === current)
4787
5353
  return;
5354
+ if (projectDraft) {
5355
+ qs("retention-days").value = String(current);
5356
+ setAppStatus("Retention unchanged", "error");
5357
+ setDetailStatus("Error: exit or apply your project draft first.", "error");
5358
+ return;
5359
+ }
4788
5360
  if (dirty) {
4789
5361
  qs("retention-days").value = String(current);
4790
5362
  setAppStatus("Retention unchanged", "error");
@@ -4831,6 +5403,7 @@ document.addEventListener("change", (event) => {
4831
5403
  }
4832
5404
  if (control.name === "safety-level") {
4833
5405
  draftPolicy.safety.level = control.value;
5406
+ markProjectField("safety.level");
4834
5407
  renderSafety();
4835
5408
  syncRawFromForm();
4836
5409
  updateDirtyStatus();
@@ -4838,12 +5411,16 @@ document.addEventListener("change", (event) => {
4838
5411
  return;
4839
5412
  }
4840
5413
  if (control.dataset?.safetyOverride) {
4841
- if (control.value === "inherit")
5414
+ if (control.value === "inherit" && !projectDraft)
4842
5415
  delete draftPolicy.safety.overrides[control.dataset.safetyOverride];
4843
5416
  if (control.value === "true")
4844
5417
  draftPolicy.safety.overrides[control.dataset.safetyOverride] = true;
4845
5418
  if (control.value === "false")
4846
5419
  draftPolicy.safety.overrides[control.dataset.safetyOverride] = false;
5420
+ if (control.value === "inherit")
5421
+ unmarkProjectField(\`safety.overrides.\${control.dataset.safetyOverride}\`);
5422
+ if (control.value !== "inherit")
5423
+ markProjectField(\`safety.overrides.\${control.dataset.safetyOverride}\`);
4847
5424
  syncRawFromForm();
4848
5425
  updateDirtyStatus();
4849
5426
  refreshPolicyPreview();
@@ -4854,6 +5431,7 @@ document.addEventListener("change", (event) => {
4854
5431
  return;
4855
5432
  if ("workflowWorktree" in input.dataset) {
4856
5433
  draftPolicy.workflow.worktree_mode = input.checked;
5434
+ markProjectField("workflow.worktree_mode");
4857
5435
  syncRawFromForm();
4858
5436
  updateDirtyStatus();
4859
5437
  return;
@@ -4869,6 +5447,7 @@ document.addEventListener("change", (event) => {
4869
5447
  return;
4870
5448
  }
4871
5449
  draftPolicy.destructive_command_protection.enabled = input.checked;
5450
+ markProjectField("destructive_command_protection.enabled");
4872
5451
  syncMasterBadges();
4873
5452
  pathLists["allow-paths"].render();
4874
5453
  syncRawFromForm();
@@ -4882,11 +5461,7 @@ document.addEventListener("change", (event) => {
4882
5461
  if (!effectiveState)
4883
5462
  return;
4884
5463
  state?.destructiveCommandRules.filter((rule) => !rule.catastrophic && tierForRule(rule) === input.dataset.destructiveTierActive).forEach((rule) => {
4885
- if (input.checked === effectiveState.rules[rule.id]?.inheritedEnabled) {
4886
- delete draftPolicy.destructive_command_protection.overrides[rule.id];
4887
- return;
4888
- }
4889
- draftPolicy.destructive_command_protection.overrides[rule.id] = input.checked ? "on" : "off";
5464
+ setDestructiveOverride(rule.id, input.checked, effectiveState.rules[rule.id]?.inheritedEnabled);
4890
5465
  });
4891
5466
  syncRawFromForm();
4892
5467
  updateDirtyStatus();
@@ -4895,10 +5470,7 @@ document.addEventListener("change", (event) => {
4895
5470
  }
4896
5471
  if (input.dataset?.destructiveCommandActive) {
4897
5472
  const ruleId = input.dataset.destructiveCommandActive;
4898
- if (input.checked === preview?.rules[ruleId]?.inheritedEnabled)
4899
- delete draftPolicy.destructive_command_protection.overrides[ruleId];
4900
- else
4901
- draftPolicy.destructive_command_protection.overrides[ruleId] = input.checked ? "on" : "off";
5473
+ setDestructiveOverride(ruleId, input.checked, preview?.rules[ruleId]?.inheritedEnabled);
4902
5474
  syncRawFromForm();
4903
5475
  updateDirtyStatus();
4904
5476
  refreshPolicyPreview();
@@ -4933,6 +5505,7 @@ document.addEventListener("change", (event) => {
4933
5505
  return;
4934
5506
  }
4935
5507
  draftPolicy.secret_protection.enabled = input.checked;
5508
+ markProjectField("secret_protection.enabled");
4936
5509
  syncMasterBadges();
4937
5510
  renderSecretPatterns();
4938
5511
  pathLists["deny-paths"].render();
@@ -4950,6 +5523,23 @@ document.addEventListener("click", (event) => {
4950
5523
  runCommandTest();
4951
5524
  return;
4952
5525
  }
5526
+ if (target.closest("#project-draft-enter")) {
5527
+ enterProjectDraft();
5528
+ return;
5529
+ }
5530
+ if (target.closest("#project-draft-change")) {
5531
+ changeProjectDirectory();
5532
+ return;
5533
+ }
5534
+ if (target.closest("#project-draft-exit")) {
5535
+ leaveProjectDraft();
5536
+ return;
5537
+ }
5538
+ const unmarkButton = target.closest("[data-unmark-field]");
5539
+ if (unmarkButton) {
5540
+ unmarkProjectField(unmarkButton.dataset.unmarkField ?? "");
5541
+ return;
5542
+ }
4953
5543
  const createRule = target.closest("[data-create-rule]");
4954
5544
  if (createRule) {
4955
5545
  openRuleComposer(createRule.dataset.createRule ?? "");
@@ -5122,7 +5712,12 @@ document.addEventListener("click", (event) => {
5122
5712
  }
5123
5713
  const inheritedButton = target.closest("[data-use-inherited]");
5124
5714
  if (inheritedButton) {
5125
- delete draftPolicy.destructive_command_protection.overrides[inheritedButton.dataset.useInherited ?? ""];
5715
+ const ruleId = inheritedButton.dataset.useInherited ?? "";
5716
+ if (projectDraft) {
5717
+ unmarkProjectField(\`destructive_command_protection.overrides.\${ruleId}\`);
5718
+ return;
5719
+ }
5720
+ delete draftPolicy.destructive_command_protection.overrides[ruleId];
5126
5721
  syncRawFromForm();
5127
5722
  updateDirtyStatus();
5128
5723
  refreshPolicyPreview();
@@ -5140,6 +5735,11 @@ document.addEventListener("click", (event) => {
5140
5735
  confirmLabel: "Restore defaults"
5141
5736
  }))
5142
5737
  return;
5738
+ clearProjectOverrideMarks("destructive_command_protection");
5739
+ if (projectDraft) {
5740
+ rebuildProjectDisplay();
5741
+ return;
5742
+ }
5143
5743
  draftPolicy.destructive_command_protection.overrides = {};
5144
5744
  syncRawFromForm();
5145
5745
  updateDirtyStatus();
@@ -5159,6 +5759,11 @@ document.addEventListener("click", (event) => {
5159
5759
  confirmLabel: "Restore defaults"
5160
5760
  }))
5161
5761
  return;
5762
+ clearProjectOverrideMarks("secret_protection");
5763
+ if (projectDraft) {
5764
+ rebuildProjectDisplay();
5765
+ return;
5766
+ }
5162
5767
  draftPolicy.secret_protection.overrides = {};
5163
5768
  renderSecretPatterns();
5164
5769
  syncRawFromForm();
@@ -5168,6 +5773,10 @@ document.addEventListener("click", (event) => {
5168
5773
  return;
5169
5774
  }
5170
5775
  if (target.closest("#discard-changes")) {
5776
+ if (projectDraft) {
5777
+ discardProjectDraft();
5778
+ return;
5779
+ }
5171
5780
  (async () => {
5172
5781
  if (!await confirmDialog({
5173
5782
  title: "Discard unsaved changes?",
@@ -5214,6 +5823,10 @@ qs("save").onclick = () => {
5214
5823
  setDetailStatus("Error: Repair policy before saving changes.", "error");
5215
5824
  return;
5216
5825
  }
5826
+ if (projectDraft) {
5827
+ reviewProjectDraft();
5828
+ return;
5829
+ }
5217
5830
  if (!dirty) {
5218
5831
  setAppStatus("No changes to save", "ok");
5219
5832
  setDetailStatus("");
@@ -5262,6 +5875,11 @@ qs("reset").onclick = async () => {
5262
5875
  setDetailStatus("Error: Policy is not loaded yet. Reload the page.", "error");
5263
5876
  return;
5264
5877
  }
5878
+ if (projectDraft) {
5879
+ setAppStatus("Reset unavailable", "error");
5880
+ setDetailStatus("Error: exit or apply your project draft first.", "error");
5881
+ return;
5882
+ }
5265
5883
  if (!await confirmDialog({
5266
5884
  title: "Reset policy?",
5267
5885
  body: "This will restore the default policy JSON at this path.",
@@ -5327,5 +5945,6 @@ load().then((loaded) => {
5327
5945
  </script>
5328
5946
  </body>
5329
5947
  </html>
5330
- `;var Qc='<script id="ccsn-data" type="application/json">';function ed(e){return Xc.replace(Qc,()=>Qc+JSON.stringify({token:e}).replaceAll("<","\\u003c"))}var Vn="kenryu42/cc-safety-net",C1=`https://github.com/${Vn}`,Ho=1e4,S1=7;async function ud(e,t={}){let n=_({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 D1(t);if(r(`CC Safety Net policy GUI: ${i.url}`),!n.flags.noOpen)try{await(t.openBrowser??$1)(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 O1(i),0}async function D1(e={}){let t=w1(24).toString("base64url"),n=k1((i,s)=>{R1(i,s,t,e)});await new Promise((i,s)=>{n.once("error",s),n.listen(0,"127.0.0.1",()=>{n.off("error",s),i()})});let o=`http://127.0.0.1:${n.address().port}`;return{origin:o,token:t,url:`${o}/?token=${encodeURIComponent(t)}`,close:()=>_1(n)}}async function R1(e,t,n,r){let o=new URL(e.url??"/","http://127.0.0.1");if(e.method==="GET"&&o.pathname==="/favicon.ico"){t.writeHead(204,{"cache-control":"no-store"}),t.end();return}if(!P1(e,o,n)){D(t,403,{error:"Forbidden"});return}if(e.method==="GET"&&o.pathname==="/"){I1(t,ed(n));return}if(e.method==="GET"&&o.pathname==="/api/policy"){let i=od(r);D(t,200,{...i,configState:xt(B(r)),destructiveCommandRules:vt,secretPatterns:nd,version:T(),preview:i.errors.length>0?null:sd(i.policy)});return}if(e.method==="POST"&&o.pathname==="/api/policy/preview"){let i=await qn(e);if(!i.ok){D(t,i.status,{errors:[i.error]});return}let s=id(i.value);D(t,s.errors.length>0?400:200,s);return}if(e.method==="POST"&&o.pathname==="/api/policy/explain"){let i=await qn(e);if(!i.ok){D(t,i.status,{errors:[i.error]});return}let s=i.value;if(s===null||typeof s.command!=="string"){D(t,400,{errors:["command must be a string"]});return}let a=kr(s.policy);if(a.length>0){D(t,400,{errors:a});return}D(t,200,A1(s.command,s.policy,r));return}if(e.method==="POST"&&o.pathname==="/api/policy"){let i=await qn(e);if(!i.ok){D(t,i.status,{errors:[i.error]});return}let s=No(i.value,r);D(t,s.errors.length>0?400:200,s);return}if(e.method==="POST"&&o.pathname==="/api/reset"){D(t,200,No(rd,r));return}if(e.method==="POST"&&o.pathname==="/api/repair"){D(t,200,ad(r));return}if(e.method==="GET"&&o.pathname==="/api/activity"){let i=tt(r),s=E1(o.searchParams.get("days"),i);if(s===null){D(t,400,{error:`days must be an integer between 1 and ${i}`});return}D(t,200,zc(s,r.activityLogsDir));return}if(e.method==="POST"&&o.pathname==="/api/rules/choose-directory"){D(t,200,await Zc());return}if(e.method==="GET"&&o.pathname==="/api/rules"){let i=ve(r),s=new Map(i.rules.map((a)=>[a.name,a]));D(t,200,{projectPath:r.cwd??process.cwd(),canPickDirectory:Yc(process.platform,process.env),rulebooks:i.rulebooks.map((a)=>({source:a.source,spec:a.spec,name:a.name,version:a.version,rules:a.rules.flatMap((l)=>{let c=s.get(l);if(!c)return[];return[{name:c.name,command:c.command,subcommand:c.subcommand,block_args:c.block_args,reason:c.reason}]})})),errors:i.errors,warnings:i.warnings});return}if(e.method==="GET"&&o.pathname==="/api/star/context"){D(t,200,await(r.fetchStarContext??(()=>j1({logsDir:r.activityLogsDir})))());return}if(e.method==="POST"&&o.pathname==="/api/star"){let i=await(r.starRepo??N1)();D(t,200,i.ok?{ok:!0}:{ok:!1,fallbackUrl:C1});return}if(e.method==="GET"&&o.pathname==="/api/integrations"){D(t,200,await(r.fetchIntegrations??F1)());return}if(e.method==="GET"&&o.pathname==="/api/health"){D(t,200,await(r.fetchHealth??H1)());return}if(e.method==="POST"&&(o.pathname==="/api/install"||o.pathname==="/api/uninstall")){let i=await qn(e);if(!i.ok){D(t,i.status,{errors:[i.error]});return}let s=i.value?.target;if(typeof s!=="string"||!ae.some((l)=>l.target===s)){D(t,400,{error:"unknown target"});return}let a=o.pathname==="/api/install"?"install":"uninstall";D(t,200,await(r.runIntegration??M1)(a,s));return}D(t,404,{error:"Not found"})}function A1(e,t,n){let r=Tn(t),o=B(n),i=bt({rules:o.policy.rules,transparentWrappers:o.policy.transparentWrappers,safety:cd(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:ld(r.secret_protection.overrides),denyPaths:r.secret_protection.deny_paths,allowPaths:r.secret_protection.allow_paths}});return et(e,{policySnapshot:i,cwd:n.cwd,userConfigDir:n.userConfigDir})}function E1(e,t){if(e===null)return Math.min(S1,t);let n=Number(e);if(!Number.isInteger(n)||n<1||n>t)return null;return n}function P1(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 T1=1048576;async function qn(e){let t=[],n=0;for await(let r of e){let o=r;if(n+=o.byteLength,n>T1)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 I1(e,t){e.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),e.end(t)}function D(e,t,n){e.writeHead(t,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),e.end(JSON.stringify(n))}function _1(e){return new Promise((t,n)=>{e.close((r)=>r?n(r):t())})}function O1(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 $1(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=dd(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 N1(e="gh",t=Ho){return{ok:await Fo(e,["api","-X","PUT",`/user/starred/${Vn}`],t)===0}}async function F1(e={}){let t=await At(e.fetcher),n=pd(t,e.homeDir);return{targets:z.map((r)=>{let o=n.find((i)=>i.platform===r.id);return{target:r.id,label:R(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 pd(e,t){return dt(process.cwd(),{homeDir:t,ampPluginListOutput:e.ampPluginListOutput,codexPluginListOutput:e.codexPluginListOutput,copilotCliVersion:e.versions["copilot-cli"]})}async function H1(e={}){let[t,n]=await Promise.all([At(e.fetcher),(e.checkUpdates??be)()]);return{hooks:pd(t,e.homeDir).filter((r)=>r.detected).map((r)=>({platform:r.platform,label:R(r.platform),configured:r.configured})),update:{currentVersion:n.currentVersion,latestVersion:n.latestVersion??null,updateAvailable:n.updateAvailable}}}var td=Promise.resolve();function M1(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 qt(e,[],{selectTargets:async()=>[t],output:new x1({write(c,d,p){i.push(String(c).replace(/\n$/,"")),p()}}),...n})===0,output:i.join(`
5331
- `)}}finally{console.log=s,console.error=a}},o=td.then(r);return td=o.then(()=>{return},()=>{return}),o}async function j1(e={}){let[t,n,r]=await Promise.all([U1(e.command),G1(e.fetchRepo),Promise.resolve(tn(tt(),e.logsDir).totalBlocked)]);return{starred:t,starCount:n,blockedTotal:r}}async function U1(e="gh",t=Ho){if(await Fo(e,["auth","status"],t)!==0)return null;let n=await Fo(e,["api",`/user/starred/${Vn}`],t);if(n===0)return!0;if(n===null)return null;return!1}function Fo(e,t,n){return new Promise((r)=>{let o=dd(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 G1(e=fetch){try{let t=await e(`https://api.github.com/repos/${Vn}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Ho)});if(!t.ok)return null;let n=await t.json();return typeof n.stargazers_count==="number"?n.stargazers_count:null}catch{return null}}function B1(e){if(e[0]!=="help")return!1;let t=e[1];if(!t)yo(),process.exit(0);if(jt(t))process.exit(0);console.error(`Unknown command: ${t}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var q1={hook:async(e)=>{let t=cs(e);if(t){await t.run();return}console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),jt("hook",console.error),process.exit(1)},install:async(e)=>{process.exit(await qt("install",e))},update:async(e)=>{process.exit(await To(e))},uninstall:async(e)=>{process.exit(await qt("uninstall",e))},rule:async(e)=>{process.exit(await Bc(e))},status:async(e)=>{if(le(_({label:"status"},e).errors))process.exit(1);Vc()},statusline:async(e)=>{let t=_({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},e);if(t.errors.length===0&&t.flags.claudeCode){await $o();return}if(le(t.errors),!t.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");jt("statusline",console.error),process.exit(1)},doctor:async(e)=>{let t=po(e);if(!t)process.exit(1);let n=await bl({json:t.json,skipUpdateCheck:t.skipUpdateCheck});process.exit(n)},logs:async(e)=>{process.exit(await Ti(e))},gui:async(e)=>{process.exit(await ud(e))},explain:async(e)=>{process.exit(await Rl(e))}};async function V1(){let e=process.argv.slice(2),t=_({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},e);if(B1(e))return;let n=e[0],r=n?en(n):void 0;if(t.help&&r&&r.name!=="rule")jt(r.name),process.exit(0);if(!n||t.help&&!r)yo(),process.exit(0);if(t.flags.version)Pl(),process.exit(0);if(r){await q1[r.name](e.slice(1));return}let o=ds(n);if(o){await o.run();return}if(n==="--statusline"){await $o();return}console.error(n.startsWith("-")?`Unknown option: ${n}`:`Unknown command: ${n}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}V1().catch((e)=>{console.error("CC Safety Net error:",e),process.exit(1)});
5948
+ `;var Xd='<script id="ccsn-data" type="application/json">';function Qd(e){return Zd.replace(Xd,()=>Xd+JSON.stringify({token:e}).replaceAll("<","\\u003c"))}var pr="kenryu42/cc-safety-net",l0=`https://github.com/${pr}`,di=1e4,c0=7,d0="The project draft directory changed; reload the draft before applying.",u0="audit settings are user scope only; remove the audit section from a project proposal";async function pu(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 p0(t);if(r(`CC Safety Net policy GUI: ${i.url}`),!n.flags.noOpen)try{await(t.openBrowser??x0)(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 k0(i),0}async function p0(e={}){let t=o0(24).toString("base64url"),n={dir:null,revision:0},r=s0((s,a)=>{f0(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:()=>w0(r)}}async function f0(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(!v0(e,i,n)){C(t,403,{error:"Forbidden"});return}if(e.method==="GET"&&i.pathname==="/"){L0(t,Qd(n));return}if(e.method==="GET"&&i.pathname==="/api/policy"){let s=iu(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:ru,version:I(),preview:s.errors.length>0?null:au(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=su(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,h0(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(ou,r));return}if(e.method==="POST"&&i.pathname==="/api/repair"){C(t,200,lu(r));return}if(e.method==="POST"&&i.pathname==="/api/policy/project/choose-directory"){let s=await(r.chooseDirectory??li)();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=fu(o,r),a=eu(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:ai(process.platform,process.env)});return}if(e.method==="POST"&&i.pathname==="/api/policy/project/diff"){let s=await tu(e,t,o,r);if(!s)return;let a=eu(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 tu(e,t,o,r);if(!s)return;let a=g0(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=y0(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,Kd(a,r.activityLogsDir));return}if(e.method==="POST"&&i.pathname==="/api/rules/choose-directory"){C(t,200,await li());return}if(e.method==="GET"&&i.pathname==="/api/rules"){let s=Pe(r),a=new Map(s.rules.map((l)=>[l.name,l]));C(t,200,{projectPath:r.cwd??process.cwd(),canPickDirectory:ai(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??(()=>P0({logsDir:r.activityLogsDir})))());return}if(e.method==="POST"&&i.pathname==="/api/star"){let s=await(r.starRepo??C0)();C(t,200,s.ok?{ok:!0}:{ok:!1,fallbackUrl:l0});return}if(e.method==="GET"&&i.pathname==="/api/integrations"){C(t,200,await(r.fetchIntegrations??S0)());return}if(e.method==="GET"&&i.pathname==="/api/health"){C(t,200,await(r.fetchHealth??R0)());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??D0)(l,a));return}C(t,404,{error:"Not found"})}function fu(e,t){return e.dir??t.cwd??process.cwd()}function eu(e){let t=se(e),n=i0(t)?_e(t):{value:void 0,errors:[]},r=Be(n.value);return{projection:r.policy,diagnostics:[...n.errors,...r.diagnostics]}}async function tu(e,t,n,r){let o=fu(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:[d0]}),null;let l=m0(a.proposal);if(l.length>0)return C(t,400,{errors:l}),null;return{dir:o,proposal:a.proposal}}function m0(e){let t=Ee(e);if(t.length>0)return t;return e?.audit===void 0?[]:[u0]}function g0(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)}
5949
+ `),{path:n,errors:[]}}catch(o){return{path:n,errors:[o instanceof Error?o.message:String(o)]}}}function h0(e,t,n){let r=Y(t),o=z(n),i=Ot({rules:o.policy.rules,transparentWrappers:o.policy.transparentWrappers,safety:du(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:cu(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 y0(e,t){if(e===null)return Math.min(c0,t);let n=Number(e);if(!Number.isInteger(n)||n<1||n>t)return null;return n}function v0(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 b0=1048576;async function dn(e){let t=[],n=0;for await(let r of e){let o=r;if(n+=o.byteLength,n>b0)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 L0(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 w0(e){return new Promise((t,n)=>{e.close((r)=>r?n(r):t())})}function k0(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 x0(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=uu(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 C0(e="gh",t=di){return{ok:await ci(e,["api","-X","PUT",`/user/starred/${pr}`],t)===0}}async function S0(e={}){let t=await qt(e.fetcher),n=mu(t,e.homeDir);return{targets:X.map((r)=>{let o=n.find((i)=>i.platform===r.id);return{target:r.id,label:P(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 mu(e,t){return vt(process.cwd(),{homeDir:t,ampPluginListOutput:e.ampPluginListOutput,codexPluginListOutput:e.codexPluginListOutput,copilotCliVersion:e.versions["copilot-cli"]})}async function R0(e={}){let[t,n]=await Promise.all([qt(e.fetcher),(e.checkUpdates??Te)()]);return{hooks:mu(t,e.homeDir).filter((r)=>r.detected).map((r)=>({platform:r.platform,label:P(r.platform),configured:r.configured})),update:{currentVersion:n.currentVersion,latestVersion:n.latestVersion??null,updateAvailable:n.updateAvailable}}}var nu=Promise.resolve();function D0(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 a0({write(c,d,m){i.push(String(c).replace(/\n$/,"")),m()}}),...n})===0,output:i.join(`
5950
+ `)}}finally{console.log=s,console.error=a}},o=nu.then(r);return nu=o.then(()=>{return},()=>{return}),o}async function P0(e={}){let[t,n,r]=await Promise.all([A0(e.command),E0(e.fetchRepo),Promise.resolve(Sn(ct(),e.logsDir).totalBlocked)]);return{starred:t,starCount:n,blockedTotal:r}}async function A0(e="gh",t=di){if(await ci(e,["auth","status"],t)!==0)return null;let n=await ci(e,["api",`/user/starred/${pr}`],t);if(n===0)return!0;if(n===null)return null;return!1}function ci(e,t,n){return new Promise((r)=>{let o=uu(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 E0(e=fetch){try{let t=await e(`https://api.github.com/repos/${pr}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(di)});if(!t.ok)return null;let n=await t.json();return typeof n.stargazers_count==="number"?n.stargazers_count:null}catch{return null}}function _0(e){if(e[0]!=="help")return!1;let t=e[1];if(!t)Go(),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 T0={hook:async(e)=>{let t=Zs(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 ni(e))},uninstall:async(e)=>{process.exit(await ln("uninstall",e))},rule:async(e)=>{process.exit(await qd(e))},policy:async(e)=>{process.exit(await Rd(e))},status:async(e)=>{if(fe(E({label:"status"},e).errors))process.exit(1);zd()},statusline:async(e)=>{let t=E({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},e);if(t.errors.length===0&&t.flags.claudeCode){await ii();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=jo(e);if(!t)process.exit(1);let n=await gc({json:t.json,skipUpdateCheck:t.skipUpdateCheck});process.exit(n)},logs:async(e)=>{process.exit(await bs(e))},gui:async(e)=>{process.exit(await pu(e))},explain:async(e)=>{process.exit(await kc(e))}};async function I0(){let e=process.argv.slice(2),t=E({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},e);if(_0(e))return;let n=e[0],r=n?Cn(n):void 0;if(t.help&&r&&r.name!=="rule")rn(r.name),process.exit(0);if(!n||t.help&&!r)Go(),process.exit(0);if(t.flags.version)Sc(),process.exit(0);if(r){await T0[r.name](e.slice(1));return}let o=Xs(n);if(o){await o.run();return}if(n==="--statusline"){await ii();return}console.error(n.startsWith("-")?`Unknown option: ${n}`:`Unknown command: ${n}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}I0().catch((e)=>{console.error("CC Safety Net error:",e),process.exit(1)});