cc-safety-net 2.3.0 → 2.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +72 -100
- package/dist/amp/cc-safety-net/index.ts +52 -52
- package/dist/api.js +1 -1
- package/dist/bin/cc-safety-net.js +105 -99
- package/dist/chunks/{index-et11dxs1.js → index-6fvz7zfr.js} +36 -36
- package/dist/chunks/{index-qxyh7m59.js → index-jnb1nckj.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/openclaw/cc-safety-net/index.js +52 -52
- package/dist/openclaw/cc-safety-net/openclaw.plugin.json +1 -1
- package/dist/openclaw/cc-safety-net/package.json +1 -1
- package/dist/pi/index.js +1 -1
- package/package.json +2 -2
|
@@ -1,44 +1,44 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{b as
|
|
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
|
|
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
|
|
8
|
-
`)}function
|
|
9
|
-
`)}function
|
|
10
|
-
`)}function
|
|
11
|
-
`)}function
|
|
12
|
-
`)}function
|
|
2
|
+
import{b as mi,c as gi,d as V,e as hi,f as br,g as ct,h as He,i as Mr,j as be,k as Rs,l as Kr,m as vn,n as Ps,o as Ds,p as bn}from"../chunks/index-jnb1nckj.js";import{$a as _r,A as it,Aa as Es,Ab as Ot,B as he,Ba as ye,Bb as _s,C as ja,Ca as Nt,D as Zi,Da as Vr,E as Pe,Ea as zr,F as yn,Fa as as,G as Pt,Ga as ls,H as xr,Ha as ki,I as je,Ia as st,J as Se,Ja as cs,K as Ne,Ka as ds,L as re,La as Ar,M as Cr,Ma as Er,Na as Xi,O as oe,Oa as Rr,P as se,Pa as ge,Qa as Qi,R as ie,Ra as Gi,S as It,Sa as Bi,T as Nd,Ta as iu,U as Ae,Ua as Ci,V as U,Va as Si,W as Re,Wa as Ee,Xa as Ri,Y as we,Ya as Ge,Z,Za as Pi,_ as Ms,_a as q,aa as Me,ab as Fr,ba as Ln,bb as jr,ca as Ut,cb as J,da as Ei,db as su,ea as _i,eb as ve,fa as $t,fb as au,ga as Ue,gb as cn,ha as Ur,hb as lu,ia as Ti,ib as cu,ja as Ii,jb as du,ka as Le,kb as Be,la as As,lb as Y,ma as Jr,mb as uu,na as Ts,nb as pu,oa as Is,ob as us,pa as Gr,pb as ps,qa as rs,qb as fs,ra as Li,rb as ms,s as Mt,sa as os,sb as Dt,t as ns,ta as is,tb as De,u as H,ua as ss,ub as W,v as Rt,va as Br,vb as es,w as x,wa as wi,wb as Dr,x as St,xa as $i,xb as _t,y as w,ya as S,yb as z,z as B,za as qr,zb as Ht}from"../chunks/index-6fvz7zfr.js";var Lu=["-h","--help"];function E(e,t){let n=Object.entries(e.booleans??{}),r=Object.entries(e.values??{}),o=Object.entries(e.lists??{}),i=Object.fromEntries(n.map(([g])=>[g,!1])),s={},a=Object.fromEntries(o.map(([g])=>[g,[]])),l=[],c=[],d=!1,m=-1;for(let[g,u]of t.entries()){if(g<=m)continue;if(u==="--"){l.push(...t.slice(g+1));break}if(Lu.includes(u)){d=!0;continue}let p=n.find(([,L])=>L.includes(u));if(p){i[p[0]]=!0;continue}let f=r.find(([,L])=>L.includes(u));if(f){let L=t[g+1];if(L===void 0||L.startsWith("-")){c.push(`${u} requires a value`);continue}s[f[0]]=L,m=g+1;continue}let b=o.find(([,L])=>L.includes(u));if(b){let L=t.slice(g+1),h=L.findIndex((v)=>v.startsWith("-")),R=L.slice(0,h===-1?L.length:h);if(R.length===0){c.push(`${u} requires at least one value`);continue}a[b[0]]=[...a[b[0]]??[],...R],m=g+R.length;continue}if(u.startsWith("-")){c.push(`Unknown option for ${e.label}: ${u}`);continue}if(e.positionals==="tail"){l.push(...t.slice(g));break}l.push(u)}if(e.positionals!=="list"&&e.positionals!=="tail")c.push(...l.map((g)=>`Unexpected argument for ${e.label}: ${g}`));return{flags:i,values:s,lists:a,positionals:l,help:d,errors:c}}function fe(e){for(let t of e)console.error(t);return e.length>0}import{readdirSync as wp,statSync as vs,unlinkSync as kp}from"node:fs";import{basename as bs,dirname as xp,join as Cp,resolve as Sp}from"node:path";function F(e){return Array.from(e,(t)=>{let n=t.charCodeAt(0);if(n<=31||n>=127&&n<=159)return`\\x${n.toString(16).padStart(2,"0")}`;return t}).join("")}var gr=(e)=>{let t=Date.now()-new Date(e).getTime();if(!Number.isFinite(t))return"";let n=Math.floor(t/60000),r=Math.floor(n/60),o=Math.floor(r/24);if(o>0)return`${o}d ago`;if(r>0)return`${r}h ago`;if(n>0)return`${n}m ago`;return"just now"},rt=(e)=>{let t=(e??"").trim().split(/\s+/).filter((o)=>o&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(o)),n=t[0]?.split("/").pop();if(!n)return null;let r=t[1];return r&&/^[a-z][a-z0-9-]*$/.test(r)?`${n} ${r}`:n};import{existsSync as wu,readdirSync as ku,readFileSync as xu}from"node:fs";import{join as Cu}from"node:path";function Ce(e,t){try{return ku(e,{withFileTypes:!0,encoding:"utf8"}).flatMap((n)=>{let r=Cu(e,n.name);if(n.isDirectory())return Ce(r,t);if(n.name.endsWith(".jsonl"))return[r];return[]})}catch{if(t&&wu(e))t.count++;return[]}}function hr(e){let t=(o)=>`${o.sessionId}
|
|
3
|
+
${rt(o.segment||o.command)}`,n=e.filter((o)=>o.decision!=="allow"),r=n.filter((o)=>o.sessionId).reduce((o,i)=>o.set(t(i),(o.get(t(i))??0)+1),new Map);return new Set(n.filter((o)=>o.failureStage||(r.get(t(o))??0)>=2))}var Su=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Ru(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e;if(typeof t.ts!=="string"||typeof t.command!=="string")return!1;return Su.every((n)=>t[n]===void 0||typeof t[n]==="string")}function Fe(e,t){try{return xu(e,"utf-8").split(`
|
|
4
|
+
`).filter(Boolean).flatMap((n)=>{try{let r=JSON.parse(n);if(!Ru(r)){if(t)t.count++;return[]}return[r]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as up}from"node:path";var Pu=["AKIA","ASIA","ghp_","gho_","ghu_","ghs_","ghr_","github_pat_","glpat-","xox","npm_","pypi-","rk_","sk-","sk_","gsk_","xai-","pplx-","bastn_","tgp_v1_","flp_","wfr_","fw_","fwp_","tp-","psk-"];function yi(e){let t=0,n={allocateSegment(){return t++},getNextSegmentIndex(){return t},recordGlobal(r){e.record({kind:"step",scope:"global",step:r})},recordSegment(r,o=n.currentSegmentIndex){if(o===void 0)return;e.record({kind:"step",scope:"segment",segmentIndex:o,step:r})}};return n}function vi(e={}){let t=[],n=e.maxEvents??512,r={maxTextLength:e.maxTextLength??2048,maxListLength:e.maxListLength??128,maxObjectProperties:e.maxObjectProperties??e.maxListLength??128,maxDepth:e.maxDepth??16},o=0,i,s=new Set;return{record(a){if(i)return;try{if(!a||t.length>=n){o++;return}t.push(vr(Du(a,r,s)))}catch{o++}},finish(a){if(i)return i;try{i=vr({events:Object.freeze(t),droppedEvents:o,terminal:Au(a,r,s)})}catch{o++,i=Object.freeze({events:Object.freeze(t),droppedEvents:o,terminal:Object.freeze({result:"blocked",reason:"trace unavailable".slice(0,r.maxTextLength),segment:"trace unavailable".slice(0,r.maxTextLength)})})}return i}}}function Du(e,t,n){if(e.kind!=="step")throw TypeError("invalid trace event");let{scope:r,step:o}=e;pn(o,n,t);let i=ot(o,t,n);if(r==="global")return{kind:"step",scope:"global",step:i};if(r!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:e.segmentIndex,step:i}}function Au(e,t,n){let r=e.result;if(r==="allowed")return Object.freeze({result:"allowed"});if(r!=="blocked")throw TypeError("invalid trace terminal");let o=e.ruleId;return Object.freeze({result:"blocked",reason:ot(e.reason,t,n),segment:ot(e.segment,t,n),...o?{ruleId:ot(o,t,n)}:{}})}function pn(e,t,n,r=0,o=new WeakSet){if(typeof e==="string"){let a=e.slice(0,n.maxTextLength);if(!br(a))return;for(let l of hi(a))for(let c of l.match(/[^\s"'()$]+/g)??[])t.add(bi(c));return}if(!e||typeof e!=="object"||r>=n.maxDepth||o.has(e))return;if(o.add(e),Array.isArray(e)){let a=Math.min(e.length,n.maxListLength);for(let l=0;l<a;l++)pn(e[l],t,n,r+1,o);return}let i=0,s=new Set;for(let a in e){if(!Object.hasOwn(e,a))continue;if(i>=n.maxObjectProperties)break;i++,pn(a,t,n);let l=yr(a,n,t);if(s.has(l))continue;s.add(l),pn(e[a],t,n,r+1,o)}}function ot(e,t,n,r=0,o=new WeakSet){if(typeof e==="string")return yr(e,t,n);if(!e||typeof e!=="object")return e;if(r>=t.maxDepth)return;if(o.has(e))return;if(o.add(e),Array.isArray(e)){let a=[],l=Math.min(e.length,t.maxListLength);for(let c=0;c<l;c++)a.push(ot(e[c],t,n,r+1,o));return a}let i={},s=0;for(let a in e){if(!Object.hasOwn(e,a))continue;if(s>=t.maxObjectProperties)break;s++;let l=yr(a,t,n);if(Object.hasOwn(i,l))continue;Object.defineProperty(i,l,{value:ot(e[a],t,n,r+1,o),enumerable:!0,configurable:!0,writable:!0})}return i}function yr(e,t,n){let r=e.slice(0,t.maxTextLength),o=br(r)?gi(r):r,i=n.size>0?_u(o,n):o;return(Eu(i)?mi(i):i).slice(0,t.maxTextLength)}function Eu(e){return e.includes("PRIVATE KEY")||e.includes("://")||e.includes("eyJ")||e.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(e)||e.length>=14&&Pu.some((t)=>e.includes(t))||e.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(e)}function _u(e,t){return e.replace(/[^\s"'()$]+/g,(n)=>t.has(bi(n))?"<redacted>":n)}function bi(e){let t=2166136261,n=2166136261;for(let r=0;r<e.length;r++)t=Math.imul(t^e.charCodeAt(r),16777619),n=Math.imul(n^e.charCodeAt(e.length-r-1),16777619);return`${t>>>0}:${n>>>0}:${e.length}`}function vr(e){if(e&&typeof e==="object"&&!Object.isFrozen(e)){for(let t of Object.values(e))vr(t);Object.freeze(e)}return e}function xi(e,t,n){let r=n??Li(),o=r.getCommandProgram(e,t.shell??"auto"),i=vi(),s=yi(i),a=o.dialect==="powershell"?r.getCommandProgram(e,"posix"):o,l=wi(a);s.recordGlobal({type:"parse",input:e,segments:l.map((m)=>[...m])});let c=ki(e,{...t,analyzePartialProgram:!0,trace:s},o,r),d=s.getNextSegmentIndex();if(c&&d>0&&d<l.length)s.recordSegment({type:"segment-skipped",index:d,reason:"prior-segment-blocked"},d);return Object.freeze({decision:c,trace:i.finish(c?{result:"blocked",reason:c.reason,segment:c.evidence.find((m)=>m.kind==="command")?.segment??e,...c.ruleId?{ruleId:c.ruleId}:{}}:{result:"allowed"})})}import{resolve as Tu}from"node:path";function Lr(e){let t=Ci().safeParse(e);return{errors:t.success?[]:Ri(t.error.issues),ruleNames:new Set(Si(e).map((n)=>n.toLowerCase()))}}function wr(e){let t=Di(e);if(!t.ok)return t.result;return Lr(t.parsed)}function Di(e){let t=[],n=new Set;try{let r=typeof e==="string"?St(e):e,o=w(r);if(o===null)return t.push(`File not found: ${r.path}`),{ok:!1,result:{errors:t,ruleNames:n}};if(!o.trim())return t.push("Config file is empty"),{ok:!1,result:{errors:t,ruleNames:n}};return{ok:!0,parsed:JSON.parse(o)}}catch(r){if(r instanceof H)return t.push(r.message),{ok:!1,result:{errors:t,ruleNames:n}};let o=r instanceof Error?r.message:String(r);return t.push(r instanceof SyntaxError?"Invalid JSON":o),{ok:!1,result:{errors:t,ruleNames:n}}}}function Ai(e){return Tu(e??process.cwd(),".safety-net.json")}function me(e){let t=Di(e);if(!t.ok)return t.result;let n=Pi(t.parsed);return{errors:n.errors,ruleNames:n.sources}}import{join as Tr,resolve as qu}from"node:path";import{dirname as mn}from"node:path";var Iu="custom.";function fn(e){if(e.rulebook_version!==2)return[];let t=e.rules.map((n)=>({name:n.name,command:n.command,block_args:[],match:n.match,reason:n.reason,intent:n.intent}));return(e.tests??[]).flatMap((n,r)=>{let o=kr(Ii(n.command));if(o.length===0)return[`tests[${r}]: could not parse fixture command: ${n.command}`];let i=o.reduce((s,a)=>s??$i(a,t)?.id.slice(Iu.length),void 0);if(n.expect==="blocked"){if(i===n.rule)return[];let s=i?`"${i}" matched first`:"no rule matched";return[`tests[${r}]: expected "${n.rule}" to block "${n.command}" but ${s}`]}return i?[`tests[${r}]: expected "${n.command}" to be allowed but "${i}" matched`]:[]})}function kr(e){return e.nodes.flatMap((t)=>{if(t.kind==="group"||t.kind==="function")return kr(t.body);if(t.kind!=="command")return[];let n=Ti(_i(t.dialect,t.words)).words.map(Ei);return[...n.length>0?[n]:[],...t.nested.flatMap((r)=>kr(r))]})}var $u=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function Oi(e,t){let n=Ni(e.rules,t);if(n.length>0)return{ok:!0,specs:n};return ji(e.rules,t)}function Fi(e,t){let n=Ni(e,t);if(n.length>0)return{ok:!0,specs:n};let r=Fu(e,t);if(r.length>0)return{ok:!0,specs:r};let o=ju(e,t);if(!o.ok)return o;if(o.specs.length>0)return{ok:!0,specs:o.specs};return ji(e,t)}function ji(e,t){let n=e.filter((r)=>Sr(r)?.name===t);if(n.length===1)return{ok:!0,specs:n};return Ou(t,n)}function Ou(e,t){return{ok:!1,result:{ok:!1,errors:t.length===0?[`No configured rulebook matches ${e}`]:[`Ambiguous rulebook match ${e}: ${t.join(", ")}`],entries:[]}}}function Ni(e,t){return e.filter((n)=>n===t)}function Fu(e,t){let n=t.match($u),r=n?.[1],o=n?.[2],i=n?.[3];if(!r||!o||!i||!Ne(i))return[];return Hi(e,(s)=>s.owner===r&&s.repo===o&&s.ref===i)}function ju(e,t){if(!Se(t))return{ok:!0,specs:[]};let[n,r]=t.split("/"),o=Hi(e,(s)=>s.owner===n&&s.repo===r);if(new Set(o.map((s)=>Sr(s)?.ref).filter((s)=>!!s)).size<2)return{ok:!0,specs:o};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${t}. Use an explicit ref:`,` cc-safety-net rule remove ${t}#<ref>`],entries:[]}}}function Sr(e){try{return je(e)}catch{return null}}function Hi(e,t){return e.filter((n)=>{let r=Sr(n);return r?t(r):!1})}var qi=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Mi(e,t,n=Rt(mn(mn(t)),"rules policy"),r=ge()){if(re(e))return Uu(e,r);return Mu(e,t,n)}async function Vi(e,t,n,r,o,i){if(!re(e))return Mi(e,t,n,r);let s=o?null:Nu(e,t,n);if(s)return s;if(!o&&!i)throw Error(`${e} is not vendored; run rule update ${e} to vendor it`);return Mi(e,t,n,r)}function Nu(e,t,n=Rt(mn(mn(t)),"rules policy")){let r=je(e),o=Re(t,r.name),i=w(x(n,o));if(i===null)return null;let s=Dt(Pr(i,`Invalid rulebook ${o}.`));if(s.name!==r.name)throw Error(`rulebook name "${s.name}" in ${o} must match "${r.name}"`);return{spec:e,rulebook:s,content:i}}async function zi(e,t={}){if(!Se(e))throw Error(`Invalid GitHub repository source: ${e}`);let[n,r]=e.split("/");if(!n||!r)throw Error(`Invalid GitHub repository source: ${e}`);if(t.ref!==void 0&&!Ne(t.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${t.ref}`);let o=t.operation??ge(),i=t.ref??await Hu(n,r,e,o),s=await Ji(n,r,i,e,o),a=await gn(`https://api.github.com/repos/${n}/${r}/git/trees/${s}?recursive=1`,"tree",o),l=a.response;if(!l.ok)throw Error(`Failed to inspect ${e}: GitHub tree returned ${l.status}`);let c=JSON.parse(a.content);if(!Array.isArray(c?.tree))throw Error(`Failed to inspect ${e}: unexpected GitHub tree response`);let d=c.tree,m=[...new Set(d.flatMap((g)=>{if(!g||typeof g!=="object")return[];let u=g;if(u.type!=="blob"||typeof u.path!=="string")return[];let p=u.path.match(xr);return p?.[1]?[p[1]]:[]}))].sort();if(m.length===0)throw Error(`No rulebooks found in ${e} under ${Pt}/`);return{source:e,owner:n,repo:r,ref:i,commit:s,names:m}}async function Hu(e,t,n,r){let o=await gn(`https://api.github.com/repos/${e}/${t}`,"metadata",r),i=o.response;if(!i.ok)throw Error(`Failed to inspect ${n}: GitHub returned ${i.status}`);let a=JSON.parse(o.content)?.default_branch;if(typeof a!=="string"||a==="")throw Error(`Failed to inspect ${n}: missing default branch`);if(!Ne(a))throw Error(`GitHub returned an invalid default branch: ${a}`);return a}function Mu(e,t,n){Cr(e);let r=Re(t,e),o=w(x(n,r));if(o===null)throw Error(`Rulebook source not found: ${e}`);let i=Ki(Pr(o,"Invalid local rulebook source."));if(i.name!==e)throw Error(`rulebook name "${i.name}" must match local source "${e}"`);return{spec:e,rulebook:i,content:o}}async function Uu(e,t){let n=je(e),r=await Ji(n.owner,n.repo,n.ref,e,t),o=await gn(`https://raw.githubusercontent.com/${n.owner}/${n.repo}/${r}/${n.path}`,"raw",t),i=o.response;if(!i.ok)throw Error(`Failed to fetch ${e}: GitHub raw returned ${i.status}`);let s=o.content,a=Ki(Pr(s,"Invalid GitHub rulebook response."));if(a.name!==n.name)throw Error(`rulebook name "${a.name}" must match GitHub source "${n.name}"`);return{spec:e,rulebook:a,content:s}}function Ki(e){let t=Dt(e),n=fn(t);if(n.length>0)throw Error(n.join("; "));return t}function Pr(e,t){try{return JSON.parse(e)}catch{throw Error(t)}}async function Ji(e,t,n,r,o){let i=await gn(`https://api.github.com/repos/${e}/${t}/commits/${encodeURIComponent(n)}`,"commit",o),s=i.response;if(!s.ok)throw Error(`Failed to resolve ${r}: GitHub returned ${s.status}`);let a=JSON.parse(i.content);if(typeof a?.sha!=="string"||a.sha==="")throw Error(`Failed to resolve commit for ${r}`);return a.sha}async function Gu(e,t,n={}){if(n.signal?.aborted)throw n.signal.reason;let r=n.budget??Rr(),o=new AbortController,i=()=>o.abort(n.signal?.reason);n.signal?.addEventListener("abort",i,{once:!0});let s=!1,a=setTimeout(()=>{if(o.signal.aborted)return;s=!0,o.abort()},n.timeoutMs??qi.timeoutMs);try{if(n.signal?.aborted)throw n.signal.reason;Gi(r);let l=await(n.fetch??fetch)(e,{signal:o.signal,redirect:"error"});if(!l.ok)return Wi(l),{response:l,content:""};return{response:l,content:await Bu(l,t,r,()=>o.abort())}}catch(l){if(s)throw Error("GitHub request timed out",{cause:l});if(n.signal?.aborted)throw n.signal.reason;throw l}finally{clearTimeout(a),n.signal?.removeEventListener("abort",i)}}function gn(e,t,n){return Gu(n.resolveUrl?.(e)??e,t,{budget:n.budget,signal:n.controller.signal})}async function Bu(e,t,n=Rr(),r){let o=qi[`${t}Bytes`],i=Number(e.headers.get("content-length"));if(Number.isFinite(i)&&i>o)throw Wi(e),Error(`GitHub ${t} response exceeds ${o} bytes`);if(!e.body)return"";let s=e.body.getReader(),a=[],l=0;while(!0){let c=await s.read();if(c.done)break;try{Bi(n,c.value.byteLength)}catch(d){throw r?.(),Ui(s),d}if(l+=c.value.byteLength,l>o)throw r?.(),Ui(s),Error(`GitHub ${t} response exceeds ${o} bytes`);a.push(Buffer.from(c.value))}return Buffer.concat(a,l).toString("utf-8")}function Wi(e){if(!e.body)return;Yi(()=>e.body?.cancel())}function Ui(e){Yi(()=>e.cancel())}function Yi(e){try{Promise.resolve(e()).catch(()=>{})}catch{}}async function Tt(e={}){let t=$r(e);return Vu(t,await hn(t,ge()))}function Vu(e,t){if(!t.ok)return t;let n=U(e),r=[...new Set(W(n.configPath,n.filesystemScope))];if(r.length===0)return t;return{ok:!1,errors:r,entries:t.entries}}async function hn(e,t,n={},r=new Set,o=new Set){try{let i=U(e),s=_r(i.configTarget);if(!s.ok)return s.result;let a=s.config;if(e.check)return ap(a,i,e);let l=e.only?Oi(a,e.only):{ok:!0,specs:a.rules};if(!l.ok)return l.result;let c=new Set([...e.refresh?l.specs:[],...r]),d=(v)=>Vi(v,i.configDir,i.filesystemScope,t,c.has(v),!e.refresh||c.has(v)),m=await np(a.rules,e.refresh?(v)=>d(v).then((P)=>({ok:!0,item:P})).catch((P)=>{if(Qi(P))throw P;return{ok:!1,spec:v,message:P instanceof Error?P.message:String(P)}}):async(v)=>({ok:!0,item:await d(v)}),t),g=m.filter((v)=>!v.ok),u=m.filter((v)=>v.ok).map((v)=>v.item),p=u.flatMap((v)=>zu(v,a.rules)),f=u.flatMap((v)=>Ku(v,o,i)),b=new Set([...p,...f].map((v)=>v.spec)),L=[...g,...p,...f],h=[],R=Wu(h,()=>u.flatMap((v)=>b.has(v.spec)||L.length>0&&o.has(v.spec)?[]:Ju(v,i,n,h)));return{ok:L.length===0,errors:L.map((v)=>`Failed to update ${v.spec}: ${v.message}`),entries:u.map(Zu),changes:R}}catch(i){return Et(i)}}function zu(e,t){if(!re(e.spec))return[];let n=Dr(e.spec),r=t.filter((o)=>o!==e.spec&&Dr(o).toLowerCase()===n.toLowerCase());if(r.length===0)return[];return[{ok:!1,spec:e.spec,message:`rulebook name "${n}" is also claimed by ${r.join(", ")}; rename one of them`}]}function Ku(e,t,n){if(!t.has(e.spec)||!re(e.spec))return[];let r=Re(n.configDir,e.rulebook.name),o=w(x(n.filesystemScope,r));if(o===null||o===e.content)return[];return[{ok:!1,spec:e.spec,message:`${r} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Ju(e,t,n,r){if(!re(e.spec))return[];let o=Re(t.configDir,e.rulebook.name),i=x(t.filesystemScope,o),s=w(i);if(s===e.content)return[];return r?.push({target:i,previous:s}),B(i,e.content,void 0,n._testAfterPolicyRename),Yu(e,s)}function Wu(e,t){try{return t()}catch(n){for(let r of[...e].reverse()){if(r.previous===null){he(r.target);continue}B(r.target,r.previous)}throw n}}function Yu(e,t){if(t===null)return[`Vendored ${e.spec} (${e.rulebook.version})`];let n=_t(t),r="problem"in n?null:n.rulebook,o=new Map(r?.rules.map((s)=>[s.name,JSON.stringify(s)])??[]),i=new Set(e.rulebook.rules.map((s)=>s.name));return[`Updated ${e.spec} (${r?.version??"unreadable"} -> ${e.rulebook.version})`,...[...i].filter((s)=>!o.has(s)).map((s)=>` + ${s}`),...[...o.keys()].filter((s)=>!i.has(s)).map((s)=>` - ${s}`),...e.rulebook.rules.filter((s)=>{let a=o.get(s.name);return a!==void 0&&a!==JSON.stringify(s)}).map((s)=>` ~ ${s.name}`)]}function Zu(e){return{spec:e.spec,name:e.rulebook.name,version:e.rulebook.version,ruleCount:e.rulebook.rules.length}}async function Ir(e,t={}){return Xu(e,op(t),ge())}async function Xu(e,t,n,r={}){let o=null,i=!1;try{let s=U(t),a=w(s.configTarget);o={target:s.configTarget,content:a};let l=_r(s.configTarget);if(!l.ok)return l.result;let c=l.config,d=Se(e);Qu(e,t,d);let m=d?await zi(e,{ref:t.ref,operation:n}):null,g=m?ep(m,t.rulebooks):[],u=m?g.map((h)=>tp(c.rules,m,h)??`${e}#${m.ref}/${h}`):[e],p=u.filter((h)=>!c.rules.includes(h)),f=[...c.rules,...p];if(f.length>Ar)return rp();if(f.length!==c.rules.length)i=!0,J(s.configTarget,{version:1,rules:f,overrides:c.overrides??{},transparent_wrappers:c.transparent_wrappers??[]},void 0,r._testAfterPolicyRename);let b=await hn(t,n,r,new Set(p),new Set(p));if(!b.ok)At(s.configTarget,a);if(!b.ok||!m)return b;let L=g.filter((h,R)=>p.includes(u[R]??""));return{...b,add:{source:e,ref:m.ref,selected:g,added:L,alreadyConfigured:g.filter((h)=>!L.includes(h)),commits:p.length>0?[m.commit]:[]}}}catch(s){if(i&&o)try{At(o.target,o.content)}catch(a){return Et(a)}return Et(s)}}function Qu(e,t,n){if(!n&&t.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!n&&t.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${e}`);if(t.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let r=t.rulebooks?.filter((o)=>!Pe.test(o))??[];if(r.length>0)throw Error(`Invalid rulebook names: ${r.join(", ")}`)}function ep(e,t){let n=t?[...new Set(t)]:e.names,r=n.filter((o)=>!e.names.includes(o));if(r.length>0)throw Error(`Rulebooks not found in ${e.source} at ${e.ref}: ${r.join(", ")}
|
|
5
|
+
Available rulebooks: ${e.names.join(", ")}`);return n}function tp(e,t,n){let r=`${t.source}#${t.ref}/${n}`;if(e.includes(r))return r;let o=`${t.source}#${t.commit}/${n}`;return e.find((i)=>i===o)}async function np(e,t,n=ge()){if(e.length>Ar)throw Error(Er);let r=Array(e.length),o=0,i,s=Array.from({length:Math.min(e.length,Xi.concurrency)},async()=>{while(!i){let a=o;if(a>=e.length)return;o++;try{r[a]=await t(e[a],a,n.controller.signal)}catch(l){if(!i)i={value:l},o=e.length,n.controller.abort(l);return}}});if(await Promise.all(s),i)throw i.value;return r}function rp(){return{ok:!1,errors:[Er],entries:[]}}function $r(e){return{cwd:e.cwd,userConfigDir:e.userConfigDir,userConfigPath:e.userConfigPath,projectConfigPath:e.projectConfigPath,global:e.global,check:e.check,only:e.only,refresh:e.refresh}}function op(e){return{...$r(e),ref:e.ref,rulebooks:e.rulebooks}}function ip(e){return{...$r(e),deleteSource:e.deleteSource}}async function Or(e,t={}){try{return await sp(e,ip(t),{})}catch(n){return Et(n)}}async function sp(e,t,n){let r=U(t),o=q(r.configTarget);if(o.errors.length>0)return{ok:!1,errors:o.errors,entries:[]};if(!o.config)return{ok:!1,errors:[`No config found at ${r.configPath}`],entries:[]};let i=Fi(o.config.rules,e);if(!i.ok)return i.result;let s=t.deleteSource?lp(r.configDir,i.specs,r.filesystemScope):{ok:!0,dirs:[]};if(!s.ok)return s.result;let a=w(r.configTarget);if(a===null)return Et(Error("Rules config is unavailable."));try{J(r.configTarget,{version:1,rules:o.config.rules.filter((d)=>!i.specs.includes(d)),overrides:o.config.overrides??{},transparent_wrappers:o.config.transparent_wrappers??[]},void 0,n._testAfterPolicyRename)}catch(d){throw At(r.configTarget,a),d}let l=await hn(t,ge(),n);if(!l.ok)return At(r.configTarget,a),l;let c=cp(s.dirs,n,r.filesystemScope);if(!c.ok){At(r.configTarget,a);let d=await hn(t,ge(),n);if(!d.ok)return{ok:!1,errors:[...c.result.errors,...d.errors],entries:d.entries};return c.result}return l}async function ap(e,t,n){let r=es(e,t.configDir,n.global?"user":"project",t.filesystemScope);return{ok:r.errors.length===0&&r.warnings.length===0,errors:[...r.errors,...r.warnings],entries:r.entries}}function lp(e,t,n){let r=t.flatMap((a)=>Pe.test(a)?[]:["--delete-source can only delete local rulebook sources"]),o=t.map((a)=>Tr(e,a)),i=r.length>0?[]:o.flatMap((a)=>ts(a,n)),s=[...r,...i];return s.length>0?{ok:!1,result:{ok:!1,errors:s,entries:[]}}:{ok:!0,dirs:o}}function ts(e,t){let n=qu(e),r=x(t,n),o=it(r);if(!o)return[`Local rulebook source directory not found: ${e}`];let i=o.find((s)=>s.name==="rulebook.json");if(!i)return[`Local rulebook source directory is missing rulebook.json: ${e}`];if(i.kind!=="file")throw new H(t.label);if(w(x(t,Tr(n,"rulebook.json"))),o.length>1)return[`Local rulebook source directory contains extra files: ${e}. delete manually if you really want to remove the directory.`];return[]}function cp(e,t,n){let r=e.flatMap((o)=>{try{if(!it(x(n,o)))return[];let i=ts(o,n);if(i.length>0)return i;return dp(o,t,n),[]}catch(i){return[`Failed to delete local rulebook source ${o}: ${i instanceof Error?i.message:String(i)}`]}});return r.length>0?{ok:!1,result:{ok:!1,errors:r,entries:[]}}:{ok:!0}}function dp(e,t,n){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(e);return}he(x(n,Tr(e,yn))),Zi(x(n,e))}function At(e,t){if(t===null){he(e);return}B(e,t)}function Et(e){return{ok:!1,errors:[e instanceof Error?e.message:String(e)],entries:[]}}function at(e,t){let n=fp(t),r=as(n),o={effectiveLevel:r.effectiveLevel,selectedPreset:n.policySnapshot.policy.safety.level??"standard",...n.policySnapshot.policyScopes?{safetyPresetScope:n.policySnapshot.policyScopes.levelScope}:{},effectiveCapabilities:r.effectiveCapabilities,destructiveCommandRuleOverrides:n.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:i,configValid:s}=pp({cwd:t?.cwd,userConfigDir:t?.userConfigDir});if(!e||!e.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:i,configValid:s,...o};let a=mp(e,n);if(a)return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:a.rule,matched:!0,reason:a.reason}]}]},result:"blocked",reason:V(a.reason),segment:V(a.target),...a.ruleId?{ruleId:V(a.ruleId)}:{},configSource:i,configValid:s,...o};let l=xi(e,n),c=l.decision,d=c?.ruleId??gp(e,n),m=$t.find((u)=>u.id===d&&u.activationCapability),g=m?r.policy.effectiveDestructiveCommandRules[m.id]:void 0;return{trace:yp(l.trace),result:c?"blocked":"allowed",reason:c?V(c.reason):void 0,segment:c?V(c.evidence.find((u)=>u.kind==="command")?.segment??e):void 0,ruleId:c?.ruleId?V(c.ruleId):void 0,customRule:hp(vp(c?.ruleId,n.policySnapshot)),configSource:i,configValid:s,...o,...m&&g?{ruleActivation:{id:m.id,...g}}:{}}}function pp(e){let t=oe(e?.cwd),n=e?.userConfigPath??ie(e),r=Ae({cwd:e?.cwd,userConfigDir:e?.userConfigDir,userConfigPath:e?.userConfigPath});try{if(w(r.projectConfigTarget)!==null){if(me(r.projectConfigTarget).errors.length===0)return{configSource:t,configValid:!0};return{configSource:t,configValid:!1}}}catch(o){if(o instanceof H)return{configSource:t,configValid:!1};throw o}try{if(w(r.userConfigTarget)!==null){let o=me(r.userConfigTarget);return{configSource:n,configValid:o.errors.length===0}}return{configSource:null,configValid:!0}}catch(o){if(o instanceof H)return{configSource:n,configValid:!1};throw o}}function fp(e){let t=up(e?.cwd??process.cwd()),n=e?.policySnapshot??z({cwd:t,userConfigDir:e?.userConfigDir}),r=ye(n.policy);return{cwd:t,effectiveCwd:t,policySnapshot:n,environment:ns(),protectedGitMetadata:ss([t]),effectiveCapabilities:r.capabilities,strict:e?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function mp(e,t){let n=t.cwd??process.cwd(),r=rs(st("",{command:e},{kind:"command",shell:"posix"},{executionCwd:n,configCwd:n},e)),o=ps(r);if(o)return{reason:us,target:o.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let i=ds(r);if(i)return{reason:cs,target:i.target,ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};let s=is(r,t.protectedGitMetadata);if(s)return{reason:os,target:s.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let a=t.policySnapshot.policy,l=a.secretProtection.enabled===!1?null:ms(r,a.secretProtection,{strict:t.strict});if(l)return{reason:fs,target:l.target,ruleId:l.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function gp(e,t){let n=t.policySnapshot.policy,r=Ot({...n,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...n.destructiveCommandRuleOverrides,...Object.fromEntries($t.flatMap((o)=>o.activationCapability?[[o.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return ls(e,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function hp(e){if(!e)return;return{id:V(e.id),...e.rulebook?{rulebook:{name:V(e.rulebook.name),version:V(e.rulebook.version)}}:{},...e.source?{source:V(e.source)}:{},...e.override?{override:{type:"reason",reason:V(e.override.reason)}}:{}}}function yp(e){let t=e.events.flatMap((r)=>r.kind==="step"&&r.scope==="global"?[r.step]:[]),n=new Map;for(let r of e.events){if(r.kind!=="step"||r.scope!=="segment")continue;let o=n.get(r.segmentIndex)??{index:r.segmentIndex,steps:[]};o.steps.push(r.step),n.set(r.segmentIndex,o)}return{steps:t,segments:[...n.values()]}}function vp(e,t){let n=e?.replace(/^custom\./,"");if(!n||!t.policy.rules.some((r)=>r.name===n))return;return t.ruleMetadata[n]??Object.freeze({id:n})}import{existsSync as hs,readFileSync as bp}from"node:fs";function gs(e,t){return{"safety.level":e.safety.level,...Nr("safety.overrides",e.safety.overrides),"workflow.worktree_mode":String(e.workflow.worktree_mode),"destructive_command_protection.enabled":String(e.destructive_command_protection.enabled),...Nr("destructive_command_protection.overrides",e.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":Hr(e.destructive_command_protection.allow_paths),"secret_protection.enabled":String(e.secret_protection.enabled),...Nr("secret_protection.overrides",e.secret_protection.overrides),"secret_protection.deny_paths":Hr(e.secret_protection.deny_paths),"secret_protection.allow_paths":Hr(e.secret_protection.allow_paths),...t?{"audit.retention_days":String(e.audit.retention_days)}:{}}}function Ft(e,t,n){let r=gs(e,n),o=gs(t,n);return[...new Set([...Object.keys(r),...Object.keys(o)])].flatMap((i)=>r[i]===o[i]?[]:[{field:i,before:r[i],after:o[i]}])}function lt(e){let t=ve(e);if(!hs(t))return{baseline:Y(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__),diagnostics:[]};let n=_e(t);return{baseline:Y(n.value),diagnostics:n.errors.length>0?n.errors:Ee(n.value)}}function _e(e){if(!hs(e))return{errors:[`${e}: file not found`]};try{return{value:JSON.parse(bp(e,"utf-8")),errors:[]}}catch(t){let n=t instanceof Error?t.message:String(t);return{errors:[`${e}: ${t instanceof SyntaxError?`Invalid JSON: ${n}`:n}`]}}}function jt(e,t){let n=Lp(e)?e:{};return{version:t.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((r)=>n[r]!==void 0).map((r)=>[r,n[r]]))}}function Nr(e,t){return Object.fromEntries(Object.entries(t).flatMap(([n,r])=>r===void 0?[]:[[`${e}.${n}`,String(r)]]))}function Hr(e){return e.length===0?"(none)":e.join(", ")}function Lp(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Rp(e){let t=ct(),n=E({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},e);if(fe(n.errors))return null;if(n.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(n.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let r=n.values.limit===void 0?20:ys(n.values.limit);if(r===null)return console.error("--limit must be a positive number"),null;let o=n.values.since===void 0?Math.min(30,t):ys(n.values.since);if(o===null||o>t)return console.error(`--since must be a positive number of days no greater than ${t}`),null;let i={limit:r,limitExplicit:n.values.limit!==void 0,since:o,sinceExplicit:n.values.since!==void 0,all:n.flags.all,json:n.flags.json,suspect:n.flags.suspect,pruneLegacy:n.flags.pruneLegacy,dryRun:n.flags.dryRun,id:n.values.id,agent:n.values.agent,rule:n.values.rule,session:n.values.session,project:n.values.project===void 0?void 0:Sp(n.values.project)};if(i.id&&(i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.sinceExplicit||i.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(i.pruneLegacy&&(i.id!==void 0||i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.all||i.sinceExplicit||i.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(i.dryRun&&!i.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return i}async function Ls(e,t={}){let n=Rp(e);if(!n)return 1;let r=t.logsDir??be();if(n.pruneLegacy)return Pp(r,n.json,n.dryRun);if(!r)return console.log(n.json?"[]":n.id?`No retained audit log entry found for id ${F(n.id)}.`:"No audit log entries found."),0;He(r);let o={count:0},i=Ce(r,o).flatMap((d)=>Fe(d,o).map((m)=>({entry:m,file:d})));if(o.count>0)console.error(`warning: ${o.count} audit log ${o.count===1?"source":"sources"} could not be read; these results are incomplete`);if(n.id)return _p(i,n,t.timeZone);let s=Date.now()-n.since*24*60*60*1000,a=i.filter((d)=>Tp(d,n,r,s)),l=n.suspect?hr(a.map((d)=>d.entry)):null,c=(l?a.filter((d)=>l.has(d.entry)):a).sort((d,m)=>Date.parse(m.entry.ts)-Date.parse(d.entry.ts)).slice(0,n.limit);if(n.json)return console.log(JSON.stringify(c.map((d)=>d.entry),null,2)),0;if(c.length===0)return console.log("No audit log entries found."),0;for(let d of c)console.log(Op(d.entry,t.timeZone));return 0}function Pp(e,t,n){let r=e?Ap(e).map((a)=>Cp(e,a)):[];if(n)return Dp(r,t);let o=[],i=0,s=0;for(let a of r){let l=vs(a,{throwIfNoEntry:!1})?.size??0,c=Ep(a);if(c){o.push(`${bs(a)}: ${c}`);continue}i++,s+=l}if(t)return console.log(JSON.stringify({removedFiles:i,removedBytes:s,failedFiles:o.length})),o.length===0?0:1;console.log(i===0&&o.length===0?"No legacy audit log files found.":`Removed ${i} legacy audit log ${i===1?"file":"files"} (${ws(s)}).`);for(let a of o)console.error(`Could not remove ${F(a)}`);if(console.log("Nested v2 audit logs were not changed."),i>0)console.log("This deletion cannot be undone.");return o.length===0?0:1}function Dp(e,t){let n=e.reduce((r,o)=>r+(vs(o,{throwIfNoEntry:!1})?.size??0),0);if(t)return console.log(JSON.stringify({dryRun:!0,files:e.length,bytes:n})),0;if(console.log(e.length===0?"No legacy audit log files found.":`Would remove ${e.length} legacy audit log ${e.length===1?"file":"files"} (${ws(n)}).`),console.log("Nested v2 audit logs are not included."),e.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Ap(e){try{return wp(e,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function Ep(e){try{return kp(e),null}catch(t){return t instanceof Error?t.message:String(t)}}function ws(e){let t=["B","KiB","MiB","GiB"],n=Math.min(Math.floor(Math.log2(Math.max(e,1))/10),t.length-1);return`${Math.round(e/1024**n*10)/10} ${t[n]}`}function _p(e,t,n){let r=e.filter((i)=>i.entry.id===t.id);if(r.length>1)return console.error(`Multiple audit log entries found for id ${F(t.id??"")}.`),1;if(t.json)return console.log(JSON.stringify(r.map((i)=>i.entry),null,2)),0;let o=r[0];if(!o)return console.log(`No retained audit log entry found for id ${F(t.id??"")}.`),0;return console.log(Fp(o.entry,n)),0}function Tp(e,t,n,r){if(!t.all&&e.entry.decision==="allow")return!1;if(Date.parse(e.entry.ts)<r)return!1;if(t.agent!==void 0&&e.entry.agent!==t.agent)return!1;if(t.rule!==void 0&&e.entry.ruleId!==t.rule)return!1;if(t.session!==void 0&&!Ip(e,n,t.session))return!1;if(t.project!==void 0&&!$p(e.entry.cwd,t.project))return!1;return!0}function Ip(e,t,n){if(e.entry.sessionId===n)return!0;return xp(e.file)===t&&bs(e.file,".jsonl")===n}function $p(e,t){if(!e)return!1;return e===t||e.startsWith(`${t}/`)}function Op(e,t){let n=F(e.id??"-"),r=F(e.decision??"deny"),o=e.cwd?` [${F(e.cwd)}]`:"",i=e.segment||e.command,s=i===e.command?"":"↳ ",a=i.length>50?`${i.slice(0,50)}…`:i;return`${n.padEnd(16)} ${F(ks(e.ts,t))} ${r.padEnd(5)} ${F(e.agent??"-").padEnd(15)} ${F(e.ruleId??"-").padEnd(20)} ${s}${F(a)}${o}`}function Fp(e,t){let n=(o)=>F(o===void 0||o===null||o===""?"-":o),r=e.shape?`${e.agent??"-"} (shape: ${e.shape})`:e.agent??"-";return[`id: ${n(e.id)}`,`ts: ${n(ks(e.ts,t))}`,`decision: ${n(e.decision)}`,`agent: ${n(r)}`,`level: ${n(e.level)}`,`tool: ${n(e.toolName)}`,`rule: ${n(e.ruleId)}`,`intent: ${n(e.intent)}`,`stage: ${n(e.failureStage)}`,`error: ${n(e.errorCode)}`,`session: ${n(e.sessionId)}`,`cwd: ${n(e.cwd)}`,`version: ${n(e.v)}`,`truncated: ${n(e.truncated===!0?"yes":void 0)}`,`reason: ${n(e.reason)}`,`command: ${n(e.command)}`,`segment: ${n(e.segment)}`].join(`
|
|
6
|
+
`)}function ks(e,t){let n=new Date(e);if(Number.isNaN(n.getTime()))return e;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:t}).format(n)}function ys(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:null}var xs={name:"doctor",aliases:["--doctor"],description:"Run diagnostic checks to verify installation and configuration",usage:"doctor [options]",options:[{flags:"--json",description:"Output diagnostics as JSON"},{flags:"--skip-update-check",description:"Skip npm registry version check"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net doctor","cc-safety-net doctor --json","cc-safety-net doctor --skip-update-check"]};var Cs={name:"explain",description:"Show step-by-step analysis trace of how a command would be analyzed",usage:"explain [options] <command>",argument:"<command>",options:[{flags:"--json",description:"Output analysis as JSON"},{flags:"--cwd",argument:"<path>",description:"Use custom working directory"},{flags:"-h, --help",description:"Show this help"}],examples:['cc-safety-net explain "git reset --hard"','cc-safety-net explain --json "rm -rf /"','cc-safety-net explain --cwd /tmp "git status"']};var Ss={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};import{isAbsolute as $s,join as Kp,relative as Jp}from"node:path";var jp=8388608;function Np(e,t){console.log(JSON.stringify(e(Ps(t))))}async function Hp(e){let t;try{t=(await Wr(process.stdin)).trim()}catch{e({reason:"Failed to parse hook input JSON."});return}if(!t){e({reason:"Missing hook input JSON."});return}return Yr(t,e,"Failed to parse hook input JSON.")}async function Wr(e){let t=[],n=0;for await(let r of e){let o=typeof r==="string"?Buffer.from(r,"utf-8"):Buffer.from(r.buffer,r.byteOffset,r.byteLength);if(n+=o.byteLength,n>jp)throw Mp(e),Error("hook input byte limit exceeded");t.push(o)}return Buffer.concat(t,n).toString("utf-8")}function Mp(e){let t=e.destroy??e.cancel;if(!t)return;try{Promise.resolve(t.call(e)).catch(()=>{})}catch{}}function Yr(e,t,n){try{return JSON.parse(e)}catch{t({reason:n});return}}function j(e,t){let n=t.get(e);return n?{kind:"command",shell:n}:{kind:As(e)}}function ae(e,t,n,r){let o=e===void 0?process.cwd():e,i=typeof o==="string"&&o.trim()!==""?Z([o]):void 0;if(i)return{configCwd:i,executionCwd:i};return T(r,t,n,qp(o)),null}function T(e,t,n,r){let o;try{o=Jr(t)}catch(i){if(!(i instanceof Le))throw i}e(vn({command:o,segment:r,toolName:n}))}async function Up(e){let t=await Hp(e.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){T(e.outputDeny);return}if(!e.isSupported(t))return;let n=e.getAgent?.(t)??e.agent,r=e.agent===n?void 0:e.agent,o=zp(t),i=(u,p)=>{Rs(u,()=>e.getSessionId(t),{agent:n,shape:r,toolName:p,cwd:o}),e.outputDeny(u)},s=e.getToolName(t);if(typeof s!=="string"||s.trim()===""){T((u)=>i(u),Vp(t));return}let a=s,l=(u)=>i(u,a),c;try{c=e.getToolInput(t,a,l)}catch(u){if(!(u instanceof Le))throw u;T(l,void 0,a);return}if(!c.ok)return;let d=e.getContext(t,c.input,a,l);if(!d)return;let m;try{m=Jr(c.input)}catch(u){if(!(u instanceof Le))throw u;T(l,void 0,a);return}let g=st(a,c.input,c.route,d,m??null);try{let u=bn(g,{guard:{auditAllowed:Es(),dependencies:e.guardDependencies},audit:{agent:n,shape:r,getSessionId:()=>e.getSessionId(t)}}),p=Kr(u,{includeEvidence:!0,toolName:u.stage==="command-analysis"?void 0:a});if(p){e.outputDeny(p);return}e.outputAllow?.()}catch(u){if(!(u instanceof _s))throw u;Gp(u);let p=Kr(u.evaluation,{includeEvidence:!0,toolName:u.evaluation.stage==="command-analysis"?void 0:a});if(p)e.outputDeny(p);return}}function Gp(e){if(!Nt(S.debug))return;console.error(`CC Safety Net debug: ${Bp(e.stage)}: ${Ds(e.cause)}`)}function Bp(e){if(e==="policy-protection")return"hook policy protection failed";if(e==="config-load")return"hook config loading failed";if(e==="secret-protection")return"hook secret protection failed";return"hook analysis failed"}function qp(e){return typeof e==="string"?e:void 0}function Vp(e){if(!e||typeof e!=="object"||Array.isArray(e))return;if(Object.hasOwn(e,"tool_input"))return e.tool_input;let t=e.toolCall;if(t&&typeof t==="object"&&!Array.isArray(t))return t.args;return}function zp(e){if(!e||typeof e!=="object"||Array.isArray(e))return null;let t=e.cwd;if(typeof t==="string")return t;let n=e.toolCall;if(!n||typeof n!=="object"||Array.isArray(n))return null;let r=n.args;if(!r||typeof r!=="object"||Array.isArray(r))return null;let o=r.Cwd;return typeof o==="string"?o:null}async function N(e){let t=(o)=>Np(e.createDenyOutput,o),n=e.createAllowOutput;await Up({...e,outputDeny:t,outputAllow:n?()=>console.log(JSON.stringify(n())):void 0})}function Gt(e){return Kp(e,".gemini","config","hooks.json")}var Wp=new Map([["run_command","auto"]]),Yp=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function Os(e){return j(e,Wp)}async function Fs(){await N({agent:"antigravity-cli",createDenyOutput:(e)=>({decision:"deny",reason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolCall?.name,getToolInput:(e,t)=>({ok:!0,input:t2(e.toolCall?.args,t),route:Os(t)}),getContext:Zp,getSessionId:(e)=>e.conversationId})}function Zp(e,t,n,r){let i=e2(e).flatMap((c)=>{let d=Z([c]);return d?[d]:[]});if(!i[0])return qe(r,t,n),null;if(n!=="run_command"){let c;try{c=Xp(t,n,i)}catch(d){if(d instanceof Le)return qe(r,void 0,n),null;if(!(d instanceof Me))throw d;return qe(r,t,n),null}if(!c)return qe(r,t,n),null;return{configCwd:c,executionCwd:c}}let s=e.toolCall?.args;if(!s||!Object.hasOwn(s,"Cwd"))return{configCwd:i[0],executionCwd:i[0]};let a=s.Cwd;if(typeof a!=="string"||a.trim()==="")return qe(r,t,n),null;let l=we(a,i);if(l){let c=js(l,i);if(!c)return qe(r,t,n,a),null;return{configCwd:c,executionCwd:l}}return qe(r,t,n,a),null}function Xp(e,t,n){let r=Os(t),o=[...Ts(e,Yp),...r.kind==="patch"?Is(e):[]].filter($s),i=Ln(),s=new Set(o.flatMap((a)=>{let l=js(Ut(a,Mt,i),n);return l?[l]:[]}));if(s.size>1)return null;return[...s][0]??n[0]??null}function js(e,t){return t.filter((n)=>Qp(e,n)).reduce((n,r)=>r.length>n.length?r:n,"")||null}function Qp(e,t){let n=Jp(t,e);return n===""||!n.startsWith("..")&&!$s(n)}function qe(e,t,n,r){let o=t&&typeof t==="object"?t.command:void 0;e(vn({command:typeof o==="string"?o:void 0,segment:r,toolName:n}))}function e2(e){if(e.workspacePaths===void 0)return[process.cwd()];let t=Array.isArray(e.workspacePaths)?e.workspacePaths.filter((n)=>typeof n==="string"&&n.trim()!==""):[];return Z(t)?t:[]}function t2(e,t){if(!e)return;if(t!=="run_command")return e;return{...e,command:typeof e.CommandLine==="string"&&e.CommandLine!==""?e.CommandLine:void 0}}var Bt=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],wn=Bt.slice().sort((e,t)=>e.doctorOrder-t.doctorOrder).map((e)=>e.id),Ns=Bt.filter((e)=>("runtime"in e)).slice().sort((e,t)=>e.runtime.order-t.runtime.order).map((e)=>({id:e.id,displayName:"displayName"in e.runtime?e.runtime.displayName:e.displayName,flags:e.runtime.flags,legacyFlags:"legacyFlags"in e.runtime?e.runtime.legacyFlags:[],description:e.runtime.description,legacyTopLevelFlags:e.runtime.legacyTopLevelFlags})),X=Bt.slice().sort((e,t)=>e.install.order-t.install.order).map((e)=>({id:e.id,...e.install})).map(({order:e,...t})=>t),Yv=Object.fromEntries(Bt.map((e)=>[e.id,e.displayName]));function D(e){return Bt.find((t)=>t.id===e)?.displayName??e}import{homedir as n2}from"node:os";import{isAbsolute as Hs,join as Zr}from"node:path";function Us(e){if(e!==void 0&&e!==null&&typeof e!=="string")return"unknown";if(typeof e==="string"&&!Hs(e))return"unknown";try{let t=Ln(),n=typeof e==="string"&&e?Ut(e,Mt,t):void 0,r=process.env.HOME||n2(),o=[["codex",process.env.CODEX_HOME||Zr(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||Zr(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||Zr(r,".claude")]],i=n?o.flatMap(([s,a])=>{if(!Hs(a))return[];return Ms(n,Ut(a,Mt,t))?[s]:[]}):[];if(i.length===1)return i[0]??"unknown";if(i.length>1)return"unknown"}catch(t){if(t instanceof Me)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var Xr="PreToolUse",Gs="BeforeTool",Bs="pre_tool_call",Qr="PreToolUse";async function kn(e){await N({agent:e.agent,...e.getAgent?{getAgent:e.getAgent}:{},createDenyOutput:(t)=>({hookSpecificOutput:{hookEventName:Xr,permissionDecision:"deny",permissionDecisionReason:t}}),isSupported:(t)=>t.hook_event_name===Xr,getToolName:(t)=>t.tool_name,getToolInput:(t,n)=>({ok:!0,input:t.tool_input,route:e.getToolRoute(n)}),getContext:(t,n,r,o)=>ae(t.cwd,n,r,o),getSessionId:(t)=>t.session_id})}var r2=new Map([["Bash","posix"],["PowerShell","powershell"]]);function o2(e){return j(e,r2)}async function qs(){await kn({agent:"claude-code",getAgent:(e)=>Us(e.transcript_path),getToolRoute:o2})}var i2=new Map([["Bash","auto"]]);async function Vs(){await kn({agent:"codex",getToolRoute:(e)=>j(e,i2)})}var s2=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function a2(e){return j(e,s2)}async function zs(){await N({agent:"copilot-cli",createDenyOutput:(e)=>({permissionDecision:"deny",permissionDecisionReason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(typeof e.toolArgs!=="string")return n({reason:"Failed to parse toolArgs JSON."}),{ok:!1};let r=Yr(e.toolArgs,n,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:a2(t)}},getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>typeof e.sessionId==="string"&&e.sessionId.trim()?e.sessionId:void 0})}var l2=new Map([["Shell","auto"]]);function c2(e){return j(e,l2)}async function Ks(){await N({agent:"cursor",createDenyOutput:(e)=>({permission:"deny",user_message:e,agent_message:e}),createAllowOutput:()=>({permission:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:c2(t)}),getContext:d2,getSessionId:(e)=>e.conversation_id})}function d2(e,t,n,r){let o=u2(e);if(!o[0])return T(r,t,n),null;let i=we(f2(e.cwd),o);if(!i)return T(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;if(t===null||typeof t!=="object"||Array.isArray(t))return{configCwd:i,executionCwd:i};if(!Object.hasOwn(t,"working_directory"))return{configCwd:i,executionCwd:i};let s=t.working_directory;if(typeof s!=="string"||s.trim()==="")return T(r,t,n),null;let a=we(s,o);if(!a)return T(r,t,n,s),null;return{configCwd:i,executionCwd:a}}function u2(e){return p2(e).flatMap((t)=>{let n=Z([t]);return n?[n]:[]})}function p2(e){if(e.workspace_roots===void 0)return typeof e.cwd==="string"&&e.cwd.trim()!==""?[e.cwd]:[];if(!Array.isArray(e.workspace_roots))return[];return e.workspace_roots.filter((t)=>typeof t==="string"&&t.trim()!=="")}function f2(e){return typeof e==="string"&&e.trim()!==""?e:"."}var m2=new Map([["run_shell_command","auto"]]);function g2(e){return j(e,m2)}async function Js(){await N({agent:"gemini-cli",createDenyOutput:(e)=>({decision:"deny",reason:e,systemMessage:e}),isSupported:(e)=>e.hook_event_name===Gs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:g2(t)}),getContext:(e,t,n,r)=>ae(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var h2=new Map([["run_terminal_command","auto"]]);function y2(e){return j(e,h2)}async function Ws(){await N({agent:"grok-build",createDenyOutput:(e)=>({decision:"deny",reason:e}),createAllowOutput:()=>({decision:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(e.toolInputTruncated===!0)return T(n,e.toolInput,t),{ok:!1};return{ok:!0,input:e.toolInput,route:y2(t)}},getContext:v2,getSessionId:(e)=>e.sessionId})}function v2(e,t,n,r){let o=Z(b2(e));if(!o)return T(r,t,n),null;let i=we(L2(e.cwd),[o]);if(!i)return T(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;return{configCwd:i,executionCwd:i}}function b2(e){let t=e.workspaceRoot===void 0?e.cwd:e.workspaceRoot;return typeof t==="string"&&t.trim()!==""?[t]:[]}function L2(e){return typeof e==="string"&&e.trim()!==""?e:"."}import{resolve as w2}from"node:path";var k2=new Map([["terminal","posix"]]);async function Ys(){await N({agent:"hermes-agent",createDenyOutput:(e)=>({action:"block",message:e}),isSupported:(e)=>e.hook_event_name===Bs,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:j(t,k2)}),getContext:x2,getSessionId:(e)=>e.session_id})}function x2(e,t,n,r){let o=ae(e.cwd,t,n,r);if(!o)return null;if(!t||typeof t!=="object"||Array.isArray(t))return o;if(!Object.hasOwn(t,"workdir"))return o;let i=t.workdir;if(typeof i!=="string"||i.trim()==="")return T(r,t,n),null;let s=Z([w2(o.configCwd,i)]);if(!s)return T(r,t,n,i),null;return{...o,executionCwd:s}}var Zs=new Map([["Bash","posix"]]);function C2(e){return j(e,Zs)}async function Xs(){await N({agent:"kimi-code",createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:Qr,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===Qr,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:C2(t)}),getContext:(e,t,n,r)=>{let o=ae(e.cwd,t,n,r);if(!o)return null;let i=e.tool_input;if(!Zs.has(n)||!i||!Object.hasOwn(i,"cwd"))return o;let s=i.cwd;if(typeof s!=="string"||s.trim()==="")return T(r,t,n),null;let a=we(s,[o.configCwd]);if(!a)return T(r,t,n,s),null;return{configCwd:o.configCwd,executionCwd:a}},getSessionId:(e)=>e.session_id})}var S2={"antigravity-cli":Fs,"claude-code":qs,codex:Vs,"copilot-cli":zs,cursor:Ks,"gemini-cli":Js,"grok-build":Ws,"hermes-agent":Ys,"kimi-code":Xs},dt=Ns.map((e)=>({...e,run:S2[e.id]}));function Qs(e){let t=E({label:"hook",booleans:Object.fromEntries(dt.map((r)=>[r.id,[...r.flags,...r.legacyFlags]]))},e);if(t.errors.length>0)return;let n=dt.filter((r)=>t.flags[r.id]);return n.length===1?n[0]:void 0}function ea(e){return dt.find((t)=>t.legacyTopLevelFlags.some((n)=>n===e))}var R2=dt.map((e)=>({flags:e.flags.join(", "),description:e.description})),P2=dt.flatMap((e)=>e.flags.map((t)=>`cc-safety-net hook ${t}`)),ta={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...R2,{flags:"-h, --help",description:"Show this help"}],examples:P2};var na={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...X.map((e)=>({flags:e.flag,description:`Install ${D(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...X.map((e)=>`cc-safety-net install ${e.flag}`)]},ra={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...X.map((e)=>({flags:e.flag,description:`Uninstall ${D(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...X.map((e)=>`cc-safety-net uninstall ${e.flag}`)]},oa={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var ia={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],ut={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var sa={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var aa={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var Cn=[sa,xs,ia,Cs,ut,xn,na,oa,ra,ta,Ss,aa];function D2(e){return e.aliases??[]}function Sn(e){let t=e.toLowerCase();return Cn.find((n)=>n.name.toLowerCase()===t||D2(n).some((r)=>r.toLowerCase()===t))}import{basename as A2}from"node:path";function Rn(e=7,t=be()){let n=Date.now()-e*24*60*60*1000,r=[],o=new Set,i=0,s,a,l,c;if(t)He(t);let d={count:0},m=t?Ce(t,d):[];for(let u of m)for(let p of Fe(u,d)){if(p.decision==="allow")continue;let f=new Date(p.ts).getTime();if(f>=n){if(i++,o.add(p.sessionId??A2(u,".jsonl")),a===void 0||f<=a)s=p.ts,a=f;if(c===void 0||f>c)l=p.ts,c=f;E2(r,p,f)}}let g=r.map((u)=>({timestamp:u.ts,command:u.command,reason:u.reason,relativeTime:gr(new Date(u.ts))}));return{totalBlocked:i,sessionCount:o.size,recentEntries:g,oldestEntry:s,newestEntry:l,unreadable:d.count}}function E2(e,t,n){let r=e.findIndex((o)=>n>new Date(o.ts).getTime());if(r===-1){if(e.length<3)e.push(t);return}if(e.splice(r,0,t),e.length>3)e.pop()}import{dirname as _2}from"node:path";function la(e,t,n){let r;try{if(w(t)===null)return{path:e,exists:!1,valid:!1,ruleCount:0};r=me(t),r.errors.push(...W(e,n))}catch(o){if(!(o instanceof H))throw o;r={errors:[o.message],ruleNames:new Set}}return{path:e,exists:!0,valid:r.errors.length===0,ruleCount:r.ruleNames.size,...r.errors.length>0?{errors:r.errors}:{}}}function T2(e,t){return{source:t,name:e.name,command:e.command,subcommand:e.subcommand,blockArgs:[...e.block_args],reason:e.reason}}function ca(e,t){let n=t?.userConfigPath??ie(),r=t?.projectConfigPath??oe(e),o=_2(n),i=De({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),s=Ae({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),a=new Map(i.rulebooks.flatMap((l)=>l.rules.map((c)=>[c,l.source])));return{userConfig:la(n,s.userConfigTarget,s.userScope),projectConfig:la(r,s.projectConfigTarget,s.projectScope),effectiveRules:i.rules.map((l)=>T2(l,a.get(l.name)??"project")),shadowedRules:[]}}var I2=[{flag:S.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:S.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:S.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:S.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:S.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:S.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:S.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:S.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function da(){return[...I2.map((e)=>({name:e.flag.name,value:Vr(e.flag),isSet:zr(e.flag),legacyName:e.flag.legacyName,legacyValue:e.flag.legacyName?process.env[e.flag.legacyName]:void 0,legacyIsSet:e.flag.legacyName?process.env[e.flag.legacyName]!==void 0:void 0,description:e.description,defaultBehavior:e.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:process.env.CC_SAFETY_NET_HOME,isSet:process.env.CC_SAFETY_NET_HOME!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ua={error:0,warning:1,info:2},$2=["policy","config","audit"];function O2(e){return e.map((t)=>{if(t==="ownership")return"is not owned by the current user";if(t==="permissions")return"has unsafe permissions";if(t==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var F2=[{derive:(e)=>e.hooks.length>0&&e.hooks.every((t)=>!t.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(e)=>e.hooks.filter((t)=>t.inspectionStatus==="failed").map((t)=>{let n=D(t.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${n} inspection failed`,detail:`Doctor could not verify the ${n} integration configuration.`,fixHint:`Correct the reported ${n} configuration error, then run \`cc-safety-net doctor\` again.`,integration:t.platform}})},{derive:(e)=>e.userConfig.exists&&!e.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.userConfig.path}]:[]},{derive:(e)=>e.projectConfig.exists&&!e.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.projectConfig.path}]:[]},{derive:(e)=>e.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${e.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(e)=>e.v2Leftovers&&e.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${e.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(e)=>{let t=e.environment.find((n)=>n.name==="CC_SAFETY_NET_AUDIT_SCOPE");return qr(t?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...$2.map((e)=>({derive:(t)=>t.posture.directories.filter((n)=>n.kind===e&&n.status==="unsafe").map((n)=>({checkId:`posture.${e}-directory-unsafe`,severity:"error",title:`${e[0]?.toUpperCase()}${e.slice(1)} directory is unsafe`,detail:`The ${e} directory ${O2(n.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...n.path?{path:n.path}:{}}))})),{derive:(e)=>{let t=[...e.effectiveSafety.weakenedRuleOverrides].sort();return t.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${t.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${t.join(", ")}.`}]:[]}}];function pa(e){return F2.flatMap((t,n)=>t.derive(e).map((r,o)=>({finding:r,catalogOrder:n,occurrence:o}))).sort((t,n)=>ua[t.finding.severity]-ua[n.finding.severity]||t.catalogOrder-n.catalogOrder||t.occurrence-n.occurrence).map((t)=>t.finding)}function le(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var j2=(e)=>le()?`\x1B[32m${e}\x1B[0m`:e,N2=(e)=>le()?`\x1B[33m${e}\x1B[0m`:e,H2=(e)=>le()?`\x1B[34m${e}\x1B[0m`:e,M2=(e)=>le()?`\x1B[35m${e}\x1B[0m`:e,U2=(e)=>le()?`\x1B[36m${e}\x1B[0m`:e,G2=(e)=>le()?`\x1B[31m${e}\x1B[0m`:e,B2=(e)=>le()?`\x1B[2m${e}\x1B[0m`:e,q2=(e)=>le()?`\x1B[1m${e}\x1B[0m`:e,y={green:j2,yellow:N2,blue:H2,magenta:M2,cyan:U2,red:G2,dim:B2,bold:q2},V2="\x1B[0m",z2=[39,82,198,226,208,51,196,46,201,214,93,154,220,27,49,190,200,33,129,227,45,160,63,118,123,202];function K2(e){let t=e;return()=>(t=(t*1664525+1013904223)%4294967296,t/4294967296)}function J2(e){let t=[...z2],n=K2(e);for(let r=t.length-1;r>0;r--){let o=Math.floor(n()*(r+1)),i=t[r];t[r]=t[o],t[o]=i}return t}function W2(e,t=0){if(!le())return"";let n=J2(t);return`\x1B[38;5;${n[e%n.length]}m`}function fa(e,t,n=0){if(!le())return`"${e}"`;return`${W2(t,n)}"${e}"${V2}`}function Pn(e){return e==="default"?"built-in default":`${e} policy`}var Y2=new RegExp("\x1B\\[[0-9;]*m","g"),no=(e)=>e.replace(Y2,"").length;function Ve(e){let t=(e.headers??e.rows[0]??[]).map((s,a)=>{let l=Math.max(...e.rows.map((c)=>no(c[a]??"")));return Math.max(no(s),l)}),n=(s,a)=>s+" ".repeat(Math.max(0,a-no(s))),r=(s,a)=>a[0]+t.map((l)=>s.repeat(l+2)).join(a[1])+a[2],o=(s)=>`│ ${s.map((a,l)=>n(a,t[l]??0)).join(" │ ")} │`,i=e.headers?[` ${o(e.headers)}`,` ${r("─",["├","┼","┤"])}`]:[];return[` ${r("─",["┌","┬","┐"])}`,...i,...e.rows.map((s)=>` ${o(s)}`),` ${r("─",["└","┴","┘"])}`].join(`
|
|
7
|
+
`)}function ma(e){let t=[];t.push("Hook Integration"),t.push(Z2(e));let n=[],r=[];for(let o of e){let i=D(o.platform);if(o.errors&&o.errors.length>0)for(let s of o.errors)if(o.configured)n.push({platform:i,message:s});else r.push({platform:i,message:s})}for(let o of n)t.push(` Warning (${o.platform}): ${o.message}`);for(let o of r)t.push(y.red(` Error (${o.platform}): ${o.message}`));return t.join(`
|
|
8
|
+
`)}function Z2(e){let t=["Platform","Discovery","Configuration","Inspection"],n=e.map((r)=>{let o=D(r.platform);if(r.inspectionStatus==="not-inspected"){let l=y.dim("Not inspected");return[o,l,l,l]}let i=r.detected?y.green("Detected"):r.inspectionStatus==="failed"?y.red("Unknown"):y.dim("Not detected"),s=r.configured?y.green("Configured"):r.detected?y.yellow("Not configured"):r.inspectionStatus==="failed"?y.red("Unknown"):y.dim("Not applicable"),a=r.inspectionStatus==="verified"?y.green("Verified"):r.inspectionStatus==="failed"?y.red("Failed"):y.dim("Not applicable");return[o,i,s,a]});return Ve({headers:t,rows:n})}function ga(e){let n=["Guard Engine Verification",` Synthetic self-test: ${e.failed>0?y.red(`${e.passed}/${e.total} FAIL`):y.green(`${e.passed}/${e.total} passed`)}`],r=e.results.filter((o)=>!o.passed);if(r.length>0){n.push(""),n.push(y.red(" Failures:"));for(let o of r)n.push(y.red(` • ${o.description}`)),n.push(y.red(` expected ${o.expected}, got ${o.actual}`))}return n.join(`
|
|
9
|
+
`)}function X2(e){if(e.length===0)return" (no custom rules)";let t=["Source","Name","Command","Block Args"],n=e.map((r)=>[r.source,r.name,r.subcommand?`${r.command} ${r.subcommand}`:r.command,r.blockArgs.join(", ")]);return Ve({headers:t,rows:n})}function ha(e){let t=[];if(t.push("Configuration"),t.push(Q2(e.userConfig,e.projectConfig)),t.push(""),e.effectiveRules.length>0)t.push(` Effective rules (${e.effectiveRules.length} total):`),t.push(X2(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 Q2(e,t){let n=["Scope","Status"],r=(i)=>{if(!i.exists)return y.dim("N/A");if(!i.valid)return y.red(`Invalid (${i.errors?.[0]??"unknown error"})`);return y.green("Configured")},o=[["User",r(e)],["Project",r(t)]];return Ve({headers:n,rows:o})}function ya(e){let t=[];return t.push("Environment"),t.push(ef(e)),t.join(`
|
|
11
|
+
`)}function va(e){let t=e.effectiveSafety.policyScopes,n=["Effective Safety",` Selected preset: ${e.effectiveSafety.selectedPreset}${t?` (${Pn(t.levelScope)})`:""}`,` Effective: ${e.effectiveSafety.level}`],r=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[o,i]of r){let s=e.effectiveSafety.capabilities[o],a=s.enabled?y.green("ON"):y.dim("OFF"),l=s.sources.length>0?` (${s.sources.join(", ")})`:"";n.push(` ${i}: ${a} via ${s.source}${l}`)}if(t&&t.weakenings.length>0){n.push(" Project policy deltas:");for(let o of t.weakenings)n.push(` ${o}`)}n.push(` Stored rule customizations: ${e.effectiveSafety.ruleCounts.stored}`),n.push(` Effective rule customizations: ${e.effectiveSafety.ruleCounts.effective}`);for(let[o,i]of Object.entries(e.effectiveSafety.ruleOverrides))n.push(` ${o}: ${i}`);return n.join(`
|
|
12
|
+
`)}function ba(e){let t=["Findings"];if(e.length===0)return t.push(" No findings from inspected doctor facts."),t.join(`
|
|
13
13
|
`);for(let n of e){let r=`[${n.severity.toUpperCase()}] ${n.checkId}: ${F(n.title)}`,o=n.severity==="error"?y.red:n.severity==="warning"?y.yellow:y.blue;if(t.push(` ${o(r)}`),t.push(` ${F(n.detail)}`),n.path)t.push(` Path: ${F(n.path)}`);if(n.fixHint)t.push(` Fix: ${F(n.fixHint)}`)}return t.join(`
|
|
14
|
-
`)}function
|
|
15
|
-
`)}function
|
|
14
|
+
`)}function ef(e){let t=["Variable","Status","Legacy"],n=e.map((r)=>{let o=r.isSet?y.green("✓"):y.dim("✗"),i=r.legacyName&&r.legacyIsSet?`${r.legacyName} ${y.green("✓")}`:r.legacyName??"";return[r.name,o,i]});return Ve({headers:t,rows:n})}function La(e){let t=[];if(e.totalBlocked===0)t.push("Recent Activity"),t.push(" No blocked commands in the last 7 days"),t.push(" Tip: This is normal for new installations");else t.push(`Recent Activity · last 7 days (${e.totalBlocked} blocked / ${e.sessionCount} sessions)`),t.push(tf(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 tf(e){let t=["Time","Command"],n=e.map((r)=>{let o=F(r.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),i=o.length>40?`${o.slice(0,37)}...`:o;return[r.relativeTime,i]});return Ve({headers:t,rows:n})}function wa(e){let t=[];if(t.push("Update Check"),e.latestVersion===null&&!e.error)return t.push(Dn([["Status",y.dim("Skipped")],["Installed",e.currentVersion]])),t.join(`
|
|
16
16
|
`);if(e.error)return t.push(Dn([["Status",`${y.yellow("⚠")} Error`],["Installed",e.currentVersion],["Error",y.dim(e.error)]])),t.join(`
|
|
17
17
|
`);if(e.updateAvailable)return t.push(Dn([["Status",`${y.yellow("⚠")} Update Available`],["Current",e.currentVersion],["Latest",y.green(e.latestVersion??"")]])),t.push(""),t.push(" Run: bunx cc-safety-net@latest doctor"),t.push(" Or: npx cc-safety-net@latest doctor"),t.join(`
|
|
18
18
|
`);return t.push(Dn([["Status",`${y.green("✓")} Up to date`],["Version",e.currentVersion]])),t.join(`
|
|
19
|
-
`)}function Dn(e){return Ve({rows:e})}function
|
|
20
|
-
`)}function
|
|
19
|
+
`)}function Dn(e){return Ve({rows:e})}function ka(e){let t=[];return t.push("System Info"),t.push(nf(e)),t.join(`
|
|
20
|
+
`)}function nf(e){let t=["Component","Version"],n=(i)=>{if(i===null)return y.dim("not found");return i},o=[{label:"cc-safety-net",value:e.version},...wn.map((i)=>({label:D(i),value:e.versions[i]??null})),{label:"Node.js",value:e.nodeVersion},{label:"npm",value:e.npmVersion},{label:"Bun",value:e.bunVersion},{label:"Platform",value:e.platform}].map((i)=>[i.label,n(i.value)]);return Ve({headers:t,rows:o})}function xa(e){if(e.findings.length===0)return y.green(`
|
|
21
21
|
No findings from inspected doctor facts.`);let t={error:e.findings.filter((i)=>i.severity==="error").length,warning:e.findings.filter((i)=>i.severity==="warning").length,info:e.findings.filter((i)=>i.severity==="info").length},n=["error","warning","info"].filter((i)=>t[i]>0).map((i)=>`${t[i]} ${i}`),r=e.findings.length===1?"finding":"findings",o=`
|
|
22
|
-
${e.findings.length} ${r}: ${n.join(", ")}.`;if(t.error>0)return y.red(o);if(t.warning>0)return y.yellow(o);return y.blue(o)}import{lstatSync as
|
|
23
|
-
`)[0]?.trim()||null}async function qt(e=pt){let[t,n,r,o,i,s]=await Promise.all([Promise.all(X.map(async(a)=>[a.id,
|
|
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 rf}from"node:fs";import{dirname as ro}from"node:path";function oo(e,t){try{let n=rf(t);if(n.isSymbolicLink())return{kind:e,path:t,status:"unsafe",issues:["symlink"]};if(!n.isDirectory())return{kind:e,path:t,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:e,path:t,status:"unknown",issues:[]};let r=[...n.uid!==process.getuid()?["ownership"]:[],...(n.mode&18)!==0?["permissions"]:[]];return{kind:e,path:t,status:r.length>0?"unsafe":"safe",issues:r}}catch(n){if(typeof n==="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return{kind:e,path:t,status:"not-applicable",issues:[]};return{kind:e,path:t,status:"unknown",issues:[]}}}function Ca(e){let t=be();return{directories:[oo("policy",ro(ro(e))),oo("config",ro(e)),...t?[oo("audit",t)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as of}from"node:child_process";import{existsSync as Sa}from"node:fs";import{delimiter as sf,extname as af,join as lf}from"node:path";import{stripVTControlCharacters as Ra}from"node:util";var Da="2.3.2",cf=5000,df="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function I(){return Da}function io(e,t){let n=e[t];if(n)return n;let r=Object.keys(e).find((o)=>o.toLowerCase()===t.toLowerCase()&&!!e[o]);return r?e[r]:n}function uf(e){return(io(e,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((t)=>t.length>0)}function pf(e,t){let n=af(e)?[e]:[...uf(t).map((r)=>`${e}${r}`),e];if(e.includes("/")||e.includes("\\"))return n.find((r)=>Sa(r))??e;return(io(t,"PATH")??"").split(sf).flatMap((r)=>n.map((o)=>lf(r,o))).find((r)=>Sa(r))??e}function Pa(e){if(!/[\s"&|<>^]/.test(e))return e;return`"${e.replace(/"/g,'""')}"`}function ze(e,t){let[n,...r]=e,o=t[df]==="win32"?"win32":process.platform;if(!n||o!=="win32")return{cmd:n??"",args:r};let i=pf(n,t);if(!/\.(?:bat|cmd)$/i.test(i))return{cmd:i,args:r};return{cmd:io(t,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Pa(i),...r.map(Pa)].join(" ")]}}var pt=async(e,t=cf)=>{let n=await ff(e,{timeoutMs:t});if(n.code!==0)return null;return Ra(n.stdout).trim()||Ra(n.stderr).trim()||null};function ff(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=of(i.cmd,i.args,{stdio:["ignore","pipe","pipe"]}),a=!1,l="",c="";s.stdout.on("data",(g)=>{l+=g.toString()}),s.stderr.on("data",(g)=>{c+=g.toString()});let d=(g)=>{if(a)return;a=!0,clearTimeout(m),o(g)},m=setTimeout(()=>{s.kill(),d({code:null,stdout:l,stderr:c})},t.timeoutMs);s.on("close",(g)=>{d({code:g,stdout:l,stderr:c})}),s.on("error",()=>{d({code:null,stdout:l,stderr:c})})}catch{o({code:null,stdout:"",stderr:""})}})}function An(e){if(!e)return null;let t=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(e);if(t)return t[1]??null;let n=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(e);if(n)return n[1]??null;return e.split(`
|
|
23
|
+
`)[0]?.trim()||null}async function qt(e=pt){let[t,n,r,o,i,s]=await Promise.all([Promise.all(X.map(async(a)=>[a.id,An(await e([...a.probeCommand]))])),e(["codex","plugin","list"],30000),e(["amp","plugins","list"],30000),e(["node","--version"]),e(["npm","--version"]),e(["bun","--version"])]);return{version:Da,versions:Object.fromEntries(t),codexPluginListOutput:n,ampPluginListOutput:r,nodeVersion:An(o),npmVersion:An(i),bunVersion:An(s),platform:`${process.platform} ${process.arch}`}}function so(e,t){if(t==="dev")return!1;let n=e.split(".").map(Number),r=t.split(".").map(Number),[o=0,i=0,s=0]=n,[a=0,l=0,c=0]=r;if(o!==a)return o>a;if(i!==l)return i>l;return s>c}async function Te(){let e=I(),t=new AbortController,n=setTimeout(()=>t.abort(),3000);try{let r=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:t.signal});if(!r.ok)return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${r.status}`};let o=await r.json(),i=so(o.version,e);return{currentVersion:e,latestVersion:o.version,updateAvailable:i}}catch(r){return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:r instanceof Error?r.message:"Network error"}}finally{clearTimeout(n)}}import*as Fa from"node:readline";var Ta=(e)=>`\x1B[${e}B`,mf=(e)=>`\x1B[${e}A`;var Aa=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function gf(e){return new Promise((t)=>setTimeout(t,e))}function hf(e,t,n){if(!n)return t(e);if(n.aborted)return Promise.resolve();return new Promise((r,o)=>{let i=()=>n.removeEventListener("abort",s),s=()=>{i(),r()};n.addEventListener("abort",s,{once:!0}),t(e).then(()=>{i(),r()},(a)=>{i(),o(a)})})}function Vt(e,t){return e&&e>0?e:t}function En(e){return Math.max(0,Math.min(1,e))}function ft(e){return Math.max(0,Math.min(255,Math.round(e)))}function ao(e){return e<=0.0031308?12.92*e:1.055*e**0.4166666666666667-0.055}function yf(e,t,n){let r=n*Math.PI/180,o=t*Math.cos(r),i=t*Math.sin(r),s=(e+0.3963377774*o+0.2158037573*i)**3,a=(e-0.1055613458*o-0.0638541728*i)**3,l=(e-0.0894841775*o-1.291485548*i)**3;return{blue:ft(ao(En(-0.0041960863*s-0.7034186147*a+1.707614701*l))*255),green:ft(ao(En(-1.2684380046*s+2.6097574011*a-0.3413193965*l))*255),red:ft(ao(En(4.0767416621*s-3.3077115913*a+0.2309699292*l))*255)}}function lo(e,t){let n=(t*e*180/Math.PI%360+360)%360;return yf(0.72,0.15,n)}function Ia(e,t=0.1){let n=lo(t,e);return`\x1B[38;2;${n.red};${n.green};${n.blue}m`}function vf(e,t){return{blue:ft(e.blue+(255-e.blue)*t),green:ft(e.green+(255-e.green)*t),red:ft(e.red+(255-e.red)*t)}}function $a(e,t,n){let r=Math.imul(e+2654435769,2246822507)^Math.imul(t+3266489909,668265263)^Math.imul(n+374761393,2654435761),o=r^r>>>15,i=Math.imul(o,739982445),s=i^i>>>12,a=Math.imul(s,695872825);return((a^a>>>15)>>>0)/4294967296}function bf(e,t,n){let r=Math.floor($a(e,t,n)*Aa.length);return Aa[r]??"░"}function Ea(e){let t=En(e);return t*t*t*(t*(t*6-15)+10)}function Lf(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 wf(e,t,n,r,o){return e.map((i,s)=>({...lo(n,r+t+s/o),bold:!1,character:i}))}function kf(e,t,n,r,o,i,s,a){let l=Math.max(1,r*0.75),c=Math.min(1,n/l),d=o*Ea(c),m=Math.max(0,(n-l)/Math.max(1,r-l)),g=(1-Ea(n/r))*a*2,u=0.35*Math.max(0,1-m*2),p=c>=1,f=Math.min(e.length,Math.ceil(d+2+1));return e.slice(0,f).map((b,L)=>{let h=lo(i,s+t+L/a+g),R=L+$a(t,L,7919)*2-1;if(R>d+2)return{...h,bold:!1,character:" "};let v=d-R,P=0.8*Math.exp(-(v*v)/12.5),ne=Math.min(0.9,P+u),un=!p&&R>d-4;return{...vf(h,ne),bold:ne>0.3,character:un?bf(t,L,n):b}})}function _a(e){return`\x1B[?2026h${e.map((t,n)=>`\x1B8${n>0?Ta(n):""}${Lf(t)}`).join("")}\x1B[?2026l`}async function co(e,t={}){if(!e)return;let n=t.output??process.stdout,r=t.sleep??gf,o=Vt(t.frequency,0.1),i=t.seed??0,s=Vt(t.speed,40),a=Vt(t.spread,3),l=Vt(t.frameRate,60),c=Math.max(1,Math.floor(Vt(t.duration,12))),d=e.split(`
|
|
24
24
|
`).map((f)=>Array.from(f)),m=Math.max(...d.map((f)=>f.length)),g=1000*c*d.filter((f)=>f.length>0).length/s,u=m>0?Math.max(1,Math.ceil(g/(1000/l))):0,p=u>0?g/u:0;n.write(`\x1B[?25l${d.length>1?`${`
|
|
25
|
-
`.repeat(d.length-1)}${
|
|
26
|
-
\x1B[0m\x1B[?25h`)}}var
|
|
27
|
-
`);function
|
|
28
|
-
`).map((n)=>
|
|
29
|
-
`).find((n)=>n.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!t)return{platform:"codex",status:"n/a"};if(!t.includes("installed,"))return{platform:"codex",status:"n/a"};if(!t.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as
|
|
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
|
|
31
|
-
`)}function
|
|
32
|
-
`),{path:t,alreadyInstalled:!1};let n=
|
|
33
|
-
`)}function
|
|
25
|
+
`.repeat(d.length-1)}${mf(d.length-1)}`:""}\x1B7`);try{for(let f=1;f<=u;f+=1){if(t.signal?.aborted)break;n.write(_a(d.map((b,L)=>kf(b,L,f,u,m,o,i,a)))),await hf(p,r,t.signal)}}finally{if(n.write(_a(d.map((f,b)=>wf(f,b,o,i,a)))),n.write("\x1B8"),d.length>1)n.write(Ta(d.length-1));n.write(`
|
|
26
|
+
\x1B[0m\x1B[?25h`)}}var Oa=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
|
|
27
|
+
`);function xf(e){return Boolean(e.isTTY)}async function zt(e={}){let t=e.output??process.stdout;if(!xf(t))return;let n=e.input??process.stdin,r={duration:e.duration,frequency:e.frequency,output:t,seed:e.seed??Math.random()*8192,sleep:e.sleep,speed:e.speed,spread:e.spread};if(!n.isTTY||typeof n.setRawMode!=="function"){await co(Oa,r);return}let o=new AbortController,i=n.readableFlowing===!0,s=n.isRaw===!0,a=!1,l=(c,d)=>{if(d.ctrl&&d.name==="c")a=!0;if(a||d.name==="return"||d.name==="enter")o.abort()};Fa.emitKeypressEvents(n),n.on("keypress",l),n.setRawMode(!0),n.resume();try{await co(Oa,{...r,signal:o.signal})}finally{if(n.off("keypress",l),n.setRawMode(s),!i)n.pause()}if(!a)return;if(e.onInterrupt){e.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Cf}from"node:crypto";import{existsSync as Na}from"node:fs";import{dirname as _n,join as Ha}from"node:path";var Sf="`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.",Rf="cache",Pf="rulebooks";function Ma(e={}){let t=U(e),n=x(t.filesystemScope,Ga(t.configDir)),r=w(t.lockTarget);if(console.log(Sf),r===null&&!Na(n.path))return console.log(`No v2 lock or cache leftovers found in ${_n(t.configDir)}; nothing to migrate.`),0;let o=Tf(r),i=q(t.configTarget);if(!i.config&&(w(t.configTarget)!==null||o.size>0))return console.error(`Cannot migrate: the rules config in ${_n(t.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let s=i.config?.rules??[];for(let a of s.flatMap((l)=>Df(l,o,t,n,e.global===!0)))console.log(a);return he(t.lockTarget),ja(n),console.log(`Removed the v2 lock and cache under ${_n(t.configDir)}.`),0}function Ua(e){return[...new Set([{cwd:e},{cwd:e,global:!0}].flatMap((t)=>{let n=U(t);return[n.lockPath,Ga(n.configDir)]}))].filter((t)=>Na(t))}function Df(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&&Af(a,i))return[];let l=t.get(e),c=l?Ef(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 Af(e,t){let n=_t(e);return!("problem"in n)&&n.rulebook.name===t}function Ef(e,t,n,r){let o=Ha(n,Pf,`${_f(e)}--${e.digest.replace("sha256:","").slice(0,12)}`,yn),i=w(x(r,o));if(i===null||Of(i)!==e.digest)return null;let s=_t(i);if("problem"in s||s.rulebook.name!==t)return null;return i}function Ga(e){return Ha(_n(e),Rf)}function _f(e){return([e.owner,e.repo,e.display_ref,e.name].every((r)=>typeof r==="string"&&r!=="")?`${e.owner}/${e.repo}#${e.display_ref}/${e.name}`:e.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function Tf(e){let t=e===null?null:$f(e),n=Ba(t)&&Array.isArray(t.rulebooks)?t.rulebooks:[];return new Map(n.filter(If).map((r)=>[r.spec,r]))}function If(e){return Ba(e)&&typeof e.spec==="string"&&typeof e.digest==="string"}function Ba(e){return!!e&&typeof e==="object"}function $f(e){try{return JSON.parse(e)}catch{return null}}function Of(e){return`sha256:${Cf("sha256").update(e).digest("hex")}`}var qa="\r\x1B[2K",Ff="\x1B[?25l",jf="\x1B[39m",Nf="\x1B[?25h",Hf=100,Mf=0.55,Uf=80,Va=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Gf(e){return new Promise((t)=>setTimeout(t,e))}async function Tn(e,t={}){let n=t.output??process.stdout;if(!n.isTTY)return e;let r=t.sleep??Gf,o=!1,i=e.then((a)=>(o=!0,a),(a)=>{throw o=!0,a});if(await Promise.race([i.then(()=>!0),r(Hf).then(()=>!1)]))return i;n.write(Ff);try{for(let a=0;!o;a+=1)n.write(`${qa}${Ia(a*Mf)}${Va[a%Va.length]}${jf} ${t.loadingMessage??"Loading…"}`),await Promise.race([i,r(Uf)]);return await i}finally{n.write(`${qa}${Nf}`)}}async function Kt(e,t,n,r={}){let o=t();if(e)await n();if(e&&o.ready)await Tn(o.ready,r);return o.finish()}import{homedir as yg}from"node:os";import{stripVTControlCharacters as Bf}from"node:util";var In="amp plugins list",qf=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function za(e){if(!e.ampPluginListOutput)return{platform:"amp",status:"n/a"};let t=Bf(e.ampPluginListOutput).split(`
|
|
28
|
+
`).map((n)=>qf.exec(n)?.[1]).find((n)=>n!==void 0);if(!t)return{platform:"amp",status:"n/a"};if(t!=="active")return{platform:"amp",status:"disabled",method:In,configPath:In,errors:[`Amp personal plugin cc-safety-net is ${t}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:In,configPath:In}}import{existsSync as Vf,readFileSync as zf}from"node:fs";var Kf=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Jf(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"||!Kf.test(a))return[];return[{command:a,enabled:n.enabled!==!1}]})})})}function Ka(e){let t=Gt(e.homeDir);if(!Vf(t))return{platform:"antigravity-cli",status:"n/a",configPath:t};let n;try{n=Jf(JSON.parse(zf(t,"utf-8")))}catch(r){return{platform:"antigravity-cli",status:"n/a",configPath:t,errors:[`Failed to parse Antigravity hooks config ${t}: ${r instanceof Error?r.message:String(r)}`]}}if(n.some((r)=>r.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:t};if(n.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:t};return{platform:"antigravity-cli",status:"n/a",configPath:t}}import{join as Ja}from"node:path";import{existsSync as Wf,lstatSync as Yf,readFileSync as Zf}from"node:fs";function ce(e,t=(n)=>n){if(!Wf(e))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(t(Zf(e,"utf-8")))}}catch{return{kind:"unreadable"}}}function _(e){try{return Yf(e)}catch{return}}function $n(e,t){let n=_(t);if(!n)return{platform:e,status:"n/a",configPath:t};if(!n.isSymbolicLink()&&n.isDirectory())return;return{platform:e,status:"n/a",configPath:t,errors:[`${t} is a symlink or not a directory; move or remove it before installing`]}}function k(e,t){return typeof e==="object"&&e!==null?e[t]:void 0}var uo="cc-safety-net@cc-marketplace";function Wa(e){return Ja(e,".claude","plugins","installed_plugins.json")}function Ya(e,t){let n=k(k(e,"plugins"),t);return Array.isArray(n)&&n.length>0}function On(e,t){let n=ce(Wa(e));return n.kind==="ok"&&Ya(n.value,t)}function po(e){let t=Wa(e),n=ce(t);if(n.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(n.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Ya(n.value,uo))return{platform:"claude-code",status:"n/a"};let r=Ja(e,".claude","settings.json"),o=ce(r);if(o.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(o.kind==="ok"&&k(k(o.value,"enabledPlugins"),uo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:r,errors:[`${uo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:t}}function Za(e){return po(e.homeDir)}function Xa(e){if(!e.codexPluginListOutput)return{platform:"codex",status:"n/a"};let t=e.codexPluginListOutput.split(`
|
|
29
|
+
`).find((n)=>n.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!t)return{platform:"codex",status:"n/a"};if(!t.includes("installed,"))return{platform:"codex",status:"n/a"};if(!t.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as Hn,readdirSync as Xf,readFileSync as Qf}from"node:fs";import{join as M}from"node:path";var de="cc-safety-net@cc-marketplace",Fn=["cc-marketplace","cc-safety-net"],Qa=["_direct","copilot-safety-net"],el=["cc-marketplace","safety-net"],tl="safety-net@cc-marketplace";function jn(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${n}([^a-z0-9-]|$)`,"m").test(e??"")}function nl(e){return jn(e,"cc-safety-net@cc-marketplace")}function rl(e){return jn(e,"cc-marketplace")}function ol(e){return jn(e,"copilot-safety-net")}function il(e){return jn(e,"safety-net@cc-marketplace")}function K(e){let t="",n=0,r=!1,o=!1,i=-1;while(n<e.length){let s=e[n],a=e[n+1];if(o){t+=s,o=!1,n++;continue}if(s==='"'&&!r){r=!0,i=-1,t+=s,n++;continue}if(s==='"'&&r){r=!1,t+=s,n++;continue}if(s==="\\"&&r){o=!0,t+=s,n++;continue}if(r){t+=s,n++;continue}if(s==="/"&&a==="/"){while(n<e.length&&e[n]!==`
|
|
30
|
+
`)n++;continue}if(s==="/"&&a==="*"){n+=2;while(n<e.length-1){if(e[n]==="*"&&e[n+1]==="/"){n+=2;break}n++}continue}if(s===","){i=t.length,t+=s,n++;continue}if(s==="}"||s==="]"){if(i!==-1){let l=t.slice(i+1);if(/^\s*$/.test(l))t=t.slice(0,i)+l}i=-1,t+=s,n++;continue}if(!/\s/.test(s))i=-1;t+=s,n++}return t}function fo(e){if(!e?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(e)}function al(e,t){if(!e)return null;let n=e.match(/(\d+)\.(\d+)\.(\d+)/);if(!n)return null;let r=[Number(n[1]),Number(n[2]),Number(n[3])];for(let o=0;o<t.length;o++){let i=r[o]??0,s=t[o]??0;if(i!==s)return i>s}return!0}function em(e){return al(e,[0,0,422])}function tm(e){return al(e,[1,0,8])}function Jt(e){return process.env.COPILOT_HOME||M(e,".copilot")}function mo(e){return(e.hooks?.preToolUse??[]).some((n)=>{if(n.type!=="command")return!1;return fo(n.command)||fo(n.bash)||fo(n.powershell)})}function Nn(e){return e===void 0||typeof e==="string"}function nm(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e;if(t.disableAllHooks!==void 0&&typeof t.disableAllHooks!=="boolean")return!1;if(t.hooks===void 0)return!0;if(!t.hooks||typeof t.hooks!=="object"||Array.isArray(t.hooks))return!1;let n=t.hooks.preToolUse;if(n===void 0)return!0;return Array.isArray(n)&&n.every((r)=>r!==null&&typeof r==="object"&&!Array.isArray(r)&&Nn(r.type)&&Nn(r.command)&&Nn(r.bash)&&Nn(r.powershell))}function go(e,t){try{let n=JSON.parse(K(Qf(e,"utf-8")));if(!nm(n)){t?.push(`Invalid hook config ${e}: hooks.preToolUse must be an array of hook objects`);return}return n}catch(n){t?.push(`Failed to parse ${e}: ${n instanceof Error?n.message:String(n)}`);return}}function ll(e,t){try{return Xf(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 rm(e,t){if(!Hn(e))return[];let n=[];for(let r of ll(e,t)){let o=M(e,r),i=go(o,t);if(i&&mo(i))n.push(o)}return n}function mt(e,t){if(!Hn(e))return;let n=go(e,t);if(!n)return;return{path:e,config:n}}function sl(e,t,n,r){if(t){e.push(`GitHub Copilot CLI ${t} does not support ${n}; requires ${r}+`);return}e.push(`GitHub Copilot CLI version unavailable; skipping ${n} because it requires ${r}+`)}function om(e){for(let t of e){if(t?.config.disableAllHooks===!0)return t.path;if(t?.config.disableAllHooks===!1)return}return}function im(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=tm(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=om([...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=rm(i,r),p=em(n),f=p===!0?r:void 0,b=Hn(s)?ll(s,f):[],L=[];for(let v of b){let P=M(s,v),ne=go(P,f);if(ne&&mo(ne))L.push(P)}if(p!==!0&&L.length>0)sl(r,n,`user hook files in ${s}`,"0.0.422"),L.length=0;let h=[];for(let v of[...m,...g]){if(!v)continue;if(!mo(v.config))continue;if(c===!0){h.push(v);continue}sl(r,n,"inline hook definitions in Copilot config files","1.0.8");break}let R=(v)=>v.filter((P)=>!!P&&h.includes(P)).map((P)=>P.path);return{activeConfigPaths:[...R(m),...u,...R(g),...L]}}function cl(e){let t=[],n=im(e.homeDir,e.cwd,e.copilotCliVersion,t);if(n.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:n.disabledBy,configPaths:[n.disabledBy],errors:t.length>0?t:void 0};let r=Jt(e.homeDir),o=M(r,"installed-plugins",...Fn),i=Hn(o),s=M(r,"settings.json"),a=ce(s,K);if(i&&a.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(i&&a.kind==="ok"&&k(k(a.value,"enabledPlugins"),de)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:s,errors:[`${de} is installed but not enabled in Copilot CLI`]};if(i||n.activeConfigPaths.length>0){let l=i,c=n.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:l?"plugin config":"hook config",configPath:c??(l?o:void 0),configPaths:n.activeConfigPaths.length>0?n.activeConfigPaths:void 0,errors:t.length>0?t:void 0}}return{platform:"copilot-cli",status:"n/a",errors:t.length>0?t:void 0}}import{existsSync as gm,readFileSync as hm}from"node:fs";import{existsSync as dl,mkdirSync as lm,readFileSync as cm}from"node:fs";import{dirname as dm,join as um}from"node:path";import{renameSync as sm,writeFileSync as am}from"node:fs";function O(e,t){let n=`${e}.${process.pid}.tmp`;am(n,t),sm(n,e)}var Wt="npx -y cc-safety-net hook --cursor",ul=30;function Un(e){return um(e,".cursor","hooks.json")}function Ke(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function ho(){return{command:Wt,timeout:ul,failClosed:!0}}function Mn(e){return Ke(e)&&e.command===Wt}function pm(e){return Object.keys(e).length===3&&e.command===Wt&&e.timeout===ul&&e.failClosed===!0}function fm(e){try{return JSON.parse(cm(e,"utf-8"))}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${e}: ${t.message}`);throw t}}function pl(e){let t=fm(e);if(!Ke(t))throw Error(`Cursor hooks config ${e} must be a JSON object`);if(t.version!==1)throw Error(`Cursor hooks config ${e} must set "version": 1`);if(t.hooks!==void 0&&!Ke(t.hooks))throw Error(`Cursor hooks config ${e} "hooks" must be an object`);let n=Ke(t.hooks)?t.hooks.preToolUse:void 0;if(n!==void 0&&!Array.isArray(n))throw Error(`Cursor hooks config ${e} "hooks.preToolUse" must be an array`);return t}function fl(e){let t=Ke(e.hooks)?e.hooks.preToolUse:void 0;return Array.isArray(t)?t:[]}function mm(e){if(!e.some(Mn))return[...e,ho()];return e.reduce((t,n)=>{if(!Mn(n))return t.result.push(n),t;if(!t.inserted)t.result.push(ho()),t.inserted=!0;return t},{result:[],inserted:!1}).result}function ml(e,t,n){let r=Ke(t.hooks)?t.hooks:{},o={...t,hooks:{...r,preToolUse:n}};O(e,`${JSON.stringify(o,null,2)}
|
|
31
|
+
`)}function gl(e){let t=Un(e);if(!dl(t))return lm(dm(t),{recursive:!0}),O(t,`${JSON.stringify({version:1,hooks:{preToolUse:[ho()]}},null,2)}
|
|
32
|
+
`),{path:t,alreadyInstalled:!1};let n=pl(t),r=fl(n),o=r.filter(Mn);if(Ke(n.hooks)&&Array.isArray(n.hooks.preToolUse)&&o.length===1&&o[0]!==void 0&&pm(o[0]))return{path:t,alreadyInstalled:!0};return ml(t,n,mm(r)),{path:t,alreadyInstalled:!1}}function hl(e){let t=Un(e);if(!dl(t))return{path:t,alreadyInstalled:!1};let n=pl(t),r=fl(n),o=r.filter((i)=>!Mn(i));if(o.length===r.length)return{path:t,alreadyInstalled:!1};return ml(t,n,o),{path:t,alreadyInstalled:!0}}function ym(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 vm(e){let t=[];if(e.length>1)t.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let n=e[0];if(n&&n.failClosed!==!0)t.push('Managed hook is missing "failClosed": true; reinstall to repair');if(n&&n.timeout!==30)t.push('Managed hook "timeout" is not 30; reinstall to repair');return t}function yl(e){let t=Un(e.homeDir);if(!gm(t))return{platform:"cursor",status:"n/a",configPath:t};let n;try{n=JSON.parse(hm(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=ym(n);if(r.length===0)return{platform:"cursor",status:"n/a",configPath:t};let o=vm(r);return{platform:"cursor",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{existsSync as bm}from"node:fs";import{join as yo}from"node:path";var vo="gemini-safety-net";function bo(e){let t=yo(e,".gemini","extensions"),n=yo(t,vo);if(!bm(n))return{platform:"gemini-cli",status:"n/a"};let r=yo(t,"extension-enablement.json"),o=ce(r);if(o.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let i=o.kind==="ok"?k(k(o.value,vo),"overrides"):void 0;if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:r,errors:[`${vo} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:n}}function vl(e){return bo(e.homeDir)}import{existsSync as xm,readFileSync as Cm}from"node:fs";import{existsSync as Ll,mkdirSync as Lm,readFileSync as wl,rmSync as wm}from"node:fs";import{dirname as km,join as bl}from"node:path";var Yt="npx -y cc-safety-net hook --grok-build",qn=30;function Vn(e){return bl(process.env.GROK_HOME??bl(e,".grok"),"hooks","cc-safety-net.json")}function Je(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Gn(){return{hooks:[{type:"command",command:Yt,timeout:qn}]}}function kl(e){return Je(e)&&e.command===Yt}function xl(e){return e.flatMap((t)=>{if(!Je(t)||!Array.isArray(t.hooks))return[t];let n=t.hooks.filter((r)=>!kl(r));if(n.length===t.hooks.length)return[t];return n.length===0?[]:[{...t,hooks:n}]})}function Cl(e){try{let t=JSON.parse(e);return Je(t)?t:null}catch{return null}}function Sl(e){let t=Je(e.hooks)?e.hooks.PreToolUse:void 0;return Array.isArray(t)?t:[]}function Bn(e,t,n){let r=Je(t.hooks)?t.hooks:{};O(e,`${JSON.stringify({...t,hooks:{...r,PreToolUse:n}},null,2)}
|
|
33
|
+
`)}function Rl(e){let t=Vn(e);if(!Ll(t))return Lm(km(t),{recursive:!0}),Bn(t,{},[Gn()]),{path:t,alreadyInstalled:!1};let n=Cl(wl(t,"utf-8"));if(!n)return Bn(t,{},[Gn()]),{path:t,alreadyInstalled:!1};let r=Sl(n),o=r.filter((i)=>Je(i)&&Array.isArray(i.hooks)&&i.hooks.some(kl));if(o.length===1&&JSON.stringify(o[0])===JSON.stringify(Gn()))return{path:t,alreadyInstalled:!0};return Bn(t,n,[...xl(r),Gn()]),{path:t,alreadyInstalled:!1}}function Pl(e){let t=Vn(e);if(!Ll(t))return{path:t,alreadyInstalled:!1};let n=Cl(wl(t,"utf-8"));if(!n)return{path:t,alreadyInstalled:!1};let r=Sl(n),o=xl(r);if(JSON.stringify(o)===JSON.stringify(r))return{path:t,alreadyInstalled:!1};let i=Je(n.hooks)?n.hooks:{};if(o.length===0&&Object.keys(n).length===1&&Object.keys(i).length===1)return wm(t),{path:t,alreadyInstalled:!0};return Bn(t,n,o),{path:t,alreadyInstalled:!0}}function Zt(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}function Sm(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 Rm(e){let n=(Array.isArray(e.hooks)?e.hooks.filter(Zt):[]).find((r)=>r.command===Yt);return[...e.matcher===void 0||e.matcher===""||e.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...n?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...n?.timeout===qn?[]:[`Managed hook "timeout" is not ${qn}; reinstall to repair`]]}function Dl(e){let t=Vn(e.homeDir);if(!xm(t))return{platform:"grok-build",status:"n/a",configPath:t};let n;try{n=JSON.parse(Cm(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=Sm(n)[0];if(!r)return{platform:"grok-build",status:"n/a",configPath:t};let o=Rm(r);return{platform:"grok-build",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{readFileSync as jl}from"node:fs";import{join as Nl}from"node:path";var Q="cc-safety-net",Al="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent";function El(e){return`# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent
|
|
34
34
|
# version: ${e}
|
|
35
|
-
`}function
|
|
35
|
+
`}function Pm(e){return`${El(e)}name: cc-safety-net
|
|
36
36
|
version: "${e}"
|
|
37
37
|
description: "Block destructive commands and secret-file access before Hermes runs a tool."
|
|
38
38
|
author: "cc-safety-net"
|
|
39
39
|
provides_hooks:
|
|
40
40
|
- pre_tool_call
|
|
41
|
-
`}function
|
|
41
|
+
`}function Dm(e){return`${El(e)}"""CC Safety Net guard for Hermes Agent.
|
|
42
42
|
|
|
43
43
|
Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
|
|
44
44
|
adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
|
|
@@ -176,86 +176,86 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
176
176
|
|
|
177
177
|
def register(ctx):
|
|
178
178
|
ctx.register_hook("pre_tool_call", _pre_tool_call)
|
|
179
|
-
`}function Xt(e){return[{name:"__init__.py",content:
|
|
180
|
-
`)}function Do(e){let t={stdout:"",stderr:""};return e.stdout.setEncoding("utf-8"),e.stderr.setEncoding("utf-8"),e.stdout.on("data",(n)=>{t.stdout+=n}),e.stderr.on("data",(n)=>{t.stderr+=n}),t}function ue(e,t){return new Promise((n,r)=>{let o=ze([...e],process.env),i=
|
|
181
|
-
`),l=t?.timeoutMs??120000,c=setTimeout(()=>{i.kill(),r(Error(
|
|
182
|
-
${a()}`.trim())))},l);i.on("error",(d)=>{clearTimeout(c),r(Error(
|
|
183
|
-
${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(
|
|
184
|
-
`,t)+1;return/^[ \t]*/.exec(e.slice(n))?.[0]??""}function
|
|
185
|
-
`)r++;return`${e.slice(0,n)}${e.slice(r)}`}o=t.start-1;while(
|
|
186
|
-
`,n-1);if(i!==-1&&/^\s*$/.test(e.slice(i+1,n)))n=i}return`${e.slice(0,n)}${e.slice(r)}`}var
|
|
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
|
|
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}: ${
|
|
190
|
-
`)}function
|
|
191
|
-
`,()=>t())})}async function
|
|
192
|
-
`))}function
|
|
193
|
-
`))}function
|
|
194
|
-
`)}var
|
|
195
|
-
`)}function
|
|
179
|
+
`}function Xt(e){return[{name:"__init__.py",content:Dm(e)},{name:"plugin.yaml",content:Pm(e)}]}import{mkdirSync as Am,readdirSync as Em,readFileSync as _m,rmSync as Lo}from"node:fs";import{join as We}from"node:path";var Tm="__pycache__";function wo(e){let t=process.env.HERMES_HOME?.trim();return t?t:We(e,".hermes")}function ko(e){return We(wo(e),"plugins",Q)}function xo(e){return e.startsWith(Al)}function Co(e,t){let n=ko(e),r=_(n);if(r&&(r.isSymbolicLink()||!r.isDirectory()))throw Error(`Refusing to ${t} ${n}: not a regular directory. Move or remove it and rerun ${t==="install"?"install":"uninstall"} --hermes-agent.`);return n}function _l(e,t){let n=_(e);if(!n)return;if(n.isSymbolicLink()||!n.isFile())throw Error(`Refusing to ${t} ${e}: not a regular file. Move or remove it.`);let r=_m(e,"utf-8");if(!xo(r))throw Error(`Refusing to ${t} unmanaged file at ${e}. Move or remove it.`);return r}function Tl(e){let t=Co(e,"install"),n=Xt(I());if(n.map((o)=>_l(We(t,o.name),"overwrite")).every((o,i)=>o===n[i]?.content))return{path:t,alreadyInstalled:!0};return Am(t,{recursive:!0}),n.forEach((o)=>{O(We(t,o.name),o.content)}),{path:t,alreadyInstalled:!1}}function So(e){let t=Co(e,"remove");if(!_(t))return[];return Xt(I()).filter((n)=>_l(We(t,n.name),"remove")!==void 0)}function Il(e){let t=Co(e,"remove");if(!_(t))return{path:t,alreadyInstalled:!1};let n=So(e);if(n.forEach((r)=>{Lo(We(t,r.name))}),Lo(We(t,Tm),{recursive:!0,force:!0}),Em(t).length===0)Lo(t,{recursive:!0});return{path:t,alreadyInstalled:n.length>0}}var zn="hermes-agent",$l=/^([^\s#][^:]*):/,Im=/^\s+([A-Za-z_][\w-]*):/,Ol=/^\s+-\s*(.*)$/;function $m(e){return e.trim().replace(/^(["'])(.*)\1$/,"$2")}function Om(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>$l.exec(i)?.[1]?.trim()==="plugins");if(n===-1)return[];let r=t.slice(n+1),o=r.findIndex((i)=>$l.test(i));return o===-1?r:r.slice(0,o)}function Fl(e,t){let n=Om(e),r=n.findIndex((s)=>Im.exec(s)?.[1]===t);if(r===-1)return[];let o=n.slice(r+1),i=o.findIndex((s)=>!Ol.test(s));return(i===-1?o:o.slice(0,i)).map((s)=>$m(Ol.exec(s)?.[1]??""))}function Fm(e){try{return jl(Nl(wo(e),"config.yaml"),"utf-8")}catch{return}}function Ro(e){let t=Fm(e)??"";return Fl(t,"enabled").includes(Q)&&!Fl(t,"disabled").includes(Q)}function Hl(e){return/^# version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function jm(e,t){let n=_(e);if(!n)return{error:`${t.name} is missing from ${e}; run install --hermes-agent`};if(n.isSymbolicLink()||!n.isFile())return{error:`${e} is a symlink or not a regular file; move or remove it`};try{let r=jl(e,"utf-8");if(!xo(r))return{error:`Unmanaged ${t.name} occupies ${e}; move or remove it`};if(Hl(r)===I()&&r!==t.content)return{error:`Modified ${t.name} occupies ${e}; run install --hermes-agent to restore it`};return{content:r}}catch(r){return{error:`Failed to read ${e}: ${r instanceof Error?r.message:String(r)}`}}}function Ml(e){let t=ko(e.homeDir),n=$n(zn,t);if(n)return n;let r=Xt(I()).map((a)=>jm(Nl(t,a.name),a)),o=r.flatMap((a)=>("error"in a)?[a.error]:[]);if(o.length>0)return{platform:zn,status:"n/a",configPath:t,errors:o};let i=r.some((a)=>("content"in a)&&Hl(a.content)!==I()),s=i?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Ro(e.homeDir))return{platform:zn,status:"disabled",method:"plugin directory",configPath:t,errors:[`${Q} is not enabled in Hermes; run \`hermes plugins enable ${Q}\``,...s]};return{platform:zn,status:"configured",method:"plugin directory",configPath:t,errors:i?s:void 0}}import{existsSync as Nm,readFileSync as Hm}from"node:fs";import{join as Ul}from"node:path";var Mm=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function Um(e){return Ul(process.env.KIMI_CODE_HOME||Ul(e,".kimi-code"),"config.toml")}function Qt(e){let t=Um(e.homeDir);if(!Nm(t))return{platform:"kimi-code",status:"n/a",configPath:t};try{if(!Mm.test(Hm(t,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:t}}catch(n){return{platform:"kimi-code",status:"n/a",configPath:t,errors:[`Failed to read ${t}: ${n instanceof Error?n.message:String(n)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:t}}import{readFileSync as Zl}from"node:fs";import{join as tn}from"node:path";var A="cc-safety-net",ee="index.js",gt="openclaw.plugin.json",ht="package.json";var Kn="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as qm,lstatSync as Vm,readdirSync as zm,readFileSync as Km}from"node:fs";import{dirname as ql,join as Ie}from"node:path";import{fileURLToPath as Jm}from"node:url";import{spawn as Gm}from"node:child_process";function Bm(e){return e.join(" ")}function Po(e,t,n){return[`Failed to run ${Bm(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=Gm(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(Po(e,null,`Timed out after ${l}ms.
|
|
182
|
+
${a()}`.trim())))},l);i.on("error",(d)=>{clearTimeout(c),r(Error(Po(e,null,`${d.message}
|
|
183
|
+
${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(Po(e,d,a())));return}n(t?.stdoutOnly?s.stdout:a())})})}async function Ao(e){for(let t of e)await ue(t)}async function Gl(e){for(let t of e)try{await ue(t)}catch(n){console.warn(n instanceof Error?n.message:String(n))}}var Bl=Ie("openclaw",A),Wm=[ee,gt,ht];function Eo(e,t){if(e==="~")return t;if(e.startsWith("~/")||e.startsWith("~\\"))return Ie(t,e.slice(2));return e}function Vl(e){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return Eo(t,e);let n=process.env.OPENCLAW_CONFIG_PATH?.trim();return n?ql(Eo(n,e)):Ie(e,".openclaw")}function zl(e){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?Eo(t,e):Ie(Vl(e),"openclaw.json")}function _o(e){return Ie(Vl(e),"extensions",A)}function Ym(e){let t=zm(e);if(t.length===0)return!0;if(t.some((o)=>!Wm.includes(o)))return!1;let n=Ie(e,ee),r=_(n);return r!==void 0&&!r.isSymbolicLink()&&r.isFile()&&Km(n,"utf-8").startsWith(Kn)}function To(e){let t=_o(e),n=_(t);if(!n)return;if(!n.isSymbolicLink()&&n.isDirectory()&&Ym(t))return;throw Error(`Refusing to modify ${t}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Kl(){let e=ql(Jm(import.meta.url));return[Ie(e,"..",Bl),Ie(e,"..","..","..","dist",Bl)]}function Io(e=Kl()){return e.find((t)=>qm(t)&&Vm(t).isDirectory())}function Zm(e=Kl()){let t=Io(e);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function Jl(e=Zm()){return[["openclaw","plugins","install",e,"--force"],["openclaw","plugins","enable",A]]}function Xm(e){let t=(()=>{try{return JSON.parse(e)}catch{return}})(),n=k(k(t,"plugin"),"status");return typeof n==="string"?n:void 0}async function Wl(){let e=Xm(await ue(["openclaw","plugins","inspect",A,"--runtime","--json"],{stdoutOnly:!0}));if(e==="loaded")return;throw Error(`${e===void 0?`The ${A} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${A} plugin with status "${e}".`} Run \`openclaw plugins inspect ${A} --runtime\` for details.`)}var Jn="openclaw",en=`run \`openclaw plugins enable ${A}\``;function yt(e,t){let n=tn(e,t),r=_(n);if(!r)return{error:`${t} is missing from ${n}; run install --openclaw`};if(r.isSymbolicLink()||!r.isFile())return{error:`${n} is a symlink or not a regular file; move or remove it`};try{return{content:Zl(n,"utf-8")}}catch(o){return{error:`Failed to read ${n}: ${o instanceof Error?o.message:String(o)}`}}}function Xl(e){try{return JSON.parse(K(e))}catch{return}}function Qm(e){let t=yt(e,gt);if("error"in t)return t.error;if(k(Xl(t.content),"id")===A)return;return`${tn(e,gt)} is not a valid ${A} manifest; run install --openclaw`}function eg(e){let t=yt(e,ht);if("error"in t)return t.error;let n=k(k(Xl(t.content),"openclaw"),"extensions");if(Array.isArray(n)&&n.includes(`./${ee}`))return;return`${tn(e,ht)} does not point OpenClaw at ${ee}; run install --openclaw`}function Yl(e){return Array.isArray(e)?e.filter((t)=>typeof t==="string"):[]}function tg(e){let t=zl(e);if(!_(t))return`${A} is not enabled; ${en}`;let n=(()=>{try{return JSON.parse(K(Zl(t,"utf-8")))}catch{return}})();if(n===void 0)return`Failed to read ${t}; fix it, then ${en}`;let r=k(n,"plugins");if(k(r,"enabled")===!1)return`plugins.enabled is false in ${t}; no OpenClaw plugin loads`;let o=k(k(k(r,"entries"),A),"enabled");if(Yl(k(r,"deny")).includes(A)||o===!1)return`${A} is disabled in ${t}; ${en}`;let i=Yl(k(r,"allow"));if(i.length>0&&!i.includes(A))return`plugins.allow in ${t} does not list ${A}; add it, then ${en}`;if(i.includes(A)||o===!0)return;return`${A} is not enabled; ${en}`}function Ql(e){return/^\/\/ version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function ng(e,t,n){if(n===void 0)return[];let r=yt(n,ee);if("error"in r||Ql(r.content)!==t)return[];return[ee,gt,ht].flatMap((o)=>{let i=yt(e,o),s=yt(n,o);if("error"in i||"error"in s||i.content===s.content)return[];return[`Modified ${o} occupies ${tn(e,o)}; run install --openclaw to restore it`]})}function ec(e){let t=_o(e.homeDir),n=$n(Jn,t);if(n)return n;let r=yt(t,ee),i=["error"in r?r.error:r.content.startsWith(Kn)?void 0:`Unmanaged ${ee} occupies ${tn(t,ee)}; move or remove it`,Qm(t),eg(t)].filter((d)=>d!==void 0),s="content"in r?Ql(r.content):void 0,a=i.length>0?i:ng(t,s,Io());if(a.length>0)return{platform:Jn,status:"n/a",configPath:t,errors:a};let l=s===I()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],c=tg(e.homeDir);if(c)return{platform:Jn,status:"disabled",method:"plugin directory",configPath:t,errors:[c,...l]};return{platform:Jn,status:"configured",method:"plugin directory",configPath:t,errors:l.length>0?l:void 0}}import{existsSync as fg,readFileSync as mg}from"node:fs";import{join as gg}from"node:path";import{existsSync as $o,readFileSync as ic,rmSync as og}from"node:fs";import{join as ke}from"node:path";import{pathToFileURL as ig}from"node:url";function tc(e){return e!==void 0&&/\s/.test(e)}function rg(e,t,n){let r=t+1,o=!1;while(r<e.length){let i=e[r];if(o){o=!1,r++;continue}if(i==="\\"){o=!0,r++;continue}if(i==='"')return r+1;r++}throw Error(n)}function Wn(e,t,n){let r=e[t],o=r==="["?"]":"}",i=0,s=t;while(s<e.length){let a=n.skipComment?.(e,s)??s;if(a!==s){s=a;continue}if(e[s]==='"'){s=rg(e,s,n.stringError);continue}if(e[s]===r)i++;if(e[s]===o){if(i--,i===0)return s}s++}throw Error(n.bracketError)}function nc(e,t){let n=e.lastIndexOf(`
|
|
184
|
+
`,t)+1;return/^[ \t]*/.exec(e.slice(n))?.[0]??""}function Yn(e,t){let{start:n,end:r,end:o}=t;while(tc(e[o]))o++;if(e[o]===","){if(r=o+1,e[r]===`
|
|
185
|
+
`)r++;return`${e.slice(0,n)}${e.slice(r)}`}o=t.start-1;while(tc(e[o]))o--;if(e[o]===","){n=o;let i=e.lastIndexOf(`
|
|
186
|
+
`,n-1);if(i!==-1&&/^\s*$/.test(e.slice(i+1,n)))n=i}return`${e.slice(0,n)}${e.slice(r)}`}var Zn="cc-safety-net",sc=`${Zn}@latest`,ac=["opencode.json","opencode.jsonc"],rc="CCSafetyNetPlugin";function Xn(e){return ke(process.env.XDG_CONFIG_HOME||ke(e,".config"),"opencode")}function sg(e){return ke(Xn(e),ac[0])}function ag(e){return ac.map((t)=>ke(Xn(e),t))}function lc(e){return ke(process.env.XDG_CACHE_HOME||ke(e,".cache"),"opencode","packages",sc)}function Oo(e){og(lc(e),{recursive:!0,force:!0})}async function cc(e){let t=ke(lc(e),"node_modules",Zn),n=ke(t,"package.json");if(!$o(n))throw Error(`The OpenCode plugin cache at ${t} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${sc}\` for details.`);let r=k(JSON.parse(ic(n,"utf-8")),"main");if(typeof r!=="string")throw Error(`The cached OpenCode plugin at ${t} declares no "main" entry.`);let o=ke(t,r);if(typeof(await import(ig(o).href))[rc]==="function")return;throw Error(`The cached OpenCode plugin at ${o} does not export a callable ${rc}, so OpenCode would load nothing and fail open.`)}function Qn(e,t){if(e[t]==="/"&&e[t+1]==="/"){let n=e.indexOf(`
|
|
187
|
+
`,t+2);return n===-1?e.length:n+1}if(e[t]==="/"&&e[t+1]==="*"){let n=e.indexOf("*/",t+2);return n===-1?e.length:n+2}return t}function oc(e,t){let n=t;while(n<e.length){if(/\s/.test(e[n]??"")){n++;continue}let r=Qn(e,n);if(r===n)return n;n=r}return n}function dc(e,t){let n=t+1,r=!1;while(n<e.length){if(r){r=!1,n++;continue}if(e[n]==="\\"){r=!0,n++;continue}if(e[n]==='"')return n+1;n++}throw Error("Unterminated string in OpenCode config")}function uc(e,t,n){return JSON.parse(e.slice(t,n))}function lg(e,t){return Wn(e,t,{skipComment:Qn,stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"})}function cg(e){let t=0,n=0;while(n<e.length){let r=Qn(e,n);if(r!==n){n=r;continue}if(e[n]==='"'){let o=dc(e,n);if(t===1&&uc(e,n,o)==="plugin"){let i=oc(e,o),s=oc(e,i+1);if(e[i]===":"&&e[s]==="[")return{start:s,end:lg(e,s)}}n=o;continue}if(e[n]==="{"||e[n]==="[")t++;if(e[n]==="}"||e[n]==="]")t--;n++}return}function dg(e,t){let n=[],r=t.start+1;while(r<t.end){let o=Qn(e,r);if(o!==r){r=o;continue}if(e[r]==='"'){let i=dc(e,r),s=uc(e,r,i);if(typeof s==="string"&&s.includes(Zn))n.push({start:r,end:i});r=i;continue}r++}return n}function pc(e,t){try{return JSON.parse(K(e))}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${t}: ${n.message}`);throw n}}function ug(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e.plugin;if(!Array.isArray(t))return!1;return t.some((n)=>typeof n==="string"&&n.includes(Zn))}function pg(e,t){let n=cg(e);if(!n)throw Error(`Failed to locate OpenCode plugin array in ${t}`);let r=[...dg(e,n)].reverse().reduce(Yn,e);return pc(r,t),r}function fc(e){Oo(e);let t=ag(e),n=t.find((o)=>$o(o)),r=[];for(let o of t){if(!$o(o))continue;try{let i=ic(o,"utf-8");if(!ug(pc(i,o)))continue;return O(o,pg(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??sg(e),alreadyInstalled:!1}}function mc(e){let t=[],n=Xn(e.homeDir),r=["opencode.json","opencode.jsonc"];for(let o of r){let i=gg(n,o);if(fg(i))try{let s=mg(i,"utf-8"),a=K(s);if((JSON.parse(a).plugin??[]).some((m)=>m.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:i,errors:t.length>0?t:void 0}}catch(s){t.push(`Failed to parse ${o}: ${s instanceof Error?s.message:String(s)}`)}}return{platform:"opencode",status:"n/a",errors:t.length>0?t:void 0}}import{join as hg}from"node:path";function Fo(e){return hg(e,".pi","agent","settings.json")}function jo(e){if(typeof e!=="string")return!1;return e==="npm:cc-safety-net"||e.startsWith("npm:cc-safety-net@")}function gc(e){let t=Fo(e.homeDir),n=ce(t);if(n.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(n.kind==="missing")return{platform:"pi",status:"n/a"};let r=k(n.value,"packages");if(!Array.isArray(r))return{platform:"pi",status:"n/a"};let o=r.find((a)=>jo(typeof a==="string"?a:k(a,"source")));if(o===void 0)return{platform:"pi",status:"n/a"};let i=k(o,"extensions");if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:t,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:t}}var vg={amp:za,"antigravity-cli":Ka,"claude-code":Za,codex:Xa,"copilot-cli":cl,cursor:yl,"gemini-cli":vl,"grok-build":Dl,"hermes-agent":Ml,"kimi-code":Qt,openclaw:ec,opencode:mc,pi:gc};function vt(e,t){let n={...t,cwd:e,homeDir:t?.homeDir??yg()};return wn.map((r)=>bg(vg[r](n)))}function bg(e){if(e.status==="not-inspected")return{platform:e.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:e.platform,detected:e.status!=="n/a",configured:e.status==="configured",inspectionStatus:e.status!=="n/a"?"verified":e.errors&&e.errors.length>0?"failed":"not-applicable",method:e.method,configPath:e.configPath,configPaths:e.configPaths,errors:e.errors}}import{tmpdir as Lg}from"node:os";import{join as wg}from"node:path";var kg=Object.freeze([{command:"git reset --hard",description:"git reset --hard",expectBlocked:!0},{command:"rm -rf /",description:"rm -rf /",expectBlocked:!0},{command:"rm -rf ./node_modules",description:"rm in cwd (safe)",expectBlocked:!1}]),xg=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),Cg={strict:!1,paranoidRm:!1,paranoidInterpreters:!1,worktreeMode:!1,effectiveLevel:"standard",capabilities:{fail_closed:{enabled:!1,source:"preset",sources:[]},paranoid_rm:{enabled:!1,source:"preset",sources:[]},paranoid_interpreters:{enabled:!1,source:"preset",sources:[]}}};function hc(){let e=wg(Lg(),"cc-safety-net-self-test"),t=kg.map((n)=>{let r=bn(st("self-test",{command:n.command},{kind:"command",shell:"auto"},{configCwd:e,executionCwd:e},n.command),{guard:{dependencies:{loadPolicySnapshot:()=>xg,getModes:()=>Cg,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),o=n.expectBlocked?"blocked":"allowed",i=r.decision.kind==="deny"?"blocked":"allowed";return{command:n.command,description:n.description,expected:o,actual:i,passed:o===i,reason:r.decision.kind==="deny"?r.decision.reason:void 0,ruleId:r.decision.kind==="deny"?r.decision.ruleId:void 0}});return{passed:t.filter((n)=>n.passed).length,failed:t.filter((n)=>!n.passed).length,total:t.length,results:t}}function No(e){let t=E({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},e);if(fe(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function yc(e={}){let t=await Kt(!e.json,()=>{let n=Sg(e);return{ready:n,finish:()=>n}},()=>zt(),{loadingMessage:"Checking system status…"});if(e.json)console.log(JSON.stringify(t,null,2));else Rg(t);return t.engineSelfTest.failed>0||t.findings.some((n)=>n.severity==="error")?1:0}async function Sg(e){let t=e.cwd??process.cwd(),n=await qt(),r=vt(t,{ampPluginListOutput:n.ampPluginListOutput,codexPluginListOutput:n.codexPluginListOutput,copilotCliVersion:n.versions["copilot-cli"]}),o=ca(t),i=da(),s=z({cwd:t}),a=s.policy,l=ye(a),c=Ue(a,l.capabilities),d=Rn(7),m=Ua(t),g=e.skipUpdateCheck?{currentVersion:I(),latestVersion:null,updateAvailable:!1}:await Te(),u={hooks:r,engineSelfTest:hc(),userConfig:o.userConfig,projectConfig:o.projectConfig,configState:Ht(s),effectiveRules:o.effectiveRules,shadowedRules:o.shadowedRules,environment:i,effectiveSafety:{selectedPreset:a.safety.level??"standard",level:l.effectiveLevel,capabilities:l.capabilities,ruleOverrides:a.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(c).filter(([,p])=>p.source==="rule_override"&&p.override==="off"&&p.inheritedEnabled&&p.changesInherited).map(([p])=>p),ruleCounts:{stored:Object.keys(a.destructiveCommandRuleOverrides).length,effective:Object.values(c).filter((p)=>p.changesInherited).length},...s.policyScopes?{policyScopes:s.policyScopes}:{}},...m.length>0?{v2Leftovers:m}:{},posture:Ca(o.userConfig.path),activity:d,update:g,system:n};return{...u,findings:pa(u)}}function Rg(e){console.log(),console.log(ma(e.hooks)),console.log(),console.log(ga(e.engineSelfTest)),console.log(),console.log(ha(e)),console.log(),console.log(ya(e.environment)),console.log(),console.log(va(e)),console.log(),console.log(ba(e.findings)),console.log(),console.log(La(e.activity)),console.log(),console.log(ka(e.system)),console.log(),console.log(wa(e.update)),console.log(xa(e))}import{existsSync as Pg}from"node:fs";var Dg=/^[A-Za-z0-9_@%+=:,./-]+$/,vc="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Ho(e){let t=E({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},e);if(fe(t.errors))return console.error(vc),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!Pg(t.values.cwd))return console.error(`Error: --cwd path does not exist: ${t.values.cwd}`),null;let n=t.positionals.length===1?t.positionals[0]:t.positionals.map((r)=>Dg.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!n)return console.error("Error: No command provided"),console.error(vc),null;return{json:t.flags.json,cwd:t.values.cwd,command:n}}function bc(e){if(e)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function Lc(e,t){let r=t-18;return[`${e.dtl}${e.dh.repeat(t)}${e.dtr}`,`${e.dv} Command Analysis${" ".repeat(r)}${e.dv}`,`${e.dbl}${e.dh.repeat(t)}${e.dbr}`]}function Mo(e){return JSON.stringify(e)}function wc(e,t=0){return`[${e.map((r,o)=>fa(r,o,t)).join(",")}]`}function nn(e,t,n=70){let r=e.split(" "),o=[],i="";for(let s of r)if(i&&i.length+s.length+1>n)o.push(i),i=s;else i=i?`${i} ${s}`:s;if(i)o.push(i);return o.map((s,a)=>a===0?s:`${t}${s}`)}function kc(e,t,n){let r=[];switch(e.type){case"parse":return null;case"env-strip":return r.push(""),r.push(`STEP ${t} ${n.h} Strip environment variables`),r.push(` Removed: ${e.envVars.map((o)=>`${o}=<redacted>`).join(", ")}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"leading-tokens-stripped":return r.push(""),r.push(`STEP ${t} ${n.h} Strip wrappers`),r.push(` Removed: ${e.removed.join(", ")}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"shell-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Detect shell wrapper`),r.push(` Wrapper: ${e.wrapper} -c`),r.push(` Inner: ${e.innerCommand}`),{lines:r,incrementStep:!0};case"interpreter":{if(r.push(""),r.push(`STEP ${t} ${n.h} Detect interpreter`),r.push(` Interpreter: ${e.interpreter}`),r.push(` Code: ${e.codeArg}`),e.paranoidBlocked)r.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:r,incrementStep:!0}}case"busybox":return r.push(""),r.push(`STEP ${t} ${n.h} Busybox wrapper`),r.push(` Subcommand: ${e.subcommand}`),{lines:r,incrementStep:!0};case"transparent-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Transparent wrapper`),r.push(` Wrapper: ${e.wrapper}`),r.push(` Tokens: ${Mo(e.output)}`),{lines:r,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(r.push(""),r.push(`STEP ${t} ${n.h} Match rules`),r.push(` Rule: ${e.rule}()`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}case"worktree-relaxation":return r.push(""),r.push(`STEP ${t} ${n.h} Worktree relaxation`),r.push(` Mode: ${S.worktree.name}`),r.push(` Git cwd: ${e.gitCwd}`),r.push(" Result: Allowed local discard in linked worktree"),{lines:r,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(e.embeddedCommandFound)return r.push(""),r.push(`STEP ${t} ${n.h} Fallback scan`),r.push(` Found: ${e.embeddedCommandFound}`),{lines:r,incrementStep:!0};return null}case"custom-rules-check":{if(e.rulesChecked){if(r.push(""),r.push(`STEP ${t} ${n.h} Custom rules`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(e.matched)return r.push(""),r.push(`STEP ${t} ${n.h} Dangerous text check`),r.push(` Token: ${e.token}`),r.push(" Result: MATCHED"),{lines:r,incrementStep:!0};return null}case"strict-unparseable":return r.push(""),r.push(`STEP ${t} ${n.h} Strict mode check`),r.push(` Command: ${e.rawCommand}`),r.push(" Result: ✗ UNPARSEABLE"),{lines:r,incrementStep:!0};case"segment-skipped":return null;case"error":return r.push(""),r.push(`ERROR: ${e.message}`),{lines:r,incrementStep:!1};default:return e}}function Uo(e,t){let n=bc(t?.asciiOnly??!1),r=58,o=[],i=1;o.push(...Lc(n,58)),o.push("");let s=e.trace.steps.find((p)=>p.type==="error");if(s&&s.type==="error"){o.push("ERROR"),o.push(` ${s.message}`),o.push(""),o.push("RESULT"),o.push(` Status: ${e.result==="blocked"?y.red("BLOCKED"):y.green("ALLOWED")}`),o.push(""),o.push("CONFIG");let p=e.configSource??"none";return o.push(` Path: ${p}`),o.join(`
|
|
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}: ${wc(f,b)}`)}}}let l=e.trace.segments,c=l.length>1;for(let p of l){if(c){o.push("");let h="";if(a&&a.type==="parse"){let mr=a.segments[p.index];if(mr)h=mr.join(" ")}let R=54,v=h,P=` Segment ${p.index+1}: `,ne=" ";if(h){if(P.length+h.length+ne.length>R){let bu=R-P.length-ne.length;v=`${h.substring(0,bu-1)}…`}}let un=h?`${P}${v}${ne}`:` Segment ${p.index+1} `,yu=h?`${P}${y.cyan(v)}${ne}`:un,pi=58-un.length,fi=Math.floor(pi/2),vu=pi-fi;o.push(`${n.sh.repeat(fi)}${yu}${n.sh.repeat(vu)}`)}if(p.steps.find((h)=>h.type==="segment-skipped")){o.push(""),o.push(" (skipped — prior segment blocked)");continue}let b=!1,L=!1;for(let h of p.steps){let R=kc(h,i,n);if(R){if(L=!0,h.type==="recurse"){o.push("");let v=" RECURSING ",P=58-v.length-4;o.push(` ${n.tl}${n.h}${v}${n.h.repeat(P)}`),o.push(` ${n.v}`),b=!0;continue}for(let v of R.lines)if(b)o.push(` ${n.v} ${v}`);else o.push(v);if(R.incrementStep)i++}}if(b)o.push(` ${n.v}`),o.push(` ${n.bl}${n.h.repeat(56)}`),b=!1;if(!L)o.push(""),o.push(` ${y.green("✓")} Allowed (no matching rules)`)}if(o.push(""),o.push("RESULT"),e.result==="blocked"){if(o.push(` Status: ${y.red("BLOCKED")}`),e.customRule){if(o.push(` Rule: ${e.customRule.id}`),e.customRule.rulebook)o.push(` Rulebook: ${e.customRule.rulebook.name} ${e.customRule.rulebook.version}`);if(e.customRule.source)o.push(` Source: ${e.customRule.source}`);if(e.customRule.override)o.push(` Override: reason ${e.customRule.override.reason}`)}if(e.reason){let p=nn(e.reason," ");o.push(` Reason: ${p[0]}`);for(let f=1;f<p.length;f++)o.push(p[f]??"")}}else o.push(` Status: ${y.green("ALLOWED")}`);o.push(""),o.push("CONFIG");let d=e.configSource??"none",m=e.configValid?"":" (invalid)";o.push(` Path: ${d}${m}`);let g=e.safetyPresetScope;o.push(` Safety preset: ${e.selectedPreset??"standard"}${g?` (${Pn(g)})`:""}`),o.push(` Effective capabilities: ${e.effectiveLevel}`);let u=Object.entries(e.destructiveCommandRuleOverrides??{});if(o.push(` Rule customizations: ${u.length}`),e.ruleActivation)o.push(` Rule activation: ${e.ruleActivation.id} — ${e.ruleActivation.enabled?"on":"off"} via ${e.ruleActivation.source}`);return o.join(`
|
|
190
|
+
`)}function Go(e){return JSON.stringify(e,null,2)}function xc(e){return new Promise((t)=>{process.stdout.write(`${e}
|
|
191
|
+
`,()=>t())})}async function Cc(e){let t=Ho(e);if(!t)return 1;try{let n=at(t.command,{cwd:t.cwd}),r=!!process.env.NO_COLOR||!process.stdout.isTTY;return await xc(t.json?Go(n):Uo(n,{asciiOnly:r})),0}catch(n){if(!(n instanceof Gr)&&!(n instanceof Me)&&!(n instanceof Le))throw n;if(t.json)return await xc(JSON.stringify({error:n.message})),1;return console.error(n.message),1}}var Sc="2.3.2",te=" ",Ye="cc-safety-net";function Rc(e){return e.argument?`${e.flags} ${e.argument}`:e.flags}function Ag(e){return Math.max(...e.map((t)=>Rc(t).length))}function Eg(e){return Math.max(...e.map((t)=>t.usage.length))}function _g(e){return Math.max(...e.map((t)=>`${Ye} ${t.usage}`.length))}function Tg(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=Eg(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=Ag(e.options);for(let o of e.options){let i=Rc(o),s=o.default?`${o.description} (default: ${o.default})`:o.description;n.push(`${te}${i.padEnd(r+2)}${s}`)}n.push("")}if(e.examples&&e.examples.length>0){n.push("EXAMPLES:");for(let r of e.examples)n.push(`${te}${r}`)}t(n.join(`
|
|
192
|
+
`))}function Bo(){let e=_g(Cn),t=[];t.push(`${Ye} v${Sc}`),t.push(""),t.push("Blocks destructive commands and secret access."),t.push(""),t.push("COMMANDS:");for(let n of Cn)t.push(Tg(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 Pc(){console.log(Sc)}function rn(e,t=console.log){let n=Sn(e);if(!n)return!1;if(n.name.toLowerCase()!==e.toLowerCase())return!1;return bt(n,t),!0}import{existsSync as ti,readFileSync as bd}from"node:fs";import{homedir as Ah,tmpdir as Eh}from"node:os";import{join as Qo}from"node:path";import*as $e from"node:readline";function Ig(e){return e==="install"?"Install":"Uninstall"}function $g(e){return e==="install"?"Installing":"Uninstalling"}function Og(e){return e==="install"?"into":"from"}function Ec(e){return e?.available===!0}function Fg(e,t){let n=new Set(t);return e.filter((r)=>n.has(r.target)).map((r)=>r.target)}function Dc(e,t,n){if(e.length===0||e.every((r)=>!r.available))return t;return Array.from({length:e.length},(r,o)=>o+1).map((r)=>(t+r*n+e.length)%e.length).find((r)=>Ec(e[r]))}function jg(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 Ng(e){return{cursor:e.findIndex((t)=>t.available),selected:[]}}function Hg(e,t,n){if(n==="confirm"||n==="update"||n==="abort"||n==="interrupt")return{state:e,done:n};if(n==="up")return{state:{...e,cursor:Dc(t,e.cursor,-1)}};if(n==="down")return{state:{...e,cursor:Dc(t,e.cursor,1)}};let r=t[e.cursor];if(!Ec(r))return{state:e};let o=e.selected.includes(r.target)?e.selected.filter((i)=>i!==r.target):Fg(t,[...e.selected,r.target]);return{state:{...e,selected:o}}}var _c="◉",Tc="◯",Ic=">",$c=" ";function Mg(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["",`${Ig(e)} CC Safety Net ${Og(e)}:`,"",...t.map((l,c)=>{let d=n.selected.includes(l.target),m=c===n.cursor,g=d?_c:Tc,u=m?Ic:$c,p=l.available?"":` (${l.unavailableReason??"not installed"})`,f=`${g} ${l.label}${p}`,b=!l.available?i(f):d?s(f):m?a(f):f;return`${u} ${b}`}),"",e==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":t.some((l)=>l.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${e}. q/Esc: close`].join(`
|
|
194
|
+
`)}var Ac=["global-hook","plugin"];function Ug(e,t,n={}){let r=n.color!==!1?y.bold:(i)=>i;return["","Install the Kimi Code integration as:","",...[`Global hook — ${t?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((i,s)=>{let a=s===e,l=`${a?_c:Tc} ${i}`;return`${a?Ic:$c} ${a?r(l):l}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
195
|
+
`)}function Oc(e){let{input:t,output:n}=e;$e.emitKeypressEvents(t);let r=t.isRaw===!0;t.setRawMode(!0),t.resume();let o=0,i=()=>{if(o===0)return;$e.moveCursor(n,0,-o),$e.cursorTo(n,0),$e.clearScreenDown(n)},s=()=>{i();let a=e.render();n.write(`${a}
|
|
196
196
|
`),o=a.split(`
|
|
197
|
-
`).length};return new Promise((a)=>{let l=(d)=>{t.off("keypress",c),t.setRawMode(r),t.pause(),i(),a(d)};function c(d,m){e.onKey(d,m,{finish:l,draw:s})}t.on("keypress",c),s()})}function
|
|
198
|
-
`);return}a.draw()}})}import{existsSync as
|
|
199
|
-
`)})}),o.on("close",(l)=>{clearTimeout(a),r({status:s?null:l,errorCode:s?"ETIMEDOUT":void 0,stdout:i.stdout,stderr:i.stderr})})})};var Lt="cc-safety-net.ts",
|
|
197
|
+
`).length};return new Promise((a)=>{let l=(d)=>{t.off("keypress",c),t.setRawMode(r),t.pause(),i(),a(d)};function c(d,m){e.onKey(d,m,{finish:l,draw:s})}t.on("keypress",c),s()})}function Fc(e={}){let t=0;return Oc({input:e.input??process.stdin,output:e.output??process.stdout,render:()=>Ug(t,e.globalHookInstalled===!0),onKey:(n,r,o)=>{if(r.ctrl&&r.name==="c"){o.finish(null),(e.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(r.name==="escape"||n==="q")return o.finish(null);if(r.name==="return"||r.name==="enter")return o.finish(Ac[t]);if(r.name==="up"||r.name==="down"||n==="k"||n==="j")t=(t+1)%Ac.length,o.draw()}})}function qo(e=process.stdin,t=process.stdout){return Boolean(e.isTTY&&t.isTTY&&typeof e.setRawMode==="function")}function jc(e,t,n={}){let r=n.output??process.stdout,o=Ng(t);return Oc({input:n.input??process.stdin,output:r,render:()=>Mg(e,t,o),onKey:(i,s,a)=>{let l=jg(e,i,s);if(!l)return;let c=Hg(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 Hc,lstatSync as Bg,mkdirSync as qg,mkdtempSync as Vg,readdirSync as zg,readFileSync as wt,rmSync as tr}from"node:fs";import{tmpdir as Kg}from"node:os";import{basename as Jg,dirname as Wg,join as G}from"node:path";import{fileURLToPath as Yg}from"node:url";var Vo="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",Ze="cc-safety-net",Xe="cc-safety-net/index.ts";import{spawn as Gg}from"node:child_process";var zo=(e,t)=>{let n=ze([...e],process.env);return new Promise((r)=>{let o=Gg(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",Nc=G("amp",Xe);function Zg(e){return G(e,".config","amp","plugins","cc-safety-net.ts")}function Xg(){let e=Wg(Yg(import.meta.url));return[G(e,"..",Nc),G(e,"..","..","..","dist",Nc)]}function Qg(e=Xg()){let t=e.find((n)=>Hc(n)&&Bg(n).isFile());if(!t)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return t}function Mc(e){try{return JSON.parse(e)}catch{return}}function nr(e){return e.subarray(0,Buffer.byteLength(Vo)).toString("utf-8")===Vo}async function on(e,t,n){let r=await e(t,n);if(r.status===0)return r;throw Error([`Failed to run ${t.join(" ")}${r.status===null?"":` (exit ${r.status})`}.`,[r.stdout,r.stderr].filter(Boolean).join(`
|
|
200
200
|
`).trim()].filter(Boolean).join(`
|
|
201
|
-
`))}async function
|
|
201
|
+
`))}async function Uc(e){let t=await e(["amp","plugins","repositories","--json"]);if(t.status===null)throw Error(`${t.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${t.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
|
|
202
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.
|
|
203
203
|
${[t.stdout,t.stderr].filter(Boolean).join(`
|
|
204
|
-
`)}`.trim());let n=
|
|
205
|
-
`}async function
|
|
206
|
-
`)}function
|
|
204
|
+
`)}`.trim());let n=Mc(t.stdout),r=(Array.isArray(n)?n:[]).filter((o)=>k(o,"scope")==="user"&&k(o,"exists")===!0&&k(o,"viewerCanWrite")===!0).map((o)=>k(o,"cloneRef")).find((o)=>typeof o==="string"&&o.length>0);if(!r)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return r}async function Gc(e,t){let n=Vg(G(Kg(),"cc-safety-net-amp-"));try{return await on(e,["amp","clone","user-plugins",n]),await t(n)}finally{tr(n,{recursive:!0,force:!0})}}function Ko(e){return`rerun ${e==="overwrite"?"install":"uninstall"} --amp`}function Bc(e,t,n){let r=G(e,t),o=_(r);if(!o)return;if(o.isSymbolicLink()||!o.isFile())throw Error(`Refusing to ${n} ${t} in your Amp personal plugins repository: not a regular file. Remove it there and ${Ko(n)}.`);let i=wt(r);if(nr(i))return i;throw Error(`Refusing to ${n} unmanaged file ${t} in your Amp personal plugins repository. Remove it there and ${Ko(n)}.`)}function qc(e,t){let n=G(e,Ze),r=_(n);if(!r)return;if(r.isSymbolicLink()||!r.isDirectory())throw Error(`Refusing to ${t} ${Ze} in your Amp personal plugins repository: not a regular directory. Remove it there and ${Ko(t)}.`);return Bc(e,Xe,t)}function eh(e){let t=G(e,Lt),n=_(t);if(!n||n.isSymbolicLink()||!n.isFile())return;let r=wt(t);return nr(r)?r:void 0}async function Vc(e,t,n,r){if(await on(e,n,t),(await on(e,["git","status","--porcelain"],t)).stdout.trim()==="")return!1;return await on(e,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",r],t),await on(e,["git","push","origin","HEAD"],t),!0}function er(e,t){th(e,t),nh(e,t)}function zc(e,t){if(t==="keep")return;throw Error(`Local Amp plugin ${e} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function th(e,t){let n=Zg(e),r=_(n);if(!r)return;if(!r.isSymbolicLink()&&r.isFile()&&nr(wt(n))){tr(n);return}zc(n,t)}function nh(e,t){let n=G(e,".config","amp","plugins",Ze),r=_(n);if(!r)return;if(!r.isSymbolicLink()&&r.isDirectory()&&rh(n)){tr(n,{recursive:!0});return}zc(n,t)}function rh(e){let t=Jg(Xe);if(zg(e).join("\x00")!==t)return!1;let n=G(e,t),r=_(n);return!!r&&!r.isSymbolicLink()&&r.isFile()&&nr(wt(n))}function oh(){let e=ve();if(!Hc(e))return"";let t=Mc(wt(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(Y(t))};
|
|
205
|
+
`}async function Kc(e,t=Qg(),n=zo){let r=Buffer.concat([wt(t),Buffer.from(oh(),"utf-8")]),o=await Uc(n);return Gc(n,async(i)=>{let s=`${o}/${Ze}`,a=qc(i,"overwrite"),l=Bc(i,Lt,"overwrite");if(a?.equals(r)&&!l)return er(e,"fail"),{path:s,alreadyInstalled:!0};if(qg(G(i,Ze),{recursive:!0}),O(G(i,Xe),r),l)tr(G(i,Lt));let c=await Vc(n,i,["git","add","--",Xe,...l?[Lt]:[]],`chore: update cc-safety-net plugin to v${I()}`);return er(e,"fail"),{path:s,alreadyInstalled:!c}})}async function Jc(e,t=zo){let n=await Uc(t);return Gc(t,async(r)=>{let o=qc(r,"remove"),i=eh(r),s=`${n}/${i&&!o?Lt:Ze}`;if(!o&&!i)return er(e,"keep"),{path:s,alreadyInstalled:!1};return await Vc(t,r,["git","rm","--",...o?[Xe]:[],...i?[Lt]:[]],`chore: remove cc-safety-net plugin v${I()}`),er(e,"keep"),{path:s,alreadyInstalled:!0}})}import{existsSync as Wc,mkdirSync as ih,readFileSync as sh}from"node:fs";import{dirname as ah}from"node:path";var Jo="npx -y cc-safety-net hook --agy-cli",Qe="cc-safety-net";function et(e){return Boolean(e)&&typeof e==="object"&&!Array.isArray(e)}function or(){return{PreToolUse:[{hooks:[{type:"command",command:Jo,timeout:30}]}]}}function Yc(e){try{let t=JSON.parse(sh(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))throw Error("Antigravity hooks config must be a JSON object");return t}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${e}: ${t.message}`);throw t}}function Zc(e){let t=e[Qe];if(t===void 0){let r=or();return e[Qe]=r,{definition:r,preToolUse:r.PreToolUse??[]}}if(!et(t))throw Error(`Antigravity hooks config entry "${Qe}" must be an object`);let n=Array.isArray(t.PreToolUse)?t.PreToolUse:[];return t.PreToolUse=n,{definition:t,preToolUse:n}}function Xc(e){if(!Array.isArray(e.PreToolUse))return!1;return e.PreToolUse.some((t)=>et(t)&&Array.isArray(t.hooks)&&t.hooks.some((n)=>et(n)&&n.command===Jo))}function lh(e){return Object.values(e).some((t)=>et(t)&&t.enabled!==!1&&Xc(t))}function ch(e){if(e[Qe]===void 0)return!1;let t=Zc(e);if(t.definition.enabled!==!1||!Xc(t.definition))return!1;return t.definition.enabled=!0,!0}function dh(e){if(e[Qe]===void 0){e[Qe]=or();return}let t=Zc(e);t.definition.enabled=!0,t.preToolUse.push(or().PreToolUse?.[0]??{hooks:[]})}function uh(e){let t=!1;for(let n of Object.values(e)){if(!et(n)||!Array.isArray(n.PreToolUse))continue;n.PreToolUse=n.PreToolUse.flatMap((r)=>{if(!et(r)||!Array.isArray(r.hooks))return[r];let o=r.hooks.filter((i)=>!et(i)||i.command!==Jo);if(o.length!==r.hooks.length)t=!0;return o.length===0?[]:[{...r,hooks:o}]})}return t}function rr(e,t){O(e,`${JSON.stringify(t,null,2)}
|
|
206
|
+
`)}function Qc(e){let t=Gt(e);if(ih(ah(t),{recursive:!0}),!Wc(t))return rr(t,{[Qe]:or()}),{path:t,alreadyInstalled:!1};let n=Yc(t);if(lh(n))return{path:t,alreadyInstalled:!0};if(ch(n))return rr(t,n),{path:t,alreadyInstalled:!1};return dh(n),rr(t,n),{path:t,alreadyInstalled:!1}}function ed(e){let t=Gt(e);if(!Wc(t))return{path:t,alreadyInstalled:!1};let n=Yc(t);if(!uh(n))return{path:t,alreadyInstalled:!1};return rr(t,n),{path:t,alreadyInstalled:!0}}import{existsSync as ph,readdirSync as fh,rmSync as mh}from"node:fs";import{join as gh}from"node:path";function td(e,t=process.platform,n){if(!ph(e))return;let r=t==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);fh(e).filter((o)=>o!==n&&r.test(o)).forEach((o)=>{mh(gh(e,o),{recursive:!0,force:!0})})}import{spawn as hh}from"node:child_process";var pe=X.map((e)=>({target:e.id,flag:e.flag,label:D(e.id),probeCommand:e.probeCommand}));function Wo(e){let t=new Set(e);return pe.map((n)=>n.target).filter((n)=>t.has(n))}async function nd(e,t){for(let n of e)await t(n)}var yh=5000;function Yo(e){return new Promise((t)=>{let n=ze([...e],process.env),r=hh(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)},yh);r.on("error",()=>i(!1)),r.on("close",(a)=>i(a===0))})}function rd(e=Yo,t={}){let n=new Set(t.configuredTargets??[]);return Promise.all(pe.map(async(r)=>({target:r.target,flag:r.flag,label:r.label,...id(t.action,await e(r.probeCommand),n.has(r.target))})))}function od(e,t){let n=new Set(t.configuredTargets??[]);return e.map((r)=>({...r,...id(t.action,r.available,n.has(r.target))}))}function id(e,t,n){if(e==="uninstall")return n?{available:!0}:{available:!1,unavailableReason:"not installed"};if(e==="install"&&n)return{available:!1,unavailableReason:"already installed"};if(!t)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as sd,readdirSync as vh,rmSync as bh}from"node:fs";import{join as kt}from"node:path";function ir(e,t=process.platform){let n=kt(process.env.npm_config_cache||(t==="win32"?kt(process.env.LOCALAPPDATA||kt(e,"AppData","Local"),"npm-cache"):kt(e,".npm")),"_npx");if(!sd(n))return;vh(n).filter((r)=>sd(kt(n,r,"node_modules","cc-safety-net"))).forEach((r)=>{bh(kt(n,r),{recursive:!0,force:!0})})}import{existsSync as ld,mkdirSync as Lh,readFileSync as cd}from"node:fs";import{dirname as wh,join as ad}from"node:path";var sn="npx -y cc-safety-net hook --kimi-code",Zo=`[[hooks]]
|
|
207
207
|
event = "PreToolUse"
|
|
208
|
-
command = "${sn}"`,
|
|
208
|
+
command = "${sn}"`,Xo=`{ event = "PreToolUse", command = "${sn}" }`;function dd(e){return ad(process.env.KIMI_CODE_HOME??ad(e,".kimi-code"),"config.toml")}function kh(e){return e.split(`
|
|
209
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(`
|
|
210
|
-
`)}function
|
|
211
|
-
`,t+1);return n===-1?e.length:n+1}function
|
|
212
|
-
`,n),o=r===-1?e.length:r,i=e.slice(n,o);if(/^\s*\[/.test(i))t=!0;if(!t){let s=/^(\s*)hooks\s*=\s*\[/.exec(i);if(s){let a=n+s[0].lastIndexOf("[");return{start:a,end:
|
|
213
|
-
${o}${
|
|
210
|
+
`)}function xh(e,t){if(e[t]!=="#")return t;let n=e.indexOf(`
|
|
211
|
+
`,t+1);return n===-1?e.length:n+1}function Ch(e,t){return Wn(e,t,{skipComment:xh,stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"})}function ud(e){let t=!1,n=0;while(n<e.length){let r=e.indexOf(`
|
|
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:Ch(e,a)}}}n=r===-1?e.length:r+1}return}function Sh(e,t){let n=e.slice(0,t.end).trimEnd(),r=nc(e,t.end),o=r===""?" ":`${r} `,i=!n.endsWith("[")&&!n.endsWith(",");return`${n}${i?",":""}
|
|
213
|
+
${o}${Xo}${e.slice(t.end)}`}function Rh(e){let t=ud(e);if(t&&e.slice(t.start+1,t.end).trim())return Sh(e,t);let n=kh(e).trimEnd();if(n==="")return`${Zo}
|
|
214
214
|
`;return`${n}
|
|
215
215
|
|
|
216
|
-
${
|
|
217
|
-
`}function
|
|
218
|
-
`),{path:t,alreadyInstalled:!1};let n=
|
|
219
|
-
`;return O(t,o),{path:t,alreadyInstalled:!0}}var
|
|
220
|
-
`)},opencode:{beforeInstall
|
|
221
|
-
`),`Enabled ${de} plugin in ${t}`}function
|
|
222
|
-
`),`Enabled npm:cc-safety-net extensions in ${t}`}function
|
|
223
|
-
`)}async function xt(e){let 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
|
|
225
|
-
`)}var
|
|
226
|
-
`),uninstall:()=>xt("copilot-cli")},cursor:{install:(e,t)=>Oe("install","cursor",e,t),uninstall:(e)=>Oe("uninstall","cursor",e)},"gemini-cli":{install:(e,t)=>tt("gemini-cli",e,t),uninstall:()=>xt("gemini-cli")},"grok-build":{install:(e,t)=>Oe("install","grok-build",e,t),uninstall:(e)=>Oe("uninstall","grok-build",e)},"hermes-agent":{install:(e,t)=>{if(!t)
|
|
227
|
-
`),uninstall:()=>xt("pi")}},
|
|
228
|
-
`);function
|
|
216
|
+
${Zo}
|
|
217
|
+
`}function Ph(e){return e.split(/(?=^\s*\[)/m).filter((n)=>!/^\s*\[\[hooks]]\s*$/m.test(n)||!n.includes(sn)).join("").trimEnd()}function Dh(e,t){let n=e.indexOf(Xo,t.start);if(n===-1||n>t.end)return e;return Yn(e,{start:n,end:n+Xo.length})}function pd(e){let t=dd(e);if(Lh(wh(t),{recursive:!0}),!ld(t))return O(t,`${Zo}
|
|
218
|
+
`),{path:t,alreadyInstalled:!1};let n=cd(t,"utf-8");if(n.includes(sn))return{path:t,alreadyInstalled:!0};return O(t,Rh(n)),{path:t,alreadyInstalled:!1}}function fd(e){let t=dd(e);if(!ld(t))return{path:t,alreadyInstalled:!1};let n=cd(t,"utf-8");if(!n.includes(sn))return{path:t,alreadyInstalled:!1};let r=ud(n),o=r?Dh(n,r):`${Ph(n)}
|
|
219
|
+
`;return O(t,o),{path:t,alreadyInstalled:!0}}var ei="safety-net@cc-marketplace",md=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gd=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function ni(e){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(e??"")}function Ld(e){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(e??"")}function _h(e){return/^Marketplace `cc-marketplace`\s*$/m.test(e??"")}var wd={"claude-code":{installCommands:(e)=>{let t=On(e,"cc-safety-net@cc-marketplace");return{commands:[...t?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...po(e).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:On(e,ei)?[["claude","plugin","uninstall",ei]]:[],update:t}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(e,t)=>{let n=t??await ue(["codex","plugin","list"]),r=Ld(n);return{commands:[r||_h(n)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:ni(n)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:r}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:"Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."},"copilot-cli":{installCommands:async()=>{let e=await ue(["copilot","plugin","list"]),t=[...ol(e)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...il(e)?[["copilot","plugin","uninstall",tl]]:[]];if(nl(e))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",de]],cleanupCommands:t,update:!0};return{commands:[rl(await ue(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",de]],cleanupCommands:t}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(e)=>{let t=bo(e);if(t.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(t.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:To,installCommands:()=>({commands:Jl()}),uninstallCommands:[["openclaw","plugins","uninstall",A,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
|
|
220
|
+
`)},opencode:{beforeInstall:Oo,installCommands:[["opencode","plugin","-g","-f","cc-safety-net@latest"]]},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function ar(){return process.env.HOME??Ah()}function kd(e,t=(n)=>n){try{let n=JSON.parse(t(bd(e,"utf-8")));if(!n||typeof n!=="object"||Array.isArray(n))throw Error(`Settings file ${e} must be a JSON object`);return n}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse ${e}: ${n.message}`);throw n}}function Th(e){let t=Qo(Jt(e),"settings.json");if(!ti(t))return;let n=kd(t,K),r=n.enabledPlugins;if(!r||typeof r!=="object"||Array.isArray(r))return;if(r[de]!==!1)return;let o=bd(t,"utf-8"),i=o.replace(new RegExp(`("${de}"\\s*:\\s*)false`),"$1true");return r[de]=!0,O(t,i!==o?i:`${JSON.stringify(n,null,2)}
|
|
221
|
+
`),`Enabled ${de} plugin in ${t}`}function Ih(e){let t=Fo(e);if(!ti(t))return;let n=kd(t);if(!Array.isArray(n.packages))return;let r=n.packages.find((o)=>!!o&&typeof o==="object"&&!Array.isArray(o)&&jo(o.source)&&("extensions"in o));if(!r)return;return delete r.extensions,O(t,`${JSON.stringify(n,null,2)}
|
|
222
|
+
`),`Enabled npm:cc-safety-net extensions in ${t}`}function hd(e,t){let n=E({label:t,booleans:Object.fromEntries(pe.map((i)=>[i.target,[i.flag]]))},e),r=n.errors[0];if(r)throw Error(r);let o=pe.filter((i)=>n.flags[i.target]).map((i)=>i.target);if(o.length!==1)throw Error(`Choose exactly one ${t} target: ${pe.map((i)=>i.flag).join(", ")}`);return o[0]}async function xd(e=ar(),t=pt){let[n,r,o]=await Promise.all([t(["amp","plugins","list"],30000),t(["codex","plugin","list"],30000),t(["copilot","--binary-version"])]);return{codexPluginListOutput:r,hooks:vt(process.cwd(),{homeDir:e,ampPluginListOutput:n,codexPluginListOutput:r,copilotCliVersion:o})}}async function $h(e,t=pt){let n=await xd(ar(),t);return n.hooks.filter((r)=>e==="install"?r.configured:r.detected||r.inspectionStatus==="not-inspected").filter((r)=>r.platform!=="codex"||!ni(n.codexPluginListOutput)||Ld(n.codexPluginListOutput)).map((r)=>r.platform)}function Oh(e,t,n){if(t.length>0)return{finish:async()=>[hd(t,e)]};if(!n.selectTargets&&!qo(n.input,n.output))return{finish:async()=>[hd(t,e)]};let r=n.detectConfiguredTargets??(()=>$h(e,n.fetchVersion)),o=Promise.all([rd(n.probeTargets),r()]);return{ready:o,finish:async()=>{let[i,s]=await o,a=od(i,{action:e,configuredTargets:s}),l=n.selectTargets?await n.selectTargets(e,vd(e,a)):await jc(e,vd(e,a),{input:n.input,output:n.output});if(l==="update")return l;if(!l||l.length===0)return null;return Wo(l)}}}async function tt(e,t,n=!1,r){let o=wd[e];o.beforeInstall?.(t);let i=typeof o.installCommands==="function"?await o.installCommands(t,r):{commands:o.installCommands};return await Ao(i.commands),await Gl(i.cleanupCommands??[]),[`${i.update||n?"Updated":"Installed"} ${D(e)} integration`,o.postInstallMessage].filter(Boolean).join(`
|
|
223
|
+
`)}async function xt(e){let t=wd[e];if(!t.uninstallCommands)throw Error(`${D(e)} uninstall is not supported`);return await Ao(t.uninstallCommands),`Uninstalled ${D(e)} integration`}function Fh(e){let t=fc(e);return t.alreadyInstalled?`Uninstalled OpenCode plugin from ${t.path}`:`OpenCode plugin not installed in ${t.path}`}var jh={"antigravity-cli":{install:Qc,uninstall:ed},cursor:{install:gl,uninstall:hl},"grok-build":{install:Rl,uninstall:Pl},"kimi-code":{install:pd,uninstall:fd}};function Oe(e,t,n,r=!1){if(e==="install"&&!r)ir(n);let o=jh[t][e](n),i=D(t),s=e!=="install"?"Uninstalled":r?"Updated":"Installed";return e==="install"&&o.alreadyInstalled?r?`${i} hook up to date in ${o.path}`:`${i} hook already installed in ${o.path}`:e==="uninstall"&&!o.alreadyInstalled?`${i} hook not installed in ${o.path}`:`${s} ${i} hook ${e==="install"?"in":"from"} ${o.path}`}var Nh={amp:{install:Kc,uninstall:Jc,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:Tl,uninstall:Il,afterInstall:async(e)=>{let t=Ro(e);return await ue(["hermes","plugins","enable",Q,"--no-allow-tool-override"]),!t},beforeUninstall:async(e)=>{So(e);try{await ue(["hermes","plugins","disable",Q])}catch(t){console.warn(`${t instanceof Error?t.message:String(t)}
|
|
224
|
+
Removing the plugin files anyway; ${Q} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function sr(e,t,n,r=!1){let o=Nh[t];if(e==="uninstall")await o.beforeUninstall?.(n);let i=e==="install"?await o.install(n):await o.uninstall(n),s=e==="install"&&await o.afterInstall?.(n),a=D(t),l=!s&&(e==="install"&&i.alreadyInstalled||e==="uninstall"&&!i.alreadyInstalled);return[l?e==="install"?`${a} plugin ${r?"up to date":"already installed"} at ${i.path}`:`${a} plugin not installed at ${i.path}`:`${e!=="install"?"Uninstalled":r?"Updated":"Installed"} ${a} plugin ${e==="install"?"at":"from"} ${i.path}`,l?void 0:o.restartNote].filter(Boolean).join(`
|
|
225
|
+
`)}var Hh={amp:{install:(e,t)=>sr("install","amp",e,t),uninstall:(e)=>sr("uninstall","amp",e)},"antigravity-cli":{install:(e,t)=>Oe("install","antigravity-cli",e,t),uninstall:(e)=>Oe("uninstall","antigravity-cli",e)},"claude-code":{install:(e,t)=>tt("claude-code",e,t),uninstall:()=>xt("claude-code")},codex:{install:(e,t,n)=>tt("codex",e,t,n),uninstall:()=>xt("codex")},"copilot-cli":{install:async(e,t)=>[await tt("copilot-cli",e,t),Th(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)ir(e);return sr("install","hermes-agent",e,t)},uninstall:(e)=>sr("uninstall","hermes-agent",e)},"kimi-code":{install:(e,t)=>Oe("install","kimi-code",e,t),uninstall:(e)=>Oe("uninstall","kimi-code",e)},openclaw:{install:async(e,t)=>{let n=await tt("openclaw",e,t);return await Wl(),n},uninstall:(e)=>(To(e),xt("openclaw"))},opencode:{install:async(e,t)=>{let n=await tt("opencode",e,t);return await cc(e),n},uninstall:(e)=>Fh(e)},pi:{install:async(e,t)=>[await tt("pi",e,t),Ih(e)].filter(Boolean).join(`
|
|
227
|
+
`),uninstall:()=>xt("pi")}},yd=["Install CC Safety Net as a native Kimi Code plugin:",""," 1. Start Kimi Code and run: /plugins install https://github.com/kenryu42/cc-safety-net"," Confirm the trust prompt; it defaults to cancel."," 2. Run /reload, or start a new session.","","Note: Kimi Code hooks are fail-open. When the hook process cannot start, crashes, or times","out, Kimi Code allows the tool call."].join(`
|
|
228
|
+
`);function Mh(e){if(Qt({homeDir:e,cwd:process.cwd()}).status!=="configured")return yd;return[yd,"",y.red(["CAUTION: the global Kimi Code hook is installed and will run alongside the plugin.","After the plugin is active, remove it with: cc-safety-net uninstall --kimi-code"].join(`
|
|
229
229
|
`))].join(`
|
|
230
|
-
`)}function
|
|
230
|
+
`)}function vd(e,t){return t.map((n)=>e==="install"&&n.target==="kimi-code"&&n.unavailableReason==="already installed"?{...n,available:!0,unavailableReason:void 0,label:`${n.label} (global hook installed)`}:n)}function Uh(e,t){if(e.selectKimiInstallMethod)return e.selectKimiInstallMethod();if(!qo(e.input,e.output))return Promise.resolve("global-hook");return Fc({input:e.input,output:e.output,globalHookInstalled:Qt({homeDir:t,cwd:process.cwd()}).status==="configured"})}async function Cd(e,t,n,r=!1,o){return Hh[t][e](n,r,o)}function Gh(e){let t=E({label:"update"},e).errors[0];if(t)throw Error(t)}async function Bh(e,t=pt){let n=await xd(e,t),r=Qo(Jt(e),"installed-plugins");return{targets:Wo([...n.hooks.filter((i)=>i.platform!=="copilot-cli"&&i.detected).map((i)=>i.platform),...[Fn,el,Qa].flatMap((i)=>ti(Qo(r,...i))?["copilot-cli"]:[]),...On(e,ei)?["claude-code"]:[],...ni(n.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:n.codexPluginListOutput}}async function qh(e){let t=ar(),n=e.output??process.stdout,r=(e.scriptPath??process.argv[1]??"").split(/[\\/]/),o=r.find((u)=>/^bunx-\d+-/.test(u)),i=o!==void 0||r.includes("_npx")?null:(e.checkLatestVersion??Te)(),s=async()=>{let u=i&&await i;if(u?.updateAvailable)n.write(`
|
|
231
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.
|
|
232
|
-
`)},a=
|
|
233
|
-
`)}),await s(),g.some((u)=>u.failed)?1:0}function
|
|
234
|
-
`),0;if(r==="update")return(n.runUpdate??(()=>
|
|
235
|
-
`);return}if(l==="plugin"){i.write(`${
|
|
236
|
-
`);return}}let a=await
|
|
232
|
+
`)},a=Bh(t,e.fetchVersion??pt).then(async(u)=>{let p=new Set(u.targets);return{targets:u.targets,codexPluginListOutput:u.codexPluginListOutput,available:new Map(await Promise.all(pe.filter((f)=>p.has(f.target)&&md.has(f.target)).map(async(f)=>[f.target,await Yo(f.probeCommand)])))}}),l=await Kt(e.showBanner??!0,()=>({ready:a,finish:()=>a}),()=>zt({input:e.input??process.stdin,output:n}),{loadingMessage:"Checking installed integrations…",output:n}),c=await Promise.resolve().then(()=>(td(Eh(),process.platform,o),null)).catch((u)=>an(u));if(l.targets.length===0){if(n.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),c!==null)console.error(c);return await s(),c===null?0:1}let d=l.targets.some((u)=>gd.has(u))?await Promise.resolve().then(()=>(ir(t),null)).catch((u)=>an(u)):null,m=await Tn(Promise.all(l.targets.map((u)=>{if(md.has(u)&&!l.available.get(u))return Promise.resolve({message:`${D(u)} not found; skipped`,failed:!1});if(d!==null&&gd.has(u))return Promise.resolve({message:d,failed:!0});return Cd("install",u,t,!0,l.codexPluginListOutput).then((p)=>({message:p,failed:!1}),(p)=>({message:an(p),failed:!0}))})),{loadingMessage:`Updating ${l.targets.length} integration${l.targets.length===1?"":"s"}…`,output:n}),g=c===null?m:[...m,{message:c,failed:!0}];return g.forEach((u)=>{u.failed?console.error(u.message):n.write(`${u.message}
|
|
233
|
+
`)}),await s(),g.some((u)=>u.failed)?1:0}function ri(e,t={}){return Promise.resolve().then(()=>Gh(e)).then(()=>qh(t)).catch((n)=>(console.error(an(n)),1))}async function ln(e,t,n={}){try{let r=await Kt(!0,()=>Oh(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??(()=>ri([],{fetchVersion:n.fetchVersion,input:n.input,output:n.output,showBanner:!1})))();let o=ar(),i=n.output??process.stdout;return await nd(r,async(s)=>{if(s==="kimi-code"&&e==="install"){let l=await Uh(n,o);if(l===null){i.write(`Cancelled: Kimi Code integration was not installed.
|
|
235
|
+
`);return}if(l==="plugin"){i.write(`${Mh(o)}
|
|
236
|
+
`);return}}let a=await Tn(Cd(e,s,o),{loadingMessage:`${e==="install"?"Installing":"Uninstalling"} ${D(s)} integration…`,output:i});i.write(`${a}
|
|
237
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}
|
|
238
238
|
Check file permissions for the target config file and parent directory.`;if(n==="ENOENT")return`${t}
|
|
239
239
|
Check that the target config path and parent directory exist.`;if(n==="ENOTDIR")return`${t}
|
|
240
|
-
Check that every parent path component is a directory.`;return t}import{mkdirSync as 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)
|
|
242
|
-
Added $schema to ${h.scope.toLowerCase()} config.`);
|
|
243
|
-
${y.red(h)}`);if(L)if(L.result.errors.length>0)
|
|
240
|
+
Check that every parent path component is a directory.`;return t}import{mkdirSync as Vh}from"node:fs";import{dirname as zh}from"node:path";import{createInterface as Kh}from"node:readline";var Sd=new Set(["check","apply"]),Rd="(unset)";async function Dd(e,t={}){let n=E({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},e),r=n.positionals[0],o=[...n.errors,...r&&!Sd.has(r)?[`Unknown policy subcommand: ${r}`]:[],...r&&Sd.has(r)&&!n.positionals[1]?[`policy ${r} requires a file`]:[],...n.positionals.slice(2).map((u)=>`Unexpected policy argument: ${u}`)];if(o.length>0){for(let u of o)console.error(u);return 1}let i=n.positionals[1];if(!r||!i)return bt(xn,console.error),1;let s=n.flags.global?ve():se(t.cwd??process.cwd()),a=_e(i),l=[...a.errors,...Ee(a.value).map((u)=>`${i}: ${u}`),...!n.flags.global&&Yh(a.value)&&a.value.audit!==void 0?[`${i}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(l.length>0){for(let u of l)console.error(u);return 1}let c=Y(a.value);if(console.log(`Scope: ${n.flags.global?"user":"project"} (${s})`),console.log(`Proposal: ${i}`),n.flags.global)Pd(Y(_e(s).value),c,!0);if(!n.flags.global){let u=lt().baseline;console.log("Effective policy (user + project merged):"),Pd(Ge(u,Be(_e(s).value).policy).policy,Ge(u,Be(a.value).policy).policy,!1)}if(r==="check")return 0;let d=t.input??process.stdin,m=t.output??process.stdout;if(!d.isTTY||!m.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${i}${n.flags.global?" --global":""}`),1;if(!await Jh(`Apply this policy to ${s}? [y/N] `,d,m))return console.log("Cancelled; nothing was written."),0;return Wh(s,a.value,c,n.flags.global),console.log(`Policy applied: ${s}`),0}function Jh(e,t,n){let r=Kh({input:t,output:n,terminal:!1});return new Promise((o)=>{r.once("close",()=>o(!1)),r.question(e,(i)=>{o(/^y(es)?$/i.test(i.trim())),r.close()})})}function Wh(e,t,n,r){if(r){cn(n);return}Vh(zh(e),{recursive:!0}),J(e,jt(t,n))}function Pd(e,t,n){let r=Ft(e,t,n);if(r.length===0){console.log("No changes.");return}console.log(`Changes (${r.length}):`);for(let o of r)console.log(` ${o.field}: ${o.before??Rd} -> ${o.after??Rd}`)}function Yh(e){return!!e&&typeof e==="object"&&!Array.isArray(e)}import{join as Ty}from"node:path";var Ad="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function lr(e,t){if(!e.ok){$d(e);return}Td(e,t)}function _d(e,t,n){if(e.ok)console.log(n);if(!e.add){lr(e,`Added rulebook source: ${t}`);return}if(!e.ok){$d(e);return}if(e.add.added.length>0)console.log(`Added ${e.add.added.length} ${e.add.added.length===1?"rulebook":"rulebooks"} from ${e.add.source} at ${e.add.ref}:`),e.add.added.forEach((r)=>{console.log(` - ${r}`)});if(e.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${e.add.source} at ${e.add.ref}: ${e.add.alreadyConfigured.join(", ")}`);if(e.add.commits.length>0)console.log(`Vendored at ${e.add.commits.map((r)=>r.slice(0,7)).join(", ")}.`);Td(e,"Rule config updated.")}function Td(e,t){for(let n of e.changes??[])console.log(n);console.log(t),console.log(""),Zh(e.entries)}function Zh(e){if(e.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${e.length}):`);for(let t of e)console.log(` - ${t.name} ${t.version} (${Xh(t.ruleCount)})`),console.log(` Source: ${t.spec}`)}function Xh(e){return`${e} ${e===1?"rule":"rules"}`}function Id(e){nt("Active sources",e.rulebooks,(t)=>[`[${t.source}] ${t.name} ${t.version}`,` Source: ${t.spec}`]),nt("Active rules",e.rules,(t)=>[`[${ey(e,t.name)}] ${t.name}`,...Qh(t),` Reason: ${t.reason}`]),nt("Disabled rules",Ed(e,"off"),(t)=>[t.key]),nt("Reason overrides",Ed(e,"reason"),(t)=>[t.key,` Reason: ${t.value.reason}`]),nt("Transparent wrappers",e.transparent_wrappers,(t)=>[t]),nt("Issues",e.errors,(t)=>[t]),nt("Warnings",e.warnings,(t)=>[t])}function nt(e,t,n){if(t.length===0){console.log(`${e}: (none)`);return}console.log(`${e} (${t.length}):`);for(let r of t){let[o,...i]=n(r);console.log(` - ${o}`);for(let s of i)console.log(` ${s}`)}}function Qh(e){if(!e.match)return[` Command: ${e.subcommand?`${e.command} ${e.subcommand}`:e.command}`,` Block args: ${e.block_args.join(", ")}`];return[` Command: ${[e.command,...e.match.command_path].join(" ")}`,...e.match.any_args?[` Any args: ${e.match.any_args.join(", ")}`]:[],...e.match.exclude_args?[` Exclude args: ${e.match.exclude_args.join(", ")}`]:[]]}function ey(e,t){return e.rulebooks.find((n)=>n.rules.includes(t))?.source??"project"}function Ed(e,t){return Object.entries({...e.userConfig?.overrides??{},...e.projectConfig?.overrides??{}}).filter((n)=>{if(t==="off")return n[1]==="off";return!!n[1]&&typeof n[1]==="object"}).map(([n,r])=>({key:n,value:r}))}function $d(e){for(let t of e.errors)console.error(t)}import{dirname as Od,join as cr}from"node:path";var ty=".safety-net.json",ny="~/.cc-safety-net/config.json";async function Hd(e){return[await Fd({legacyPath:Nd({cwd:e.cwd}),configPath:oe(e.cwd),defaultRulebookName:"project-rules",migratedFrom:ty,cleanup:e.cleanup,syncOptions:{cwd:e.cwd}}),await Fd({legacyPath:It(),configPath:ie(),defaultRulebookName:"user-rules",migratedFrom:ny,cleanup:e.cleanup,syncOptions:{cwd:e.cwd,global:!0}})].every((n)=>n)?0:1}async function Fd(e){let t=U(e.syncOptions),n=x(t.filesystemScope,e.legacyPath),r=w(n);if(r===null)return console.log(`No legacy config found at ${e.legacyPath}`),!0;let o=oy(r);if(!o.ok){for(let g of o.errors)console.error(g);return!1}let i=q(t.configTarget);if(i.errors.length>0){for(let g of i.errors)console.error(g);return!1}let s=i.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},a=iy(Od(e.configPath),s.rules,e.defaultRulebookName,e.migratedFrom,t.filesystemScope),l=cr(Od(e.configPath),a,"rulebook.json"),c=x(t.filesystemScope,l),d=[jd(t.configTarget),jd(c)],m=await ry(e,t.configTarget,c,a,o.config.rules,s.rules.includes(a)?s.rules:[...s.rules,a],s.overrides??{},s.transparent_wrappers??[]);if(!m.ok){ly(d);for(let g of m.errors)console.error(g);return!1}if(!e.cleanup)return console.log(`Migrated legacy config at ${e.legacyPath}. Legacy file is no longer used.`),!0;if(!ay(t.configTarget,c,a,e.migratedFrom,o.config.rules))return console.error(`Migration cleanup verification failed for ${e.legacyPath}`),!1;return he(n),console.log(`Deleted legacy config at ${e.legacyPath}`),!0}async function ry(e,t,n,r,o,i,s,a){try{return J(t,{version:1,rules:i,overrides:s,transparent_wrappers:a}),J(n,sy(r,e.migratedFrom,o)),await Tt(e.syncOptions)}catch(l){return{ok:!1,errors:[l instanceof Error?l.message:String(l)]}}}function oy(e){try{let t=JSON.parse(e),n=Lr(t);if(n.errors.length>0)return{ok:!1,errors:n.errors};return{ok:!0,config:{version:1,rules:t.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function iy(e,t,n,r,o){let i=t.find((s)=>cy(x(o,cr(e,s,"rulebook.json")))===r);if(i)return i;if(w(x(o,cr(e,n,"rulebook.json")))===null)return n;for(let s=2;;s++){let a=`${n}-${s}`;if(w(x(o,cr(e,a,"rulebook.json")))===null)return a}}function sy(e,t,n){return{rulebook_version:1,name:e,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:t,allowed_commands:[...new Set(n.map((r)=>r.command))],rules:n,tests:n.map((r)=>({command:[r.command,r.subcommand,r.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:r.name}))}}function ay(e,t,n,r,o){if(!q(e).config?.rules.includes(n))return!1;try{let s=w(t);if(s===null)return!1;let a=JSON.parse(s);return a.migrated_from===r&&JSON.stringify(a.rules)===JSON.stringify(o)}catch{return!1}}function jd(e){return{target:e,content:w(e)}}function ly(e){for(let t of e){if(t.content===null){he(t.target);continue}B(t.target,t.content)}}function cy(e){let t=w(e);if(t===null)return null;try{let n=JSON.parse(t);return typeof n.migrated_from==="string"?n.migrated_from:null}catch{return null}}import{mkdir as dy,readFile as uy,writeFile as py}from"node:fs/promises";import{dirname as fy,join as my}from"node:path";var gy=86400000,hy=604800000;async function Ud(e=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=Mr();if(!t)return null;let n=my(t,".cc-safety-net","update-check.json"),r=await yy(n,e);if(!r.lastCheck||e-r.lastCheck>gy){let s=await Te();if(r.lastCheck=e,s.latestVersion)r.latestVersion=s.latestVersion;if(!await Md(n,r))return null;if(s.error)return null}let o=r.latestVersion,i=I();if(!o||!so(o,i))return null;if(r.notifiedVersion===o&&r.notifiedAt!==void 0&&e-r.notifiedAt<hy)return null;if(r.notifiedVersion=o,r.notifiedAt=e,!await Md(n,r))return null;return`UPDATE_AVAILABLE: cc-safety-net v${o} is available (running v${i}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function yy(e,t){let n=await uy(e,"utf8").then((i)=>JSON.parse(i)).catch(()=>{return});if(!n||typeof n!=="object"||Array.isArray(n))return{};let r=n,o=(i)=>typeof i==="number"&&Number.isFinite(i)&&i<=t?i:void 0;return{lastCheck:o(r.lastCheck),latestVersion:typeof r.latestVersion==="string"?r.latestVersion:void 0,notifiedVersion:typeof r.notifiedVersion==="string"?r.notifiedVersion:void 0,notifiedAt:o(r.notifiedAt)}}async function Md(e,t){return dy(fy(e),{recursive:!0,mode:448}).then(()=>py(e,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as vy,resolve as oi}from"node:path";var Gd="CC Safety Net Config",by="═".repeat(Gd.length),Ly="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",wy=new Set(["rule.json","rule.lock","cache"]);function Bd(e={}){try{return ky(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}function ky(e){let t=e.cwd??process.cwd(),n=e.userConfigPath??ie(),r=e.projectConfigPath??oe(t),o=e.legacyUserConfigPath??It(),i=e.legacyProjectConfigPath??Ai(t),s=oi(t,Pt),a=Ae({cwd:t,userConfigPath:n,projectConfigPath:r}),l=Ae({cwd:t}),c=x(a.userScope,n),d=x(a.projectScope,r),m=e.legacyUserConfigPath?St(e.legacyUserConfigPath,"user policy"):x(l.userScope,o),g=e.legacyProjectConfigPath?St(e.legacyProjectConfigPath,"project policy"):x(l.projectScope,i),u=!1,p=!1,f=[],b=[],L=xy(x(l.projectScope,s));if(Sy(),w(c)!==null){let h=me(c);if(h.errors.push(...W(n,a.userScope)),f.push({scope:"User",path:n,result:h,schema:"rules",target:c}),h.errors.length>0)u=!0}if(w(m)!==null)if(p=!0,w(c)!==null)b.push(dr("user","cleanup"));else{let h=wr(m);if(f.push({scope:"User",path:o,result:h,schema:"legacy",inactive:!0,target:m}),b.push(dr("user",h.errors.length>0?"fix-or-delete":"migrate")),h.errors.length>0)u=!0}if(w(d)!==null){let h=me(d);if(h.errors.push(...W(r,a.projectScope)),f.push({scope:"Project",path:oi(r),result:h,schema:"rules",target:d}),h.errors.length>0)u=!0;if(w(g)!==null)p=!0,b.push(dr("project","cleanup"))}else if(w(g)!==null){p=!0,u=!0;let h=wr(g);f.push({scope:"Project",path:oi(i),result:h,schema:"legacy",inactive:!0,target:g}),b.push(dr("project",h.errors.length>0?"fix-or-delete":"migrate"))}if(L?.result.errors.length)u=!0;if(f.length===0&&!L)return console.log(`
|
|
241
|
+
No config files found. Using built-in rules only.`),0;for(let h of f)if(h.inactive)Py(h.scope,h.path,h.result);else if(h.result.errors.length>0)Dy(h.scope,h.path,h.result.errors);else{if(h.schema==="rules"&&_y(h.target))console.log(`
|
|
242
|
+
Added $schema to ${h.scope.toLowerCase()} config.`);Ry(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)Ey(L.path,L.result.errors);else Ay(L.path,L.result);if(u)return console.error(`
|
|
244
244
|
Config validation failed.`),1;return console.log(p?`
|
|
245
245
|
Configs valid with warnings.`:`
|
|
246
|
-
All configs valid.`),0}function
|
|
247
|
-
✓ ${e} config: ${t}`),console.log(` Schema: ${r==="rules"?"rulebook sources":"legacy inline rules"}`),n.ruleNames.size>0){console.log(` ${r==="rules"?"Sources":"Rules"}:`);let o=1;for(let i of n.ruleNames)console.log(` ${o}. ${i}`),o++}else console.log(` ${r==="rules"?"Sources":"Rules"}: (none)`)}function
|
|
248
|
-
✗ Legacy ${e.toLowerCase()} config: ${t}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),n.errors.length>0){console.error(" Errors:");let r=1;for(let o of n.errors)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++;return}if(n.ruleNames.size>0){console.error(" Rules:");let r=1;for(let o of n.ruleNames)console.error(` ${r}. ${o}`),r++;return}console.error(" Rules: (none)")}function
|
|
249
|
-
✓ GitHub source rules: ${e}`),console.log(" Rulebooks:");let n=1;for(let r of t.ruleNames)console.log(` ${n}. ${r}`),n++}function
|
|
250
|
-
✗ ${e}: ${t}`),console.error(" Errors:");let r=1;for(let o of n)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++}function
|
|
251
|
-
`))}import{spawn as
|
|
252
|
-
return POSIX path of (choose folder with prompt "${
|
|
246
|
+
All configs valid.`),0}function dr(e,t){let n=`legacy ${e} config`;if(t==="cleanup")return`Warning: Legacy ${e} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(t==="migrate")return`Warning: Legacy ${e} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${e} config is no longer supported. Fix or delete the ${n}, then run \`npx -y cc-safety-net rule migrate\`.`}function xy(e){if(it(e)===null)return null;let t=Cy(e);if(t.ruleNames.size===0&&t.errors.length===0)return null;return{path:e.path,result:t}}function Cy(e){let t=[],n=new Set,r=(it(e)??[]).filter((o)=>!wy.has(o.name)).sort((o,i)=>o.name.localeCompare(i.name));if(r.length===0)return{errors:t,ruleNames:n};for(let o of r){if(!Pe.test(o.name)){t.push(`rulebook directory names must match ${Pe}: ${o.name}`);continue}if(o.kind!=="directory"){t.push(`${o.name} must be a rulebook directory`);continue}let i=x(e.scope,vy(e.path,o.name,"rulebook.json")),s=w(i);if(s===null){t.push(`${o.name}/rulebook.json is required`);continue}try{let a;try{a=JSON.parse(s)}catch{t.push(`${o.name}/rulebook.json: invalid JSON`);continue}let l=Dt(a);if(l.name!==o.name){t.push(`rulebook name "${l.name}" must match folder "${o.name}"`);continue}let c=fn(l);if(c.length>0){t.push(...c.map((d)=>`${o.name}/rulebook.json: ${d}`));continue}n.add(o.name)}catch(a){t.push(a instanceof Error?`${o.name}/rulebook.json: ${a.message}`:`${o.name}/rulebook.json: ${String(a)}`)}}return{errors:t,ruleNames:n}}function Sy(){console.log(Gd),console.log(by)}function Ry(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 Py(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 Dy(e,t,n){qd(`${e} config`,t,n)}function Ay(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 Ey(e,t){qd("GitHub source rules",e,t)}function qd(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 _y(e){try{let t=w(e);if(t===null)return!1;let n=JSON.parse(t);if(n.$schema)return!1;return B(e,JSON.stringify({$schema:Ly,...n},null,2)),!0}catch(t){if(t instanceof H)throw t;return!1}}var Vd=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),Iy=new Set(["add","remove","list"]),$y="cc-safety-net/rulebooks";async function zd(e){try{return await Oy(e)}catch(t){if(t instanceof H)return console.error(t.message),1;throw t}}async function Oy(e){let t=jy(e),n=t.help?Fy(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);Uy(s.configTarget);let a=Ty(s.configDir,"example-rules","rulebook.json"),l=x(s.filesystemScope,a);if(t.example&&w(l)===null)jr(l,"example-rules");let c=W(s.configPath,s.filesystemScope);for(let d of c)console.error(d);if(c.length>0)return 1;return console.log("Rule config initialized."),0}if(r==="add"){let s=Kd(t);if(!s)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let a=U(i),l=await Ir(s,{...i,ref:t.ref,rulebooks:t.only.length>0?t.only:void 0});return _d(l,s,`Scope: ${t.global?"user":"project"} (${a.configDir})`),l.ok?0:1}if(r==="remove"){if(!o)return console.error("rule remove requires a source"),1;let s=await Or(o,{...i,deleteSource:t.deleteSource});return lr(s,`Removed rulebook source: ${o}`),s.ok?0:1}if(r==="update"){let s=await Tt({...i,only:o,refresh:!0});return lr(s,"Rule config updated."),s.ok?0:1}if(r==="sync")return Ma({global:t.global});if(r==="list"){let s=De();return Id(s),s.errors.length>0?1:0}if(r==="wrapper")return Gy(t);if(r==="migrate")return Hd({cleanup:t.cleanup,cwd:process.cwd()});if(r==="doc"){console.log(Ad);let s=await Ud();if(s)console.error(s);return 0}if(r==="verify")return Bd();return 1}function Fy(e){if(e.length===0)return ut;let t=ut.subcommands.filter((r)=>r.usage.split(" ")[0]===e[0]);if(t.length===0)return null;if(e.length===1&&t.length>1)return{name:`rule ${e[0]}`,description:`Subcommands of rule ${e[0]}`,usage:`rule ${e[0]} <subcommand>`,subcommands:t,options:[]};let n=e.length===1?t[0]:t.find((r)=>r.usage.split(" ")[1]===e[1]);if(!n)return null;return{name:`rule ${e[0]}`,description:n.description,usage:`rule ${n.usage}`,options:e[0]==="add"?eo:[],examples:e[0]==="add"?to:void 0}}function jy(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 Ny(n),n}function Ny(e){let[t]=e.positionals;if(t&&!Vd.has(t))e.errors.push(`Unknown rule subcommand: ${t}`);if(e.deleteSource&&t!=="remove")if(t&&Vd.has(t))e.errors.push(`Unknown option for rule ${t}: --delete-source`);else e.errors.push("--delete-source is only valid with 'rule remove'");if(e.check&&t)e.errors.push(Ct(t,"--check"));if(e.cleanup&&t!=="migrate")e.errors.push(Ct(t,"--cleanup"));if(e.example&&t!=="init")e.errors.push(Ct(t,"--example"));if(e.ref&&t!=="add")e.errors.push(Ct(t,"--ref"));if(e.only.length>0&&t!=="add")e.errors.push(Ct(t,"--only"));if(t==="add")Hy(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")My(e);else if(e.positionals.length>2)e.errors.push(`Unexpected rule argument: ${e.positionals[2]}`);if(t==="list"&&e.global)e.errors.push("Unknown option for rule list: --global")}function Kd(e){if(e.positionals[1])return e.positionals[1];if(e.ref||e.only.length>0)return $y;return}function Hy(e){let t=Kd(e);if(!t)return;if((e.ref||e.only.length>0)&&!Se(t)){if(e.ref)e.errors.push(`--ref can only select a ref for an owner/repo source: ${t}`);if(e.only.length>0)e.errors.push("--only can only select rulebooks from an owner/repo source");return}if(e.ref&&!Ne(e.ref))e.errors.push(`--ref must use valid path segments: ${e.ref}`);let n=e.only.filter((r)=>!Pe.test(r));if(n.length>0)e.errors.push(`Invalid rulebook names: ${n.join(", ")}`)}function Ct(e,t){return e?`Unknown option for rule ${e}: ${t}`:`Unknown option for rule: ${t}`}function My(e){let t=e.positionals[1],n=e.positionals[2];if(!t){e.errors.push("rule wrapper requires add, remove, or list");return}if(!Iy.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 Uy(e){if(w(e)===null){Fr(e);return}let t=q(e);if(!t.config)return;J(e,{version:1,rules:t.config.rules,overrides:t.config.overrides??{},transparent_wrappers:t.config.transparent_wrappers??[]})}async function Gy(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 By(a.config?.transparent_wrappers??[]),0}if(!n||!Ur.test(n))return console.error("transparent wrapper must match command pattern"),1;if(Br(n))return console.error(`reserved command "${n}" cannot be a wrapper`),1;let o=q(r);if(o.errors.length>0){for(let a of o.errors)console.error(a);return 1}let i=o.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},s=t==="add"?[...new Set([...i.transparent_wrappers??[],n])]:(i.transparent_wrappers??[]).filter((a)=>a!==n);return J(r,{version:1,rules:i.rules,overrides:i.overrides??{},transparent_wrappers:s}),console.log(t==="add"?`Added transparent wrapper: ${n}`:`Removed transparent wrapper: ${n}`),0}function By(e){if(e.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${e.length}):`);for(let t of e)console.log(` - ${t}`)}import{homedir as ai}from"node:os";import{sep as Yy}from"node:path";import{existsSync as qy,readFileSync as Vy}from"node:fs";import{homedir as zy}from"node:os";import{join as Ky}from"node:path";async function Jy(e){if(e.isTTY)return null;return(await Wr(e).catch(()=>null))?.trim()||null}function Wy(){if(process.env.CLAUDE_SETTINGS_PATH)return process.env.CLAUDE_SETTINGS_PATH;return Ky(zy(),".claude","settings.json")}function ii(){let e=Wy();if(!qy(e))return!1;try{let t=Vy(e,"utf-8"),n=JSON.parse(t);if(!n.enabledPlugins)return!1;let r="cc-safety-net@cc-marketplace";if(!(r in n.enabledPlugins))return!1;return n.enabledPlugins[r]===!0}catch(t){if(Nt(S.debug))console.error(`CC Safety Net debug: failed to read Claude settings: ${e}: ${t instanceof Error?t.message:String(t)}`);return!1}}async function si(e=process.stdin){let t=ii(),n;if(!t)n="\uD83D\uDEE1️ CC Safety Net ❌";else{let o=z({cwd:process.cwd()}),i=o.policy,s=ye(i),a=Object.values(Ue(i,s.capabilities)).some((d)=>d.changesInherited),l={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[a?"custom":s.effectiveLevel],c=(o.policyScopes?.weakenings.length??0)>0?"\uD83D\uDD3B":"";n=`\uD83D\uDEE1️ CC Safety Net ${l}${s.worktreeMode?"\uD83C\uDF33":""}${c}${o.state==="degraded"?"⚠️":""}`}let r=await Jy(e);if(r&&!r.startsWith("{"))console.log(`${r} | ${n}`);else console.log(n)}function Jd(){let e=z({cwd:process.cwd()}),t=e.policy,n=ye(t),r=!!process.env.NO_COLOR||!process.stdout.isTTY,o=Math.min(process.stdout.columns||80,100),i=r?"ok":"✔",s=r?"OFF":"✘",a=(p,f)=>{let b=` ${p.padEnd(13)}${f}`;return(b.length>o?`${b.slice(0,o-1)}…`:b).replaceAll(s,y.red(s))},l=Object.values(Ue(t,n.capabilities)).some((p)=>p.changesInherited),c=(p)=>p===ai()||p.startsWith(`${ai()}${Yy}`)?`~${p.slice(ai().length)}`:p,d={ready:y.green,degraded:y.yellow}[e.state],m=e.policyScopes?.weakenings??[],g=[...ii()?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...e.diagnostics],u=r?"-":"·";console.log([`${r?"":"\uD83D\uDEE1️ "}CC Safety Net — ${d(e.state)}`,"",a("Protection",`destructive ${t.destructiveCommandProtectionEnabled?i:s} secrets ${t.secretProtection.enabled?i:s}`),a("Level",l?`${n.effectiveLevel} (customised)`:n.effectiveLevel),a("Rules",t.rules.length===0?"none active":`${t.rules.length} active`),a("Policy",c(ve())),...e.policyScopes?[a("Project",c(se()))]:[],...n.worktreeMode?[a("Worktree","relaxations active")]:[],"",...m.length===0?[]:[" Project policy",...m.flatMap((p)=>nn(p," ",o-6).map((f,b)=>b===0?` ${f}`:f)),""],...g.length===0?[" Everything configured is active."]:[" Not active",...g.flatMap((p)=>nn(p," ",o-6).map((f,b)=>b===0?` ${u} ${f}`:f)),""," Full report: cc-safety-net doctor"]].join(`
|
|
251
|
+
`))}import{spawn as fu}from"node:child_process";import{randomBytes as a0}from"node:crypto";import{existsSync as l0}from"node:fs";import{createServer as c0}from"node:http";import{Writable as d0}from"node:stream";import{homedir as Zy}from"node:os";var ur=500;function Xy(e){let t=e.filter((o)=>o.decision!=="allow"),n=e.filter((o)=>o.decision==="allow"),r=Math.min(t.length,Math.max(ur-n.length,Math.ceil(ur/2)));return[...t.slice(0,r),...n.slice(0,ur-r)]}function Wd(e,t=be()){if(t)He(t);let n=(f)=>new Date(f.getFullYear(),f.getMonth(),f.getDate()).getTime(),r=n(new Date),o=new Date(r);o.setDate(o.getDate()-(e-1));let i=o.getTime(),s=[],a={count:0};for(let f of t?Ce(t,a):[])for(let b of Fe(f,a)){if(!b||typeof b.ts!=="string"||typeof b.command!=="string")continue;let L=new Date(b.ts).getTime();if(!Number.isFinite(L))continue;if(L>=i)s.push(b)}s.sort((f,b)=>new Date(b.ts).getTime()-new Date(f.ts).getTime());let l=Array.from({length:e},()=>0),c=Array.from({length:e},()=>0),d={},m={},g={},u=0,p=0;for(let f of s){let b=f.agent||"unknown";d[b]=(d[b]??0)+1;let L=Math.round((r-n(new Date(f.ts)))/86400000),h=e-1-L,R=L>=0&&L<e;if(R)c[h]=(c[h]??0)+1;if(f.decision!=="allow"){if(u++,f.ruleId)m[f.ruleId]=(m[f.ruleId]??0)+1;let v=rt(f.segment||f.command);if(v)g[v]=(g[v]??0)+1;if(f.failureStage)p++;if(R)l[h]=(l[h]??0)+1}}return{days:e,logsDir:t,homeDir:Zy(),totalInWindow:s.length,truncated:s.length>ur,unreadable:a.count,counts:{blocked:u,allowed:s.length-u,agents:d,blockedByDay:l,analyzedByDay:c,rules:m,commands:g,errors:p},entries:Xy(s).sort((f,b)=>new Date(b.ts).getTime()-new Date(f.ts).getTime())}}import{spawn as Qy}from"node:child_process";import{existsSync as e0,statSync as Yd}from"node:fs";import{delimiter as t0,join as n0}from"node:path";var r0=120000,pr="Choose the project folder",o0=`try
|
|
252
|
+
return POSIX path of (choose folder with prompt "${pr}")
|
|
253
253
|
on error number -128
|
|
254
254
|
return ""
|
|
255
|
-
end try`,
|
|
255
|
+
end try`,i0=`Add-Type -AssemblyName System.Windows.Forms
|
|
256
256
|
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
257
|
-
$dialog.Description = '${
|
|
258
|
-
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,
|
|
257
|
+
$dialog.Description = '${pr}'
|
|
258
|
+
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Zd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${pr}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",pr]}],Xd=(e,t)=>(t.PATH??"").split(t0).some((n)=>{if(n.length===0)return!1;try{let r=Yd(n0(n,e));return r.isFile()&&(r.mode&73)!==0}catch{return!1}});function li(e,t){if(e==="darwin"||e==="win32")return!0;if(e!=="linux")return!1;if(!t.DISPLAY&&!t.WAYLAND_DISPLAY)return!1;return Zd.some((n)=>Xd(n.binary,t))}function s0(e,t){if(e==="darwin")return{cmd:"osascript",args:["-e",o0]};if(e==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",i0]};let n=Zd.find((r)=>Xd(r.binary,t));return n?{cmd:n.binary,args:n.args}:null}function ci(e=process.platform,t=process.env){let n=s0(e,t);if(!n)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((r)=>{let o=Qy(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"})},r0);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(!e0(c)||!Yd(c).isDirectory())return a({error:"That selection is not a folder on disk"});a({path:c})})})}var Qd=`<!doctype html>
|
|
259
259
|
<html lang="en">
|
|
260
260
|
<head>
|
|
261
261
|
<meta charset="utf-8">
|
|
@@ -3268,6 +3268,12 @@ var catalog = [
|
|
|
3268
3268
|
id: "codex",
|
|
3269
3269
|
displayName: "Codex",
|
|
3270
3270
|
doctorOrder: 4,
|
|
3271
|
+
runtime: {
|
|
3272
|
+
order: 3,
|
|
3273
|
+
flags: ["-cx", "--codex"],
|
|
3274
|
+
description: "Run as a Codex PreToolUse hook",
|
|
3275
|
+
legacyTopLevelFlags: []
|
|
3276
|
+
},
|
|
3271
3277
|
install: {
|
|
3272
3278
|
order: 4,
|
|
3273
3279
|
flag: "--codex",
|
|
@@ -3280,7 +3286,7 @@ var catalog = [
|
|
|
3280
3286
|
displayName: "GitHub Copilot CLI",
|
|
3281
3287
|
doctorOrder: 7,
|
|
3282
3288
|
runtime: {
|
|
3283
|
-
order:
|
|
3289
|
+
order: 6,
|
|
3284
3290
|
flags: ["-cp", "--copilot-cli"],
|
|
3285
3291
|
description: "Run as GitHub Copilot CLI PreToolUse hook",
|
|
3286
3292
|
legacyTopLevelFlags: ["-cp", "--copilot-cli"]
|
|
@@ -3297,7 +3303,7 @@ var catalog = [
|
|
|
3297
3303
|
displayName: "Gemini CLI",
|
|
3298
3304
|
doctorOrder: 6,
|
|
3299
3305
|
runtime: {
|
|
3300
|
-
order:
|
|
3306
|
+
order: 5,
|
|
3301
3307
|
flags: ["-gc", "--gemini-cli"],
|
|
3302
3308
|
description: "Run as Gemini CLI BeforeTool hook",
|
|
3303
3309
|
legacyTopLevelFlags: ["-gc", "--gemini-cli"]
|
|
@@ -3314,7 +3320,7 @@ var catalog = [
|
|
|
3314
3320
|
displayName: "Grok Build",
|
|
3315
3321
|
doctorOrder: 8,
|
|
3316
3322
|
runtime: {
|
|
3317
|
-
order:
|
|
3323
|
+
order: 7,
|
|
3318
3324
|
flags: ["-gb", "--grok-build"],
|
|
3319
3325
|
description: "Run as Grok Build PreToolUse hook",
|
|
3320
3326
|
legacyTopLevelFlags: []
|
|
@@ -3331,7 +3337,7 @@ var catalog = [
|
|
|
3331
3337
|
displayName: "Hermes Agent",
|
|
3332
3338
|
doctorOrder: 9,
|
|
3333
3339
|
runtime: {
|
|
3334
|
-
order:
|
|
3340
|
+
order: 8,
|
|
3335
3341
|
flags: ["-ha", "--hermes-agent"],
|
|
3336
3342
|
description: "Run as Hermes Agent pre_tool_call hook",
|
|
3337
3343
|
legacyTopLevelFlags: []
|
|
@@ -3348,7 +3354,7 @@ var catalog = [
|
|
|
3348
3354
|
displayName: "Kimi Code",
|
|
3349
3355
|
doctorOrder: 10,
|
|
3350
3356
|
runtime: {
|
|
3351
|
-
order:
|
|
3357
|
+
order: 9,
|
|
3352
3358
|
flags: ["-kc", "--kimi-code"],
|
|
3353
3359
|
description: "Run as Kimi Code PreToolUse hook",
|
|
3354
3360
|
legacyTopLevelFlags: []
|
|
@@ -3398,7 +3404,7 @@ var catalog = [
|
|
|
3398
3404
|
displayName: "Cursor",
|
|
3399
3405
|
doctorOrder: 5,
|
|
3400
3406
|
runtime: {
|
|
3401
|
-
order:
|
|
3407
|
+
order: 4,
|
|
3402
3408
|
flags: ["-cu", "--cursor"],
|
|
3403
3409
|
description: "Run as Cursor preToolUse hook",
|
|
3404
3410
|
legacyTopLevelFlags: []
|
|
@@ -5945,6 +5951,6 @@ load().then((loaded) => {
|
|
|
5945
5951
|
</script>
|
|
5946
5952
|
</body>
|
|
5947
5953
|
</html>
|
|
5948
|
-
`;var
|
|
5949
|
-
`),{path:n,errors:[]}}catch(o){return{path:n,errors:[o instanceof Error?o.message:String(o)]}}}function
|
|
5950
|
-
`)}}finally{console.log=s,console.error=a}},o=
|
|
5954
|
+
`;var eu='<script id="ccsn-data" type="application/json">';function tu(e){return Qd.replace(eu,()=>eu+JSON.stringify({token:e}).replaceAll("<","\\u003c"))}var fr="kenryu42/cc-safety-net",u0=`https://github.com/${fr}`,ui=1e4,p0=7,f0="The project draft directory changed; reload the draft before applying.",m0="audit settings are user scope only; remove the audit section from a project proposal";async function mu(e,t={}){let n=E({label:"gui",booleans:{noOpen:["--no-open"]}},e),r=t.log??console.log,o=t.error??console.error;if(n.errors.length>0){for(let s of n.errors)o(s);return o("Usage: cc-safety-net gui [--no-open]"),1}let i=await g0(t);if(r(`CC Safety Net policy GUI: ${i.url}`),!n.flags.noOpen)try{await(t.openBrowser??R0)(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 S0(i),0}async function g0(e={}){let t=a0(24).toString("base64url"),n={dir:null,revision:0},r=c0((s,a)=>{h0(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:()=>C0(r)}}async function h0(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(!w0(e,i,n)){C(t,403,{error:"Forbidden"});return}if(e.method==="GET"&&i.pathname==="/"){x0(t,tu(n));return}if(e.method==="GET"&&i.pathname==="/api/policy"){let s=au(r),a=z(r);C(t,200,{...s,configState:Ht(a),...a.policyScopes?{projectPolicy:{path:se(r.cwd),weakenings:a.policyScopes.weakenings}}:{},destructiveCommandRules:$t,secretPatterns:iu,version:I(),preview:s.errors.length>0?null:cu(s.policy)});return}if(e.method==="POST"&&i.pathname==="/api/policy/preview"){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=lu(s.value);C(t,a.errors.length>0?400:200,a);return}if(e.method==="POST"&&i.pathname==="/api/policy/explain"){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=s.value;if(a===null||typeof a.command!=="string"){C(t,400,{errors:["command must be a string"]});return}let l=Ee(a.policy);if(l.length>0){C(t,400,{errors:l});return}C(t,200,b0(a.command,a.policy,r));return}if(e.method==="POST"&&i.pathname==="/api/policy"){let s=await dn(e);if(!s.ok){C(t,s.status,{errors:[s.error]});return}let a=cn(s.value,r);C(t,a.errors.length>0?400:200,a);return}if(e.method==="POST"&&i.pathname==="/api/reset"){C(t,200,cn(su,r));return}if(e.method==="POST"&&i.pathname==="/api/repair"){C(t,200,du(r));return}if(e.method==="POST"&&i.pathname==="/api/policy/project/choose-directory"){let s=await(r.chooseDirectory??ci)();if("path"in s)o.dir=s.path,o.revision+=1;C(t,200,{cancelled:"cancelled"in s,..."error"in s?{error:s.error}:{}});return}if(e.method==="GET"&&i.pathname==="/api/policy/project"){let s=gu(o,r),a=nu(s),l=lt(r);C(t,200,{dir:s,path:se(s),revision:o.revision,baseline:l.baseline,userPolicyDiagnostics:l.diagnostics,projection:a.projection,projectionDiagnostics:a.diagnostics,canPickDirectory:li(process.platform,process.env)});return}if(e.method==="POST"&&i.pathname==="/api/policy/project/diff"){let s=await ru(e,t,o,r);if(!s)return;let a=nu(s.dir),l=lt(r).baseline,c=Ge(l,Be(s.proposal).policy);C(t,200,{rows:Ft(Ge(l,a.projection).policy,c.policy,!1),weakenings:c.weakenings,existingFileDiagnostics:a.diagnostics,errors:[]});return}if(e.method==="POST"&&i.pathname==="/api/policy/project/apply"){let s=await ru(e,t,o,r);if(!s)return;let a=v0(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=L0(i.searchParams.get("days"),s);if(a===null){C(t,400,{error:`days must be an integer between 1 and ${s}`});return}C(t,200,Wd(a,r.activityLogsDir));return}if(e.method==="POST"&&i.pathname==="/api/rules/choose-directory"){C(t,200,await ci());return}if(e.method==="GET"&&i.pathname==="/api/rules"){let s=De(r),a=new Map(s.rules.map((l)=>[l.name,l]));C(t,200,{projectPath:r.cwd??process.cwd(),canPickDirectory:li(process.platform,process.env),rulebooks:s.rulebooks.map((l)=>({source:l.source,spec:l.spec,name:l.name,version:l.version,rules:l.rules.flatMap((c)=>{let d=a.get(c);if(!d)return[];return[{name:d.name,command:d.command,subcommand:d.subcommand,block_args:d.block_args,reason:d.reason}]})})),errors:s.errors,warnings:s.warnings});return}if(e.method==="GET"&&i.pathname==="/api/star/context"){C(t,200,await(r.fetchStarContext??(()=>_0({logsDir:r.activityLogsDir})))());return}if(e.method==="POST"&&i.pathname==="/api/star"){let s=await(r.starRepo??P0)();C(t,200,s.ok?{ok:!0}:{ok:!1,fallbackUrl:u0});return}if(e.method==="GET"&&i.pathname==="/api/integrations"){C(t,200,await(r.fetchIntegrations??D0)());return}if(e.method==="GET"&&i.pathname==="/api/health"){C(t,200,await(r.fetchHealth??A0)());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??E0)(l,a));return}C(t,404,{error:"Not found"})}function gu(e,t){return e.dir??t.cwd??process.cwd()}function nu(e){let t=se(e),n=l0(t)?_e(t):{value:void 0,errors:[]},r=Be(n.value);return{projection:r.policy,diagnostics:[...n.errors,...r.diagnostics]}}async function ru(e,t,n,r){let o=gu(n,r),i=n.revision,s=await dn(e);if(!s.ok)return C(t,s.status,{errors:[s.error]}),null;let a=s.value;if(typeof a?.revision!=="number")return C(t,400,{errors:["revision must be a number"]}),null;if(a.revision!==i)return C(t,409,{errors:[f0]}),null;let l=y0(a.proposal);if(l.length>0)return C(t,400,{errors:l}),null;return{dir:o,proposal:a.proposal}}function y0(e){let t=Ee(e);if(t.length>0)return t;return e?.audit===void 0?[]:[m0]}function v0(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)}
|
|
5955
|
+
`),{path:n,errors:[]}}catch(o){return{path:n,errors:[o instanceof Error?o.message:String(o)]}}}function b0(e,t,n){let r=Y(t),o=z(n),i=Ot({rules:o.policy.rules,transparentWrappers:o.policy.transparentWrappers,safety:pu(r.safety),worktreeMode:r.workflow.worktree_mode,destructiveCommandProtectionEnabled:r.destructive_command_protection.enabled,destructiveCommandRuleOverrides:r.destructive_command_protection.overrides,destructiveCommandAllowPaths:r.destructive_command_protection.allow_paths,secretProtection:{enabled:r.secret_protection.enabled,disabledRules:uu(r.secret_protection.overrides),denyPaths:r.secret_protection.deny_paths,allowPaths:r.secret_protection.allow_paths}});return at(e,{policySnapshot:i,cwd:n.cwd,userConfigDir:n.userConfigDir})}function L0(e,t){if(e===null)return Math.min(p0,t);let n=Number(e);if(!Number.isInteger(n)||n<1||n>t)return null;return n}function w0(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 k0=1048576;async function dn(e){let t=[],n=0;for await(let r of e){let o=r;if(n+=o.byteLength,n>k0)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 x0(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 C0(e){return new Promise((t,n)=>{e.close((r)=>r?n(r):t())})}function S0(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 R0(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",n=process.platform==="win32"?["/c","start","",e]:[e];return new Promise((r,o)=>{let i=fu(t,n,{detached:!0,stdio:"ignore"}),s=(l)=>{i.off("spawn",a),o(l)},a=()=>{i.off("error",s),i.unref(),r()};i.once("error",s),i.once("spawn",a)})}async function P0(e="gh",t=ui){return{ok:await di(e,["api","-X","PUT",`/user/starred/${fr}`],t)===0}}async function D0(e={}){let t=await qt(e.fetcher),n=hu(t,e.homeDir);return{targets:X.map((r)=>{let o=n.find((i)=>i.platform===r.id);return{target:r.id,label:D(r.id),version:t.versions[r.id]??null,status:o?.configured?"active":o?.detected?"disabled":o?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:t.version,nodeVersion:t.nodeVersion,platform:t.platform}}}function hu(e,t){return vt(process.cwd(),{homeDir:t,ampPluginListOutput:e.ampPluginListOutput,codexPluginListOutput:e.codexPluginListOutput,copilotCliVersion:e.versions["copilot-cli"]})}async function A0(e={}){let[t,n]=await Promise.all([qt(e.fetcher),(e.checkUpdates??Te)()]);return{hooks:hu(t,e.homeDir).filter((r)=>r.detected).map((r)=>({platform:r.platform,label:D(r.platform),configured:r.configured})),update:{currentVersion:n.currentVersion,latestVersion:n.latestVersion??null,updateAvailable:n.updateAvailable}}}var ou=Promise.resolve();function E0(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 d0({write(c,d,m){i.push(String(c).replace(/\n$/,"")),m()}}),...n})===0,output:i.join(`
|
|
5956
|
+
`)}}finally{console.log=s,console.error=a}},o=ou.then(r);return ou=o.then(()=>{return},()=>{return}),o}async function _0(e={}){let[t,n,r]=await Promise.all([T0(e.command),I0(e.fetchRepo),Promise.resolve(Rn(ct(),e.logsDir).totalBlocked)]);return{starred:t,starCount:n,blockedTotal:r}}async function T0(e="gh",t=ui){if(await di(e,["auth","status"],t)!==0)return null;let n=await di(e,["api",`/user/starred/${fr}`],t);if(n===0)return!0;if(n===null)return null;return!1}function di(e,t,n){return new Promise((r)=>{let o=fu(e,t,{stdio:"ignore",windowsHide:!0}),i=!1,s,a=(l)=>{if(i)return;if(i=!0,s)clearTimeout(s);r(l)};o.once("error",()=>a(null)),o.once("close",a),s=setTimeout(()=>{o.kill(),a(null)},n)})}async function I0(e=fetch){try{let t=await e(`https://api.github.com/repos/${fr}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(ui)});if(!t.ok)return null;let n=await t.json();return typeof n.stargazers_count==="number"?n.stargazers_count:null}catch{return null}}function $0(e){if(e[0]!=="help")return!1;let t=e[1];if(!t)Bo(),process.exit(0);if(rn(t))process.exit(0);console.error(`Unknown command: ${t}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var O0={hook:async(e)=>{let t=Qs(e);if(t){await t.run();return}console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),rn("hook",console.error),process.exit(1)},install:async(e)=>{process.exit(await ln("install",e))},update:async(e)=>{process.exit(await ri(e))},uninstall:async(e)=>{process.exit(await ln("uninstall",e))},rule:async(e)=>{process.exit(await zd(e))},policy:async(e)=>{process.exit(await Dd(e))},status:async(e)=>{if(fe(E({label:"status"},e).errors))process.exit(1);Jd()},statusline:async(e)=>{let t=E({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},e);if(t.errors.length===0&&t.flags.claudeCode){await si();return}if(fe(t.errors),!t.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");rn("statusline",console.error),process.exit(1)},doctor:async(e)=>{let t=No(e);if(!t)process.exit(1);let n=await yc({json:t.json,skipUpdateCheck:t.skipUpdateCheck});process.exit(n)},logs:async(e)=>{process.exit(await Ls(e))},gui:async(e)=>{process.exit(await mu(e))},explain:async(e)=>{process.exit(await Cc(e))}};async function F0(){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?Sn(n):void 0;if(t.help&&r&&r.name!=="rule")rn(r.name),process.exit(0);if(!n||t.help&&!r)Bo(),process.exit(0);if(t.flags.version)Pc(),process.exit(0);if(r){await O0[r.name](e.slice(1));return}let o=ea(n);if(o){await o.run();return}if(n==="--statusline"){await si();return}console.error(n.startsWith("-")?`Unknown option: ${n}`:`Unknown command: ${n}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}F0().catch((e)=>{console.error("CC Safety Net error:",e),process.exit(1)});
|