cc-safety-net 2.0.6 → 2.0.7
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 +35 -96
- package/dist/amp/cc-safety-net.ts +53 -53
- package/dist/bin/cc-safety-net.js +124 -129
- package/dist/chunks/index-4pw6zr4t.js +64 -0
- package/dist/index.js +1 -1
- package/dist/openclaw/cc-safety-net/index.js +51 -51
- 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 +2 -2
- package/package.json +2 -3
- package/dist/chunks/index-3a1zwkma.js +0 -64
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{$ as
|
|
3
|
-
${
|
|
4
|
-
`).filter(Boolean).flatMap((e)=>{try{return[JSON.parse(e)]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as ud}from"node:path";var R3=["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 mr(n){let t=0,e={allocateSegment(){return t++},getNextSegmentIndex(){return t},recordGlobal(r){n.record({kind:"step",scope:"global",step:r})},recordSegment(r,a=e.currentSegmentIndex){if(a===void 0)return;n.record({kind:"step",scope:"segment",segmentIndex:a,step:r})}};return e}function kr(n={}){let t=[],e=n.maxEvents??512,r={maxTextLength:n.maxTextLength??2048,maxListLength:n.maxListLength??128,maxObjectProperties:n.maxObjectProperties??n.maxListLength??128,maxDepth:n.maxDepth??16},a=0,l,d=new Set;return{record(s){if(l)return;try{if(!s||t.length>=e){a++;return}t.push(Zt(K3(s,r,d)))}catch{a++}},finish(s){if(l)return l;try{l=Zt({events:Object.freeze(t),droppedEvents:a,terminal:M3(s,r,d)})}catch{a++,l=Object.freeze({events:Object.freeze(t),droppedEvents:a,terminal:Object.freeze({result:"blocked",reason:"trace unavailable".slice(0,r.maxTextLength),segment:"trace unavailable".slice(0,r.maxTextLength)})})}return l}}}function K3(n,t,e){if(n.kind!=="step")throw TypeError("invalid trace event");let{scope:r,step:a}=n;Sn(a,e,t);let l=X2(a,t,e);if(r==="global")return{kind:"step",scope:"global",step:l};if(r!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:n.segmentIndex,step:l}}function M3(n,t,e){let r=n.result;if(r==="allowed")return Object.freeze({result:"allowed"});if(r!=="blocked")throw TypeError("invalid trace terminal");let a=n.ruleId;return Object.freeze({result:"blocked",reason:X2(n.reason,t,e),segment:X2(n.segment,t,e),...a?{ruleId:X2(a,t,e)}:{}})}function Sn(n,t,e,r=0,a=new WeakSet){if(typeof n==="string"){let s=n.slice(0,e.maxTextLength);if(!Qt(s))return;for(let c of Dr(s))for(let i of c.match(/[^\s"'()$]+/g)??[])t.add(qr(i));return}if(!n||typeof n!=="object"||r>=e.maxDepth||a.has(n))return;if(a.add(n),Array.isArray(n)){let s=Math.min(n.length,e.maxListLength);for(let c=0;c<s;c++)Sn(n[c],t,e,r+1,a);return}let l=0,d=new Set;for(let s in n){if(!Object.hasOwn(n,s))continue;if(l>=e.maxObjectProperties)break;l++,Sn(s,t,e);let c=Jt(s,e,t);if(d.has(c))continue;d.add(c),Sn(n[s],t,e,r+1,a)}}function X2(n,t,e,r=0,a=new WeakSet){if(typeof n==="string")return Jt(n,t,e);if(!n||typeof n!=="object")return n;if(r>=t.maxDepth)return;if(a.has(n))return;if(a.add(n),Array.isArray(n)){let s=[],c=Math.min(n.length,t.maxListLength);for(let i=0;i<c;i++)s.push(X2(n[i],t,e,r+1,a));return s}let l={},d=0;for(let s in n){if(!Object.hasOwn(n,s))continue;if(d>=t.maxObjectProperties)break;d++;let c=Jt(s,t,e);if(Object.hasOwn(l,c))continue;Object.defineProperty(l,c,{value:X2(n[s],t,e,r+1,a),enumerable:!0,configurable:!0,writable:!0})}return l}function Jt(n,t,e){let r=n.slice(0,t.maxTextLength),a=Qt(r)?gr(r):r,l=e.size>0?G3(a,e):a;return(V3(l)?$r(l):l).slice(0,t.maxTextLength)}function V3(n){return n.includes("PRIVATE KEY")||n.includes("://")||n.includes("eyJ")||n.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(n)||n.length>=14&&R3.some((t)=>n.includes(t))||n.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(n)}function G3(n,t){return n.replace(/[^\s"'()$]+/g,(e)=>t.has(qr(e))?"<redacted>":e)}function qr(n){let t=2166136261,e=2166136261;for(let r=0;r<n.length;r++)t=Math.imul(t^n.charCodeAt(r),16777619),e=Math.imul(e^n.charCodeAt(n.length-r-1),16777619);return`${t>>>0}:${e>>>0}:${n.length}`}function Zt(n){if(n&&typeof n==="object"&&!Object.isFrozen(n)){for(let t of Object.values(n))Zt(t);Object.freeze(n)}return n}function Br(n,t,e,r){let a=r??jr(),l=e??a.getCommandProgram(n,t.shell??"auto"),d=kr(),s=mr(d),c=l.dialect==="powershell"?a.getCommandProgram(n,"posix"):l,i=Fr(c);s.recordGlobal({type:"parse",input:n,segments:i.map((v)=>[...v])});let L=zr(n,{...t,analyzePartialProgram:!0,trace:s},l,a),u=s.getNextSegmentIndex();if(L&&u>0&&u<i.length)s.recordSegment({type:"segment-skipped",index:u,reason:"prior-segment-blocked"},u);return Object.freeze({decision:L,trace:d.finish(L?{result:"blocked",reason:L.reason,segment:L.evidence.find((v)=>v.kind==="command")?.segment??n,...L.ruleId?{ruleId:L.ruleId}:{}}:{result:"allowed"}),program:l})}import{resolve as C3}from"node:path";function Xt(n){let t=Jr().safeParse(n);return{errors:t.success?[]:Qr(t.error.issues),ruleNames:new Set(Zr(n).map((e)=>e.toLowerCase()))}}function Yt(n){let t=Yr(n);if(!t.ok)return t.result;return Xt(t.parsed)}function Yr(n){let t=[],e=new Set;try{let r=typeof n==="string"?sn(n):n,a=g(r);if(a===null)return t.push(`File not found: ${r.path}`),{ok:!1,result:{errors:t,ruleNames:e}};if(!a.trim())return t.push("Config file is empty"),{ok:!1,result:{errors:t,ruleNames:e}};return{ok:!0,parsed:JSON.parse(a)}}catch(r){if(r instanceof Z)return t.push(r.message),{ok:!1,result:{errors:t,ruleNames:e}};let a=r instanceof Error?r.message:String(r);return t.push(r instanceof SyntaxError?"Invalid JSON":a),{ok:!1,result:{errors:t,ruleNames:e}}}}function Sr(n){return C3(n??process.cwd(),".safety-net.json")}function a2(n){let t=Yr(n);if(!t.ok)return t.result;let e=Xr(t.parsed);return{errors:e.errors,ruleNames:e.sources}}import{isAbsolute as U3,join as Hn,relative as O3,resolve as Hr,sep as T3}from"node:path";async function W2(n={}){let t=Gt(n);return _3(t,await An(t,S2()))}function _3(n,t){if(!t.ok)return t;let e=U(n),r=[...new Set(l2(e.configPath,e.lockPath,n,e.filesystemScope))];if(r.length===0)return t;return{ok:!1,errors:r,warnings:t.warnings,entries:t.entries}}async function An(n,t,e,r={}){let a=null,l=!1;try{let d=U(n),s=Kt(d.configTarget);if(!s.ok)return s.result;let c=s.config;if(n.check)return td(c,d,n);a={target:d.lockTarget,content:g(d.lockTarget)};let i=Mt(d.lockTarget);if(i.errors.some((h)=>h.startsWith("Unable to access ")))return{ok:!1,errors:i.errors,warnings:[],entries:[]};if(n.only&&i.errors.length>0)return{ok:!1,errors:i.errors,warnings:[],entries:[]};let L=i.errors.length>0?null:i.lock,u=n.only?Gr(c,L,n.only):{ok:!0,specs:c.rules};if(!u.ok)return u.result;if(n.only&&!L&&u.specs.length<c.rules.length)return{ok:!1,errors:[`No lockfile available for partial update; run ${Mr}`],warnings:[],entries:[]};let v=(await P3(u.specs,(h)=>Ur(h,d.configDir,n,L,d.filesystemScope,t),t)).map((h)=>ed(h,L,e));for(let h of v)ld(h.content,h.entry,d.configDir,n,d.filesystemScope);let p=n.only?rd(c,L,v):v.map((h)=>h.entry);l=!0,T(d.lockTarget,{version:1,rulebooks:p},void 0,r._testAfterPolicyRename);let f=new Map(v.map((h)=>[h.entry.spec,h.rulebook.rules.length])),o=dd(p,d.configDir,n,d.filesystemScope,r);return{ok:!0,errors:[],warnings:o,entries:p.map((h)=>ad(h,f))}}catch(d){if(l&&a)try{Y2(a.target,a.content)}catch(s){return H2(s)}return H2(d)}}async function Vt(n,t={}){return E3(n,Gt(t),S2())}async function E3(n,t,e,r={}){let a=null,l=!1;try{let d=U(t),s=g(d.configTarget);a={target:d.configTarget,content:s};let c=Kt(d.configTarget);if(!c.ok)return c.result;let i=c.config,L=Kr(n)?await Or(n,e):[{spec:n}],u=L.map((f)=>f.spec),v=[...new Set([...i.rules,...u])];if(v.length>Wt)return I3();if(v.length!==i.rules.length)l=!0,T(d.configTarget,{version:1,rules:v,overrides:i.overrides??{},transparent_wrappers:i.transparent_wrappers??[]},void 0,r._testAfterPolicyRename);let p=await An(t,e,new Map(L.filter((f)=>!!f.display_ref).map((f)=>[f.spec,f.display_ref])),r);if(!p.ok)Y2(d.configTarget,s);return p}catch(d){if(l&&a)try{Y2(a.target,a.content)}catch(s){return H2(s)}return H2(d)}}async function P3(n,t,e=S2()){if(n.length>Wt)throw Error(Rt);let r=Array(n.length),a=0,l,d=Array.from({length:Math.min(n.length,Vr.concurrency)},async()=>{while(!l){let s=a;if(s>=n.length)return;a++;try{r[s]=await t(n[s],s,e.controller.signal)}catch(c){if(!l)l={value:c},a=n.length,e.controller.abort(c);return}}});if(await Promise.all(d),l)throw l.value;return r}function I3(){return{ok:!1,errors:[Rt],warnings:[],entries:[]}}function Gt(n){return{cwd:n.cwd,cacheConfigDir:n.cacheConfigDir,userConfigDir:n.userConfigDir,userConfigPath:n.userConfigPath,projectConfigPath:n.projectConfigPath,global:n.global,check:n.check,only:n.only,refresh:n.refresh}}function N3(n){return{...Gt(n),deleteSource:n.deleteSource}}async function Ct(n,t={}){try{return await nd(n,N3(t),{})}catch(e){return H2(e)}}async function nd(n,t,e){let r=U(t),a=O(r.configTarget);if(a.errors.length>0)return{ok:!1,errors:a.errors,warnings:[],entries:[]};if(!a.config)return{ok:!1,errors:[`No config found at ${r.configPath}`],warnings:[],entries:[]};let l=Mt(r.lockTarget);if(l.errors.length>0)return{ok:!1,errors:l.errors,warnings:[],entries:[]};let d=Cr(a.config.rules,l.lock,n);if(!d.ok)return d.result;let s=t.deleteSource?sd(r.configDir,d.specs,l.lock,r.filesystemScope):{ok:!0,dirs:[]};if(!s.ok)return s.result;let c=g(r.configTarget);if(c===null)return H2(Error("Rules config is unavailable."));try{T(r.configTarget,{version:1,rules:a.config.rules.filter((u)=>!d.specs.includes(u)),overrides:a.config.overrides??{},transparent_wrappers:a.config.transparent_wrappers??[]},void 0,e._testAfterPolicyRename)}catch(u){throw Y2(r.configTarget,c),u}let i=await An(t,S2(),void 0,e);if(!i.ok)return Y2(r.configTarget,c),i;let L=id(s.dirs,e,r.filesystemScope);if(!L.ok){Y2(r.configTarget,c);let u=await An(t,S2(),void 0,e);if(!u.ok)return{ok:!1,errors:[...L.result.errors,...u.errors],warnings:u.warnings,entries:u.entries};return L.result}return i}async function td(n,t,e){let r=Tr(n,t.lockPath,t.configDir,e,e.global?"user":"project",t.filesystemScope);return{ok:r.errors.length===0&&r.warnings.length===0,errors:[...r.errors,...r.warnings],warnings:[],entries:r.entries}}function ed(n,t,e){let r=t?.rulebooks.find((l)=>l.spec===n.entry.spec&&l.kind==="github"),a=e?.get(n.entry.spec)??(r?.kind==="github"?r.display_ref:void 0);if(!a||n.entry.kind!=="github")return n;return{...n,entry:{...n.entry,display_ref:a}}}function rd(n,t,e){let r=new Set(n.rules),a=new Set(t?.rulebooks.map((d)=>d.spec)??[]),l=new Map(e.map((d)=>[d.entry.spec,d.entry]));return[...(t?.rulebooks.filter((d)=>r.has(d.spec))??[]).map((d)=>l.get(d.spec)??d),...e.filter((d)=>!a.has(d.entry.spec)).map((d)=>d.entry)]}function ad(n,t){return{...n,ruleCount:t.get(n.spec)}}function ld(n,t,e,r,a){let l=Ht(t,At(e,r));w2(D(a,l),n)}function dd(n,t,e,r,a){let l=At(t,e),d=Wn(l),s=D(r,d),c=A2(s);if(!c)return[];let i=n.map((u)=>D(r,Ht(u,l))),L=c.filter((u)=>u.kind==="directory").map((u)=>({directory:D(r,Hn(d,u.name)),identity:D(r,Hn(d,u.name,Rr))})).filter((u)=>!i.some((v)=>Ar(u.identity,v))).map((u)=>u.directory);for(let u of L)Wr(u);return L.flatMap((u)=>{try{return Ld(u,a),[]}catch{return["Unable to prune rules policy cache safely."]}})}function sd(n,t,e,r){let a=new Map(e?.rulebooks.map((i)=>[i.spec,i])??[]),l=t.flatMap((i)=>{let L=a.get(i);if(!L)return Ln.test(i)?[]:["--delete-source can only delete local rulebook sources"];return L.kind==="local-directory"?[]:["--delete-source can only delete local rulebook sources"]}),d=t.map((i)=>{let L=a.get(i);return Hn(n,L?.kind==="local-directory"?L.path:i)}),s=l.length>0?[]:d.flatMap((i)=>cd(n,i,r)),c=[...l,...s];return c.length>0?{ok:!1,result:{ok:!1,errors:c,warnings:[],entries:[]}}:{ok:!0,dirs:d}}function cd(n,t,e){let r=Hr(n),a=Hr(t),l=O3(r,a);if(l===""||l===".."||l.startsWith(`..${T3}`)||U3(l))return[`Refusing to delete local rulebook source outside ${n}: ${t}`];let d=D(e,a),s=A2(d);if(!s)return[`Local rulebook source directory not found: ${t}`];let c=s.find((i)=>i.name==="rulebook.json");if(!c)return[`Local rulebook source directory is missing rulebook.json: ${t}`];if(c.kind!=="file")throw new Z(e.label);if(g(D(e,Hn(a,"rulebook.json"))),s.length>1)return[`Local rulebook source directory contains extra files: ${t}. delete manually if you really want to remove the directory.`];return[]}function id(n,t,e){let r=n.flatMap((a)=>{try{return pd(D(e,a),t),[]}catch(l){return[`Failed to delete local rulebook source ${a}: ${l instanceof Error?l.message:String(l)}`]}});return r.length>0?{ok:!1,result:{ok:!1,errors:r,warnings:[],entries:[]}}:{ok:!0}}function Ld(n,t){if(t._testPruneRulebookCacheDir){t._testPruneRulebookCacheDir(n.path);return}St(n)}function pd(n,t){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(n.path);return}St(n)}function Y2(n,t){if(t===null){cn(n);return}w2(n,t)}function H2(n){return{ok:!1,errors:[n instanceof Error?n.message:String(n)],warnings:[],entries:[]}}function V2(n,t){let e=vd(t),r=n1(e),a={effectiveLevel:r.effectiveLevel,selectedPreset:e.policySnapshot.policy.safety.level??"standard",effectiveCapabilities:r.effectiveCapabilities,destructiveCommandRuleOverrides:e.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:l,configValid:d}=od({cwd:t?.cwd,userConfigDir:t?.userConfigDir});if(!n||!n.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:l,configValid:d,...a};let s=bd(n,e);if(s)return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",ruleModule:s.ruleModule,ruleFunction:s.ruleFunction,matched:!0,reason:s.reason}]}]},result:"blocked",reason:A(s.reason),segment:A(s.target),...s.ruleId?{ruleId:A(s.ruleId)}:{},configSource:l,configValid:d,...a};let c=Br(n,e),i=c.decision,L=i?.ruleId??fd(n,e),u=un.find((p)=>p.id===L&&p.activationCapability),v=u?r.policy.effectiveDestructiveCommandRules[u.id]:void 0;return{trace:yd(c.trace),result:i?"blocked":"allowed",reason:i?A(i.reason):void 0,segment:i?A(i.evidence.find((p)=>p.kind==="command")?.segment??n):void 0,ruleId:i?.ruleId?A(i.ruleId):void 0,customRule:hd(wd(i?.ruleId,e.policySnapshot)),configSource:l,configValid:d,...a,...u&&v?{ruleActivation:{id:u.id,...v}}:{}}}function od(n){let t=_(n?.cwd),e=n?.userConfigPath??E(n),r=P({cwd:n?.cwd,userConfigDir:n?.userConfigDir,userConfigPath:n?.userConfigPath});try{if(g(r.projectConfigTarget)!==null){if(a2(r.projectConfigTarget).errors.length===0)return{configSource:t,configValid:!0};return{configSource:t,configValid:!1}}}catch(a){if(a instanceof Z)return{configSource:t,configValid:!1};throw a}try{if(g(r.userConfigTarget)!==null){let a=a2(r.userConfigTarget);return{configSource:e,configValid:a.errors.length===0}}return{configSource:null,configValid:!0}}catch(a){if(a instanceof Z)return{configSource:e,configValid:!1};throw a}}function vd(n){let t=ud(n?.cwd??process.cwd()),e=n?.policySnapshot??W({cwd:t,userConfigDir:n?.userConfigDir}),r=d2(e.policy);return{cwd:t,effectiveCwd:t,policySnapshot:e,environment:_r(),protectedGitMetadata:Nr(t),effectiveCapabilities:r.capabilities,strict:n?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function bd(n,t){let e=t.cwd??process.cwd(),r=Er(M2("",{command:n},{kind:"command",shell:"posix"},{executionCwd:e,configCwd:e},n)),a=r1(r);if(a)return{reason:e1,target:a.target,ruleId:"policy-protection",ruleModule:"policy-protection",ruleFunction:"findPolicyConfigMutationTarget"};let l=Ir(r,t.protectedGitMetadata);if(l)return{reason:Pr,target:l.target,ruleId:"git-metadata-protection",ruleModule:"git-metadata-protection",ruleFunction:"findGitMetadataMutationTarget"};let d=t.policySnapshot.policy,s=d.secretProtection.enabled===!1?null:l1(r,d.secretProtection,{strict:t.strict});if(s)return{reason:a1,target:s.target,ruleId:s.ruleId,ruleModule:"secret-protection",ruleFunction:"findSensitiveTarget"};return null}function fd(n,t){let e=t.policySnapshot.policy,r=on({...e,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...e.destructiveCommandRuleOverrides,...Object.fromEntries(un.flatMap((a)=>a.activationCapability?[[a.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return t1(n,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function hd(n){if(!n)return;return{id:A(n.id),...n.rulebook?{rulebook:{name:A(n.rulebook.name),version:A(n.rulebook.version)}}:{},...n.source?{source:A(n.source)}:{},...n.override?{override:{type:"reason",reason:A(n.override.reason)}}:{}}}function yd(n){let t=n.events.flatMap((r)=>r.kind==="step"&&r.scope==="global"?[r.step]:[]),e=new Map;for(let r of n.events){if(r.kind!=="step"||r.scope!=="segment")continue;let a=e.get(r.segmentIndex)??{index:r.segmentIndex,steps:[]};a.steps.push(r.step),e.set(r.segmentIndex,a)}return{steps:t,segments:[...e.values()]}}function wd(n,t){let e=n?.replace(/^custom\./,"");if(!e||!t.policy.rules.some((r)=>r.name===e))return;return t.ruleMetadata[e]??Object.freeze({id:e})}function kd(n){let t=G2(),e=F({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"]}},n);if(r2(e.errors))return null;if(e.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(e.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let r=e.values.limit===void 0?20:d1(e.values.limit);if(r===null)return console.error("--limit must be a positive number"),null;let a=e.values.since===void 0?Math.min(30,t):d1(e.values.since);if(a===null||a>t)return console.error(`--since must be a positive number of days no greater than ${t}`),null;let l={limit:r,limitExplicit:e.values.limit!==void 0,since:a,sinceExplicit:e.values.since!==void 0,all:e.flags.all,json:e.flags.json,suspect:e.flags.suspect,pruneLegacy:e.flags.pruneLegacy,dryRun:e.flags.dryRun,id:e.values.id,agent:e.values.agent,rule:e.values.rule,session:e.values.session,project:e.values.project===void 0?void 0:md(e.values.project)};if(l.id&&(l.agent!==void 0||l.rule!==void 0||l.session!==void 0||l.project!==void 0||l.suspect||l.sinceExplicit||l.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(l.pruneLegacy&&(l.id!==void 0||l.agent!==void 0||l.rule!==void 0||l.session!==void 0||l.project!==void 0||l.suspect||l.all||l.sinceExplicit||l.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(l.dryRun&&!l.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return l}async function i1(n,t={}){let e=kd(n);if(!e)return 1;let r=t.logsDir??s2();if(e.pruneLegacy)return qd(r,e.json,e.dryRun);if(!r)return console.log(e.json?"[]":e.id?`No retained audit log entry found for id ${z(e.id)}.`:"No audit log entries found."),0;$2(r);let a={count:0},l=u2(r,a).flatMap((L)=>dn(L,a).map((u)=>({entry:u,file:L})));if(a.count>0)console.error(`warning: ${a.count} audit log ${a.count===1?"source":"sources"} could not be read; these results are incomplete`);if(e.id)return Bd(l,e,t.timeZone);let d=Date.now()-e.since*24*60*60*1000,s=l.filter((L)=>Jd(L,e,r,d)),c=e.suspect?Bt(s.map((L)=>L.entry)):null,i=(c?s.filter((L)=>c.has(L.entry)):s).sort((L,u)=>Date.parse(u.entry.ts)-Date.parse(L.entry.ts)).slice(0,e.limit);if(e.json)return console.log(JSON.stringify(i.map((L)=>L.entry),null,2)),0;if(i.length===0)return console.log("No audit log entries found."),0;for(let L of i)console.log(Xd(L.entry,t.timeZone));return 0}function qd(n,t,e){let r=n?Fd(n).map((s)=>Dd(n,s)):[];if(e)return jd(r,t);let a=[],l=0,d=0;for(let s of r){let c=s1(s,{throwIfNoEntry:!1})?.size??0,i=zd(s);if(i){a.push(`${c1(s)}: ${i}`);continue}l++,d+=c}if(t)return console.log(JSON.stringify({removedFiles:l,removedBytes:d,failedFiles:a.length})),a.length===0?0:1;console.log(l===0&&a.length===0?"No legacy audit log files found.":`Removed ${l} legacy audit log ${l===1?"file":"files"} (${L1(d)}).`);for(let s of a)console.error(`Could not remove ${z(s)}`);if(console.log("Nested v2 audit logs were not changed."),l>0)console.log("This deletion cannot be undone.");return a.length===0?0:1}function jd(n,t){let e=n.reduce((r,a)=>r+(s1(a,{throwIfNoEntry:!1})?.size??0),0);if(t)return console.log(JSON.stringify({dryRun:!0,files:n.length,bytes:e})),0;if(console.log(n.length===0?"No legacy audit log files found.":`Would remove ${n.length} legacy audit log ${n.length===1?"file":"files"} (${L1(e)}).`),console.log("Nested v2 audit logs are not included."),n.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Fd(n){try{return xd(n,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function zd(n){try{return $d(n),null}catch(t){return t instanceof Error?t.message:String(t)}}function L1(n){let t=["B","KiB","MiB","GiB"],e=Math.min(Math.floor(Math.log2(Math.max(n,1))/10),t.length-1);return`${Math.round(n/1024**e*10)/10} ${t[e]}`}function Bd(n,t,e){let r=n.filter((l)=>l.entry.id===t.id);if(r.length>1)return console.error(`Multiple audit log entries found for id ${z(t.id??"")}.`),1;if(t.json)return console.log(JSON.stringify(r.map((l)=>l.entry),null,2)),0;let a=r[0];if(!a)return console.log(`No retained audit log entry found for id ${z(t.id??"")}.`),0;return console.log(Yd(a.entry,e)),0}function Jd(n,t,e,r){if(!t.all&&n.entry.decision==="allow")return!1;if(Date.parse(n.entry.ts)<r)return!1;if(t.agent!==void 0&&n.entry.agent!==t.agent)return!1;if(t.rule!==void 0&&n.entry.ruleId!==t.rule)return!1;if(t.session!==void 0&&!Zd(n,e,t.session))return!1;if(t.project!==void 0&&!Qd(n.entry.cwd,t.project))return!1;return!0}function Zd(n,t,e){if(n.entry.sessionId===e)return!0;return gd(n.file)===t&&c1(n.file,".jsonl")===e}function Qd(n,t){if(!n)return!1;return n===t||n.startsWith(`${t}/`)}function Xd(n,t){let e=z(n.id??"-"),r=z(n.decision??"deny"),a=n.cwd?` [${z(n.cwd)}]`:"",l=n.segment||n.command,d=l===n.command?"":"↳ ",s=l.length>50?`${l.slice(0,50)}…`:l;return`${e.padEnd(16)} ${z(p1(n.ts,t))} ${r.padEnd(5)} ${z(n.agent??"-").padEnd(15)} ${z(n.ruleId??"-").padEnd(20)} ${d}${z(s)}${a}`}function Yd(n,t){let e=(a)=>z(a===void 0||a===null||a===""?"-":a),r=n.shape?`${n.agent??"-"} (shape: ${n.shape})`:n.agent??"-";return[`id: ${e(n.id)}`,`ts: ${e(p1(n.ts,t))}`,`decision: ${e(n.decision)}`,`agent: ${e(r)}`,`level: ${e(n.level)}`,`tool: ${e(n.toolName)}`,`rule: ${e(n.ruleId)}`,`intent: ${e(n.intent)}`,`stage: ${e(n.failureStage)}`,`error: ${e(n.errorCode)}`,`session: ${e(n.sessionId)}`,`cwd: ${e(n.cwd)}`,`version: ${e(n.v)}`,`truncated: ${e(n.truncated===!0?"yes":void 0)}`,`reason: ${e(n.reason)}`,`command: ${e(n.command)}`,`segment: ${e(n.segment)}`].join(`
|
|
5
|
-
`)}function p1(n,t){let e=new Date(n);if(Number.isNaN(e.getTime()))return n;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(e)}function d1(n){let t=Number(n);return Number.isFinite(t)&&t>0?t:null}var u1={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 o1={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 v1={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 D1,relative as Ud}from"node:path";var Sd=8388608;function Hd(n,t){console.log(JSON.stringify(n(f1(t))))}async function Ad(n){let t;try{t=(await le(process.stdin)).trim()}catch{n({reason:"Failed to parse hook input JSON."});return}if(!t){n({reason:"Missing hook input JSON."});return}return de(t,n,"Failed to parse hook input JSON.")}async function le(n){let t=[],e=0;for await(let r of n){let a=typeof r==="string"?Buffer.from(r,"utf-8"):Buffer.from(r.buffer,r.byteOffset,r.byteLength);if(e+=a.byteLength,e>Sd)throw Wd(n),Error("hook input byte limit exceeded");t.push(a)}return Buffer.concat(t,e).toString("utf-8")}function Wd(n){let t=n.destroy??n.cancel;if(!t)return;try{Promise.resolve(t.call(n)).catch(()=>{})}catch{}}function de(n,t,e){try{return JSON.parse(n)}catch{t({reason:e});return}}function X(n,t){let e=t.get(n);return e?{kind:"command",shell:e}:{kind:y1(n)}}function I(n,t,e,r){let a=n===void 0?process.cwd():n,l=typeof a==="string"&&a.trim()!==""?c2([a]):void 0;if(l)return{configCwd:l,executionCwd:l};return H(r,t,e,Vd(a)),null}function H(n,t,e,r){let a;try{a=ae(t)}catch(l){if(!(l instanceof C2))throw l}n(Rn({command:a,segment:r,toolName:e}))}async function Rd(n){let t=await Ad(n.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){H(n.outputDeny);return}if(!n.isSupported(t))return;let e=n.getAgent?.(t)??n.agent,r=n.agent===e?void 0:n.agent,a=Cd(t),l=(p,f)=>{b1(p,()=>n.getSessionId(t),{agent:e,shape:r,toolName:f,cwd:a}),n.outputDeny(p)},d=n.getToolName(t);if(typeof d!=="string"||d.trim()===""){H((p)=>l(p),Gd(t));return}let s=d,c=(p)=>l(p,s),i;try{i=n.getToolInput(t,s,c)}catch(p){if(!(p instanceof C2))throw p;H(c,void 0,s);return}if(!i.ok)return;let L=n.getContext(t,i.input,s,c);if(!L)return;let u;try{u=ae(i.input)}catch(p){if(!(p instanceof C2))throw p;H(c,void 0,s);return}let v=M2(s,i.input,i.route,L,u??null);try{let p=Kn(v,{guard:{auditAllowed:w1(),dependencies:n.guardDependencies},audit:{agent:e,shape:r,getSessionId:()=>n.getSessionId(t)}}),f=re(p,{includeEvidence:!0,toolName:p.stage==="command-analysis"?void 0:s});if(f){n.outputDeny(f);return}n.outputAllow?.()}catch(p){if(!(p instanceof x1))throw p;Kd(p);let f=re(p.evaluation,{includeEvidence:!0,toolName:p.evaluation.stage==="command-analysis"?void 0:s});if(f)n.outputDeny(f);return}}function Kd(n){if(!vn(m.debug))return;console.error(`CC Safety Net debug: ${Md(n.stage)}: ${h1(n.cause)}`)}function Md(n){if(n==="policy-protection")return"hook policy protection failed";if(n==="config-load")return"hook config loading failed";if(n==="secret-protection")return"hook secret protection failed";return"hook analysis failed"}function Vd(n){return typeof n==="string"?n:void 0}function Gd(n){if(!n||typeof n!=="object"||Array.isArray(n))return;if(Object.hasOwn(n,"tool_input"))return n.tool_input;let t=n.toolCall;if(t&&typeof t==="object"&&!Array.isArray(t))return t.args;return}function Cd(n){if(!n||typeof n!=="object"||Array.isArray(n))return null;let t=n.cwd;if(typeof t==="string")return t;let e=n.toolCall;if(!e||typeof e!=="object"||Array.isArray(e))return null;let r=e.args;if(!r||typeof r!=="object"||Array.isArray(r))return null;let a=r.Cwd;return typeof a==="string"?a:null}async function Y(n){let t=(a)=>Hd(n.createDenyOutput,a),e=n.createAllowOutput;await Rd({...n,outputDeny:t,outputAllow:e?()=>console.log(JSON.stringify(e())):void 0})}var Od=new Map([["run_command","auto"]]),Td=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function m1(n){return X(n,Od)}async function k1(){await Y({agent:"antigravity-cli",createDenyOutput:(n)=>({decision:"deny",reason:n}),isSupported:()=>!0,getToolName:(n)=>n.toolCall?.name,getToolInput:(n,t)=>({ok:!0,input:Nd(n.toolCall?.args,t),route:m1(t)}),getContext:_d,getSessionId:(n)=>n.conversationId})}function _d(n,t,e,r){let l=Id(n).flatMap((i)=>{let L=c2([i]);return L?[L]:[]});if(!l[0])return D2(r,t,e),null;if(e!=="run_command"){let i;try{i=Ed(t,e,l)}catch(L){if(L instanceof C2)return D2(r,void 0,e),null;if(!(L instanceof Mn))throw L;return D2(r,t,e),null}if(!i)return D2(r,t,e),null;return{configCwd:i,executionCwd:i,policyConfigCwds:l}}let d=n.toolCall?.args;if(!d||!Object.hasOwn(d,"Cwd"))return{configCwd:l[0],executionCwd:l[0],policyConfigCwds:l};let s=d.Cwd;if(typeof s!=="string"||s.trim()==="")return D2(r,t,e),null;let c=wn(s,l);if(c){let i=q1(c,l);if(!i)return D2(r,t,e,s),null;return{configCwd:i,executionCwd:c,policyConfigCwds:l}}return D2(r,t,e,s),null}function Ed(n,t,e){let r=m1(t),a=[...$1(n,Td),...r.kind==="patch"?g1(n):[]].filter(D1),l=Vn(),d=new Set(a.flatMap((s)=>{let c=q1(hn(s,yn,l),e);return c?[c]:[]}));if(d.size>1)return null;return[...d][0]??e[0]??null}function q1(n,t){return t.filter((e)=>Pd(n,e)).reduce((e,r)=>r.length>e.length?r:e,"")||null}function Pd(n,t){let e=Ud(t,n);return e===""||!e.startsWith("..")&&!D1(e)}function D2(n,t,e,r){let a=t&&typeof t==="object"?t.command:void 0;n(Rn({command:typeof a==="string"?a:void 0,segment:r,toolName:e}))}function Id(n){if(n.workspacePaths===void 0)return[process.cwd()];let t=Array.isArray(n.workspacePaths)?n.workspacePaths.filter((e)=>typeof e==="string"&&e.trim()!==""):[];return c2(t)?t:[]}function Nd(n,t){if(!n)return;if(t!=="run_command")return n;return{...n,command:typeof n.CommandLine==="string"&&n.CommandLine!==""?n.CommandLine:void 0}}var U2=[{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",installLabel:"Antigravity CLI",helpTarget:"Antigravity CLI 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",installLabel:"Claude Code",helpTarget:"Claude Code plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,install:{order:4,flag:"--codex",installLabel:"Codex",helpTarget:"Codex 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",installLabel:"GitHub Copilot CLI",helpTarget:"GitHub Copilot CLI 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",installLabel:"Gemini CLI",helpTarget:"Gemini CLI extension",probeCommand:["gemini","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:8,runtime:{order:6,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--hermes-agent",installLabel:"Hermes Agent",helpTarget:"Hermes Agent plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:9,runtime:{order:7,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--kimi-code",installLabel:"Kimi Code",helpTarget:"Kimi Code hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:10,install:{order:10,flag:"--openclaw",installLabel:"OpenClaw",helpTarget:"OpenClaw plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:11,install:{order:11,flag:"--opencode",installLabel:"OpenCode",helpTarget:"OpenCode plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:12,install:{order:12,flag:"--pi",installLabel:"Pi",helpTarget:"Pi 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",installLabel:"Cursor",helpTarget:"Cursor hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",installLabel:"Amp Code",helpTarget:"Amp Code plugin",probeCommand:["amp","--version"]}}],j1=U2.slice().sort((n,t)=>n.doctorOrder-t.doctorOrder).map((n)=>n.id),F1=U2.filter((n)=>("runtime"in n)).slice().sort((n,t)=>n.runtime.order-t.runtime.order).map((n)=>({id:n.id,displayName:"displayName"in n.runtime?n.runtime.displayName:n.displayName,flags:n.runtime.flags,legacyFlags:"legacyFlags"in n.runtime?n.runtime.legacyFlags:[],description:n.runtime.description,legacyTopLevelFlags:n.runtime.legacyTopLevelFlags})),i2=U2.slice().sort((n,t)=>n.install.order-t.install.order).map((n)=>({id:n.id,...n.install})).map(({order:n,...t})=>t),B6=Object.fromEntries(U2.map((n)=>[n.id,n.displayName]));function v2(n){return U2.find((t)=>t.id===n)?.displayName??n}function b2(n){return U2.find((t)=>t.id===n)?.install.installLabel??n}import{homedir as ns}from"node:os";import{isAbsolute as z1,join as se}from"node:path";function J1(n){if(n!==void 0&&n!==null&&!z1(n))return"unknown";try{let t=Vn(),e=n?hn(n,yn,t):void 0,r=process.env.HOME||ns(),a=[["codex",process.env.CODEX_HOME||se(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||se(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||se(r,".claude")]],l=e?a.flatMap(([d,s])=>{if(!z1(s))return[];return B1(e,hn(s,yn,t))?[d]:[]}):[];if(l.length===1)return l[0]??"unknown";if(l.length>1)return"unknown"}catch(t){if(t instanceof Mn)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var ce="PreToolUse",Z1="BeforeTool",Q1="pre_tool_call",ie="PreToolUse";var ts=new Map([["Bash","posix"],["PowerShell","powershell"]]);function es(n){return X(n,ts)}async function X1(){await Y({agent:"claude-code",getAgent:(n)=>J1(n.transcript_path),createDenyOutput:(n)=>({hookSpecificOutput:{hookEventName:ce,permissionDecision:"deny",permissionDecisionReason:n}}),isSupported:(n)=>n.hook_event_name===ce,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:es(t)}),getContext:(n,t,e,r)=>I(n.cwd,t,e,r),getSessionId:(n)=>n.session_id})}var rs=new Map([["bash","auto"],["Bash","auto"]]);function as(n){return X(n,rs)}async function Y1(){await Y({agent:"copilot-cli",createDenyOutput:(n)=>({permissionDecision:"deny",permissionDecisionReason:n}),isSupported:()=>!0,getToolName:(n)=>n.toolName,getToolInput:(n,t,e)=>{if(typeof n.toolArgs!=="string")return e({reason:"Failed to parse toolArgs JSON."}),{ok:!1};let r=de(n.toolArgs,e,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:as(t)}},getContext:(n,t,e,r)=>I(n.cwd,t,e,r),getSessionId:(n)=>typeof n.sessionId==="string"&&n.sessionId.trim()?n.sessionId:void 0})}var ls=new Map([["Shell","auto"]]);function ds(n){return X(n,ls)}async function S1(){await Y({agent:"cursor",createDenyOutput:(n)=>({permission:"deny",user_message:n,agent_message:n}),createAllowOutput:()=>({permission:"allow"}),isSupported:()=>!0,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:ds(t)}),getContext:ss,getSessionId:(n)=>n.conversation_id})}function ss(n,t,e,r){let a=cs(n);if(!a[0])return H(r,t,e),null;let l=wn(Ls(n.cwd),a);if(!l)return H(r,t,e,typeof n.cwd==="string"?n.cwd:void 0),null;if(t===null||typeof t!=="object"||Array.isArray(t))return{configCwd:l,executionCwd:l,policyConfigCwds:a};if(!Object.hasOwn(t,"working_directory"))return{configCwd:l,executionCwd:l,policyConfigCwds:a};let d=t.working_directory;if(typeof d!=="string"||d.trim()==="")return H(r,t,e),null;let s=wn(d,a);if(!s)return H(r,t,e,d),null;return{configCwd:l,executionCwd:s,policyConfigCwds:a}}function cs(n){return is(n).flatMap((t)=>{let e=c2([t]);return e?[e]:[]})}function is(n){if(n.workspace_roots===void 0)return typeof n.cwd==="string"&&n.cwd.trim()!==""?[n.cwd]:[];if(!Array.isArray(n.workspace_roots))return[];return n.workspace_roots.filter((t)=>typeof t==="string"&&t.trim()!=="")}function Ls(n){return typeof n==="string"&&n.trim()!==""?n:"."}var ps=new Map([["run_shell_command","auto"]]);function us(n){return X(n,ps)}async function H1(){await Y({agent:"gemini-cli",createDenyOutput:(n)=>({decision:"deny",reason:n,systemMessage:n}),isSupported:(n)=>n.hook_event_name===Z1,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:us(t)}),getContext:(n,t,e,r)=>I(n.cwd,t,e,r),getSessionId:(n)=>n.session_id})}import{resolve as os}from"node:path";var vs=new Map([["terminal","posix"]]);async function A1(){await Y({agent:"hermes-agent",createDenyOutput:(n)=>({action:"block",message:n}),isSupported:(n)=>n.hook_event_name===Q1,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:X(t,vs)}),getContext:bs,getSessionId:(n)=>n.session_id})}function bs(n,t,e,r){let a=I(n.cwd,t,e,r);if(!a)return null;if(!t||typeof t!=="object"||Array.isArray(t))return a;if(!Object.hasOwn(t,"workdir"))return a;let l=t.workdir;if(typeof l!=="string"||l.trim()==="")return H(r,t,e),null;let d=c2([os(a.configCwd,l)]);if(!d)return H(r,t,e,l),null;return{...a,executionCwd:d}}var fs=new Map([["Bash","posix"]]);function hs(n){return X(n,fs)}async function W1(){await Y({agent:"kimi-code",createDenyOutput:(n)=>({hookSpecificOutput:{hookEventName:ie,permissionDecision:"deny",permissionDecisionReason:n}}),isSupported:(n)=>n.hook_event_name===ie,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:hs(t)}),getContext:(n,t,e,r)=>I(n.cwd,t,e,r),getSessionId:(n)=>n.session_id})}var ys={"antigravity-cli":k1,"claude-code":X1,"copilot-cli":Y1,cursor:S1,"gemini-cli":H1,"hermes-agent":A1,"kimi-code":W1},O2=F1.map((n)=>({...n,run:ys[n.id]}));function R1(n){let t=F({label:"hook",booleans:Object.fromEntries(O2.map((r)=>[r.id,[...r.flags,...r.legacyFlags]]))},n);if(t.errors.length>0)return;let e=O2.filter((r)=>t.flags[r.id]);return e.length===1?e[0]:void 0}function K1(n){return O2.find((t)=>t.legacyTopLevelFlags.some((e)=>e===n))}var ws=O2.map((n)=>({flags:n.flags.join(", "),description:n.description})),xs=O2.flatMap((n)=>n.flags.map((t)=>`cc-safety-net hook ${t}`)),M1={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...ws,{flags:"-h, --help",description:"Show this help"}],examples:xs};var V1={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...i2.map((n)=>({flags:n.flag,description:`Install ${n.helpTarget}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...i2.map((n)=>`cc-safety-net install ${n.flag}`)]},G1={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...i2.map((n)=>({flags:n.flag,description:`Uninstall ${n.helpTarget}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...i2.map((n)=>`cc-safety-net uninstall ${n.flag}`)]},C1={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 U1={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 T2={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add <source>",description:"Add a rulebook source and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Refresh rulebook lock/cache state"},{usage:"sync",description:"Sync configured rulebooks"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--check",description:"Check without changing lock/cache state"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk","cc-safety-net rule add project-rules","cc-safety-net rule sync","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var O1={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 T1={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 _1=[O1,u1,U1,o1,T2,V1,C1,G1,M1,v1,T1];function $s(n){return n.aliases??[]}function gs(n){return!n.hidden}function Gn(n){let t=n.toLowerCase();return _1.find((e)=>e.name.toLowerCase()===t||$s(e).some((r)=>r.toLowerCase()===t))}function E1(){return _1.filter(gs)}import{readFileSync as Ds}from"node:fs";import{basename as ms}from"node:path";function Cn(n=7,t=s2()){let e=Date.now()-n*24*60*60*1000,r=[],a=new Set,l=0,d,s,c,i;if(t)$2(t);let L={count:0},u=t?u2(t,L):[];for(let p of u)try{let o=Ds(p,"utf-8").trim().split(`
|
|
6
|
-
`).filter(Boolean);for(let h of
|
|
7
|
-
`)}function
|
|
8
|
-
`)}function
|
|
9
|
-
`)}function
|
|
10
|
-
`)}function
|
|
11
|
-
`)}function
|
|
12
|
-
`)}function
|
|
13
|
-
`);for(let
|
|
14
|
-
`)}function
|
|
15
|
-
`)}function
|
|
16
|
-
`);if(n.error)return t.push(
|
|
17
|
-
`);if(n.updateAvailable)return t.push(
|
|
18
|
-
`);return t.push(
|
|
19
|
-
`)}function
|
|
20
|
-
`)}function
|
|
21
|
-
No findings from inspected doctor facts.`);let t={error:n.findings.filter((l)=>l.severity==="error").length,warning:n.findings.filter((l)=>l.severity==="warning").length,info:n.findings.filter((l)=>l.severity==="info").length},
|
|
22
|
-
${n.findings.length} ${
|
|
23
|
-
`)[0]?.trim()||null}async function
|
|
24
|
-
`).map((
|
|
25
|
-
`.repeat(
|
|
26
|
-
\x1B[0m\x1B[?25h`)}}var
|
|
27
|
-
`);function
|
|
28
|
-
`).map((
|
|
29
|
-
`).find((
|
|
30
|
-
`)
|
|
31
|
-
`)}function
|
|
32
|
-
`),{path:t,alreadyInstalled:!1};let
|
|
2
|
+
import{$ as Lr,$a as Ct,A as un,Aa as Ye,B as c3,Ba as Se,C as N,Ca as dr,D as T,Da as He,E as Pt,Ea as Re,F as Kt,Fa as _,G as An,Ga as Ut,H as Vt,Ha as It,I as O2,Ia as Nt,J as D2,Ja as E,K as nr,Ka as Z3,L as L2,La as fn,M as w1,Ma as Q3,N as cr,Na as xe,O as Kn,Oa as X3,P as x1,Pa as Y3,Q as $1,Qa as S3,R as k2,Ra as ft,S as Mn,Sa as H3,T as hn,Ta as R3,U as wn,Ua as s1,V as Ne,Va as d1,W as vn,Wa as c1,X as q2,Xa as L1,Y as tr,Ya as u3,Z as i2,Za as Te,_ as m1,_a as _e,aa as k1,ab as Ee,b as ke,ba as q1,bb as Pe,c as qe,ca as rr,cb as y2,d as A,da as n1,db as g2,e as je,ea as Je,eb as d2,f as Ht,fa as t1,fb as Ie,g as X,ga as r1,gb as K,h as D,ha as e1,hb as yn,i as cn,ia as er,ib as on,j as m,ja as Ze,jb as D1,k as m2,ka as k,kb as z2,l as Ve,la as ar,lb as p2,m as K2,ma as g1,mb as Q1,n as Ln,na as c2,nb as Vn,o as y3,oa as bn,p as At,pa as lr,q as Me,qa as sr,r as pn,ra as a1,s as Ge,sa as l1,t as Et,ta as Qe,u as Ue,ua as U2,v as Ce,va as Mt,w as P,wa as Gt,x as I,xa as Oe,y as M2,ya as W2,z as G2,za as J3}from"../chunks/index-4pw6zr4t.js";var G3=["-h","--help"];function B(n,t){let r=Object.entries(n.booleans??{}),e=Object.entries(n.values??{}),a=Object.fromEntries(r.map(([i])=>[i,!1])),l={},s=[],d=[],c=!1,L=-1;for(let[i,u]of t.entries()){if(i<=L)continue;if(u==="--"){s.push(...t.slice(i+1));break}if(G3.includes(u)){c=!0;continue}let o=r.find(([,f])=>f.includes(u));if(o){a[o[0]]=!0;continue}let p=e.find(([,f])=>f.includes(u));if(p){let f=t[i+1];if(f===void 0||f.startsWith("-")){d.push(`${u} requires a value`);continue}l[p[0]]=f,L=i+1;continue}if(u.startsWith("-")){d.push(`Unknown option for ${n.label}: ${u}`);continue}if(n.positionals==="tail"){s.push(...t.slice(i));break}s.push(u)}if(n.positionals!=="list"&&n.positionals!=="tail")d.push(...s.map((i)=>`Unexpected argument for ${n.label}: ${i}`));return{flags:a,values:l,positionals:s,help:c,errors:d}}function l2(n){for(let t of n)console.error(t);return n.length>0}import{readdirSync as Fs,statSync as p1,unlinkSync as Bs}from"node:fs";import{basename as u1,dirname as Js,join as Zs,resolve as Qs}from"node:path";function J(n){return Array.from(n,(t)=>{let r=t.charCodeAt(0);if(r<=31||r>=127&&r<=159)return`\\x${r.toString(16).padStart(2,"0")}`;return t}).join("")}var Qt=(n)=>{let t=Date.now()-new Date(n).getTime();if(!Number.isFinite(t))return"";let r=Math.floor(t/60000),e=Math.floor(r/60),a=Math.floor(e/24);if(a>0)return`${a}d ago`;if(e>0)return`${e}h ago`;if(r>0)return`${r}m ago`;return"just now"},S2=(n)=>{let t=(n??"").trim().split(/\s+/).filter((a)=>a&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(a)),r=t[0]?.split("/").pop();if(!r)return null;let e=t[1];return e&&/^[a-z][a-z0-9-]*$/.test(e)?`${r} ${e}`:r};import{existsSync as U3,readdirSync as C3,readFileSync as O3}from"node:fs";import{join as T3}from"node:path";function f2(n,t){try{return C3(n,{withFileTypes:!0,encoding:"utf8"}).flatMap((r)=>{let e=T3(n,r.name);if(r.isDirectory())return f2(e,t);if(r.name.endsWith(".jsonl"))return[e];return[]})}catch{if(t&&U3(n))t.count++;return[]}}function Xt(n){let t=(a)=>`${a.sessionId}
|
|
3
|
+
${S2(a.segment||a.command)}`,r=n.filter((a)=>a.decision!=="allow"),e=r.filter((a)=>a.sessionId).reduce((a,l)=>a.set(t(l),(a.get(t(l))??0)+1),new Map);return new Set(r.filter((a)=>a.failureStage||(e.get(t(a))??0)>=2))}function dn(n,t){try{return O3(n,"utf-8").split(`
|
|
4
|
+
`).filter(Boolean).flatMap((r)=>{try{return[JSON.parse(r)]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as $s}from"node:path";var _3=["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 ze(n){let t=0,r={allocateSegment(){return t++},getNextSegmentIndex(){return t},recordGlobal(e){n.record({kind:"step",scope:"global",step:e})},recordSegment(e,a=r.currentSegmentIndex){if(a===void 0)return;n.record({kind:"step",scope:"segment",segmentIndex:a,step:e})}};return r}function Fe(n={}){let t=[],r=n.maxEvents??512,e={maxTextLength:n.maxTextLength??2048,maxListLength:n.maxListLength??128,maxObjectProperties:n.maxObjectProperties??n.maxListLength??128,maxDepth:n.maxDepth??16},a=0,l,s=new Set;return{record(d){if(l)return;try{if(!d||t.length>=r){a++;return}t.push(St(E3(d,e,s)))}catch{a++}},finish(d){if(l)return l;try{l=St({events:Object.freeze(t),droppedEvents:a,terminal:P3(d,e,s)})}catch{a++,l=Object.freeze({events:Object.freeze(t),droppedEvents:a,terminal:Object.freeze({result:"blocked",reason:"trace unavailable".slice(0,e.maxTextLength),segment:"trace unavailable".slice(0,e.maxTextLength)})})}return l}}}function E3(n,t,r){if(n.kind!=="step")throw TypeError("invalid trace event");let{scope:e,step:a}=n;Hn(a,r,t);let l=H2(a,t,r);if(e==="global")return{kind:"step",scope:"global",step:l};if(e!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:n.segmentIndex,step:l}}function P3(n,t,r){let e=n.result;if(e==="allowed")return Object.freeze({result:"allowed"});if(e!=="blocked")throw TypeError("invalid trace terminal");let a=n.ruleId;return Object.freeze({result:"blocked",reason:H2(n.reason,t,r),segment:H2(n.segment,t,r),...a?{ruleId:H2(a,t,r)}:{}})}function Hn(n,t,r,e=0,a=new WeakSet){if(typeof n==="string"){let d=n.slice(0,r.maxTextLength);if(!Ht(d))return;for(let c of je(d))for(let L of c.match(/[^\s"'()$]+/g)??[])t.add(Be(L));return}if(!n||typeof n!=="object"||e>=r.maxDepth||a.has(n))return;if(a.add(n),Array.isArray(n)){let d=Math.min(n.length,r.maxListLength);for(let c=0;c<d;c++)Hn(n[c],t,r,e+1,a);return}let l=0,s=new Set;for(let d in n){if(!Object.hasOwn(n,d))continue;if(l>=r.maxObjectProperties)break;l++,Hn(d,t,r);let c=Yt(d,r,t);if(s.has(c))continue;s.add(c),Hn(n[d],t,r,e+1,a)}}function H2(n,t,r,e=0,a=new WeakSet){if(typeof n==="string")return Yt(n,t,r);if(!n||typeof n!=="object")return n;if(e>=t.maxDepth)return;if(a.has(n))return;if(a.add(n),Array.isArray(n)){let d=[],c=Math.min(n.length,t.maxListLength);for(let L=0;L<c;L++)d.push(H2(n[L],t,r,e+1,a));return d}let l={},s=0;for(let d in n){if(!Object.hasOwn(n,d))continue;if(s>=t.maxObjectProperties)break;s++;let c=Yt(d,t,r);if(Object.hasOwn(l,c))continue;Object.defineProperty(l,c,{value:H2(n[d],t,r,e+1,a),enumerable:!0,configurable:!0,writable:!0})}return l}function Yt(n,t,r){let e=n.slice(0,t.maxTextLength),a=Ht(e)?qe(e):e,l=r.size>0?N3(a,r):a;return(I3(l)?ke(l):l).slice(0,t.maxTextLength)}function I3(n){return n.includes("PRIVATE KEY")||n.includes("://")||n.includes("eyJ")||n.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(n)||n.length>=14&&_3.some((t)=>n.includes(t))||n.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(n)}function N3(n,t){return n.replace(/[^\s"'()$]+/g,(r)=>t.has(Be(r))?"<redacted>":r)}function Be(n){let t=2166136261,r=2166136261;for(let e=0;e<n.length;e++)t=Math.imul(t^n.charCodeAt(e),16777619),r=Math.imul(r^n.charCodeAt(n.length-e-1),16777619);return`${t>>>0}:${r>>>0}:${n.length}`}function St(n){if(n&&typeof n==="object"&&!Object.isFrozen(n)){for(let t of Object.values(n))St(t);Object.freeze(n)}return n}function Xe(n,t,r){let e=r??Je(),a=e.getCommandProgram(n,t.shell??"auto"),l=Fe(),s=ze(l),d=a.dialect==="powershell"?e.getCommandProgram(n,"posix"):a,c=Ze(d);s.recordGlobal({type:"parse",input:n,segments:c.map((u)=>[...u])});let L=Qe(n,{...t,analyzePartialProgram:!0,trace:s},a,e),i=s.getNextSegmentIndex();if(L&&i>0&&i<c.length)s.recordSegment({type:"segment-skipped",index:i,reason:"prior-segment-blocked"},i);return Object.freeze({decision:L,trace:l.finish(L?{result:"blocked",reason:L.reason,segment:L.evidence.find((u)=>u.kind==="command")?.segment??n,...L.ruleId?{ruleId:L.ruleId}:{}}:{result:"allowed"}),program:a})}import{resolve as ns}from"node:path";function Rt(n){let t=Ye().safeParse(n);return{errors:t.success?[]:He(t.error.issues),ruleNames:new Set(Se(n).map((r)=>r.toLowerCase()))}}function Wt(n){let t=We(n);if(!t.ok)return t.result;return Rt(t.parsed)}function We(n){let t=[],r=new Set;try{let e=typeof n==="string"?cn(n):n,a=m(e);if(a===null)return t.push(`File not found: ${e.path}`),{ok:!1,result:{errors:t,ruleNames:r}};if(!a.trim())return t.push("Config file is empty"),{ok:!1,result:{errors:t,ruleNames:r}};return{ok:!0,parsed:JSON.parse(a)}}catch(e){if(e instanceof X)return t.push(e.message),{ok:!1,result:{errors:t,ruleNames:r}};let a=e instanceof Error?e.message:String(e);return t.push(e instanceof SyntaxError?"Invalid JSON":a),{ok:!1,result:{errors:t,ruleNames:r}}}}function Ae(n){return ns(n??process.cwd(),".safety-net.json")}function s2(n){let t=We(n);if(!t.ok)return t.result;let r=Re(t.parsed);return{errors:r.errors,ruleNames:r.sources}}import{isAbsolute as ts,join as Rn,relative as rs,resolve as Ke,sep as es}from"node:path";async function V2(n={}){let t=Tt(n);return as(t,await Wn(t,W2()))}function as(n,t){if(!t.ok)return t;let r=T(n),e=[...new Set(d2(r.configPath,r.lockPath,n,r.filesystemScope))];if(e.length===0)return t;return{ok:!1,errors:e,warnings:t.warnings,entries:t.entries}}async function Wn(n,t,r,e={}){let a=null,l=!1;try{let s=T(n),d=Ut(s.configTarget);if(!d.ok)return d.result;let c=d.config;if(n.check)return is(c,s,n);a={target:s.lockTarget,content:m(s.lockTarget)};let L=Ct(s.lockTarget);if(L.errors.some((h)=>h.startsWith("Unable to access ")))return{ok:!1,errors:L.errors,warnings:[],entries:[]};if(n.only&&L.errors.length>0)return{ok:!1,errors:L.errors,warnings:[],entries:[]};let i=L.errors.length>0?null:L.lock,u=n.only?Te(c,i,n.only):{ok:!0,specs:c.rules};if(!u.ok)return u.result;if(n.only&&!i&&u.specs.length<c.rules.length)return{ok:!1,errors:[`No lockfile available for partial update; run ${Ce}`],warnings:[],entries:[]};let o=(await ss(u.specs,(h)=>Ee(h,s.configDir,n,i,s.filesystemScope,t),t)).map((h)=>ps(h,i,r));for(let h of o)os(h.content,h.entry,s.configDir,n,s.filesystemScope);let p=n.only?us(c,i,o):o.map((h)=>h.entry);l=!0,E(s.lockTarget,{version:1,rulebooks:p},void 0,e._testAfterPolicyRename);let f=new Map(o.map((h)=>[h.entry.spec,h.rulebook.rules.length])),v=bs(p,s.configDir,n,s.filesystemScope,e);return{ok:!0,errors:[],warnings:v,entries:p.map((h)=>vs(h,f))}}catch(s){if(l&&a)try{R2(a.target,a.content)}catch(d){return A2(d)}return A2(s)}}async function Ot(n,t={}){return ls(n,Tt(t),W2())}async function ls(n,t,r,e={}){let a=null,l=!1;try{let s=T(t),d=m(s.configTarget);a={target:s.configTarget,content:d};let c=Ut(s.configTarget);if(!c.ok)return c.result;let L=c.config,i=Ue(n)?await Pe(n,r):[{spec:n}],u=i.map((f)=>f.spec),o=[...new Set([...L.rules,...u])];if(o.length>Mt)return ds();if(o.length!==L.rules.length)l=!0,E(s.configTarget,{version:1,rules:o,overrides:L.overrides??{},transparent_wrappers:L.transparent_wrappers??[]},void 0,e._testAfterPolicyRename);let p=await Wn(t,r,new Map(i.filter((f)=>!!f.display_ref).map((f)=>[f.spec,f.display_ref])),e);if(!p.ok)R2(s.configTarget,d);return p}catch(s){if(l&&a)try{R2(a.target,a.content)}catch(d){return A2(d)}return A2(s)}}async function ss(n,t,r=W2()){if(n.length>Mt)throw Error(Gt);let e=Array(n.length),a=0,l,s=Array.from({length:Math.min(n.length,Oe.concurrency)},async()=>{while(!l){let d=a;if(d>=n.length)return;a++;try{e[d]=await t(n[d],d,r.controller.signal)}catch(c){if(!l)l={value:c},a=n.length,r.controller.abort(c);return}}});if(await Promise.all(s),l)throw l.value;return e}function ds(){return{ok:!1,errors:[Gt],warnings:[],entries:[]}}function Tt(n){return{cwd:n.cwd,cacheConfigDir:n.cacheConfigDir,userConfigDir:n.userConfigDir,userConfigPath:n.userConfigPath,projectConfigPath:n.projectConfigPath,global:n.global,check:n.check,only:n.only,refresh:n.refresh}}function cs(n){return{...Tt(n),deleteSource:n.deleteSource}}async function _t(n,t={}){try{return await Ls(n,cs(t),{})}catch(r){return A2(r)}}async function Ls(n,t,r){let e=T(t),a=_(e.configTarget);if(a.errors.length>0)return{ok:!1,errors:a.errors,warnings:[],entries:[]};if(!a.config)return{ok:!1,errors:[`No config found at ${e.configPath}`],warnings:[],entries:[]};let l=Ct(e.lockTarget);if(l.errors.length>0)return{ok:!1,errors:l.errors,warnings:[],entries:[]};let s=_e(a.config.rules,l.lock,n);if(!s.ok)return s.result;let d=t.deleteSource?fs(e.configDir,s.specs,l.lock,e.filesystemScope):{ok:!0,dirs:[]};if(!d.ok)return d.result;let c=m(e.configTarget);if(c===null)return A2(Error("Rules config is unavailable."));try{E(e.configTarget,{version:1,rules:a.config.rules.filter((u)=>!s.specs.includes(u)),overrides:a.config.overrides??{},transparent_wrappers:a.config.transparent_wrappers??[]},void 0,r._testAfterPolicyRename)}catch(u){throw R2(e.configTarget,c),u}let L=await Wn(t,W2(),void 0,r);if(!L.ok)return R2(e.configTarget,c),L;let i=hs(d.dirs,r,e.filesystemScope);if(!i.ok){R2(e.configTarget,c);let u=await Wn(t,W2(),void 0,r);if(!u.ok)return{ok:!1,errors:[...i.result.errors,...u.errors],warnings:u.warnings,entries:u.entries};return i.result}return L}async function is(n,t,r){let e=Ie(n,t.lockPath,t.configDir,r,r.global?"user":"project",t.filesystemScope);return{ok:e.errors.length===0&&e.warnings.length===0,errors:[...e.errors,...e.warnings],warnings:[],entries:e.entries}}function ps(n,t,r){let e=t?.rulebooks.find((l)=>l.spec===n.entry.spec&&l.kind==="github"),a=r?.get(n.entry.spec)??(e?.kind==="github"?e.display_ref:void 0);if(!a||n.entry.kind!=="github")return n;return{...n,entry:{...n.entry,display_ref:a}}}function us(n,t,r){let e=new Set(n.rules),a=new Set(t?.rulebooks.map((s)=>s.spec)??[]),l=new Map(r.map((s)=>[s.entry.spec,s.entry]));return[...(t?.rulebooks.filter((s)=>e.has(s.spec))??[]).map((s)=>l.get(s.spec)??s),...r.filter((s)=>!a.has(s.entry.spec)).map((s)=>s.entry)]}function vs(n,t){return{...n,ruleCount:t.get(n.spec)}}function os(n,t,r,e,a){let l=Kt(t,Vt(r,e));m2(D(a,l),n)}function bs(n,t,r,e,a){let l=Vt(t,r),s=An(l),d=D(e,s),c=K2(d);if(!c)return[];let L=n.map((u)=>D(e,Kt(u,l))),i=c.filter((u)=>u.kind==="directory").map((u)=>({directory:D(e,Rn(s,u.name)),identity:D(e,Rn(s,u.name,Ge))})).filter((u)=>!L.some((o)=>Ve(u.identity,o))).map((u)=>u.directory);for(let u of i)Me(u);return i.flatMap((u)=>{try{return ws(u,a),[]}catch{return["Unable to prune rules policy cache safely."]}})}function fs(n,t,r,e){let a=new Map(r?.rulebooks.map((L)=>[L.spec,L])??[]),l=t.flatMap((L)=>{let i=a.get(L);if(!i)return pn.test(L)?[]:["--delete-source can only delete local rulebook sources"];return i.kind==="local-directory"?[]:["--delete-source can only delete local rulebook sources"]}),s=t.map((L)=>{let i=a.get(L);return Rn(n,i?.kind==="local-directory"?i.path:L)}),d=l.length>0?[]:s.flatMap((L)=>ys(n,L,e)),c=[...l,...d];return c.length>0?{ok:!1,result:{ok:!1,errors:c,warnings:[],entries:[]}}:{ok:!0,dirs:s}}function ys(n,t,r){let e=Ke(n),a=Ke(t),l=rs(e,a);if(l===""||l===".."||l.startsWith(`..${es}`)||ts(l))return[`Refusing to delete local rulebook source outside ${n}: ${t}`];let s=D(r,a),d=K2(s);if(!d)return[`Local rulebook source directory not found: ${t}`];let c=d.find((L)=>L.name==="rulebook.json");if(!c)return[`Local rulebook source directory is missing rulebook.json: ${t}`];if(c.kind!=="file")throw new X(r.label);if(m(D(r,Rn(a,"rulebook.json"))),d.length>1)return[`Local rulebook source directory contains extra files: ${t}. delete manually if you really want to remove the directory.`];return[]}function hs(n,t,r){let e=n.flatMap((a)=>{try{return xs(D(r,a),t),[]}catch(l){return[`Failed to delete local rulebook source ${a}: ${l instanceof Error?l.message:String(l)}`]}});return e.length>0?{ok:!1,result:{ok:!1,errors:e,warnings:[],entries:[]}}:{ok:!0}}function ws(n,t){if(t._testPruneRulebookCacheDir){t._testPruneRulebookCacheDir(n.path);return}At(n)}function xs(n,t){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(n.path);return}At(n)}function R2(n,t){if(t===null){Ln(n);return}m2(n,t)}function A2(n){return{ok:!1,errors:[n instanceof Error?n.message:String(n)],warnings:[],entries:[]}}function C2(n,t){let r=gs(t),e=a1(r),a={effectiveLevel:e.effectiveLevel,selectedPreset:r.policySnapshot.policy.safety.level??"standard",effectiveCapabilities:e.effectiveCapabilities,destructiveCommandRuleOverrides:r.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:l,configValid:s}=ms({cwd:t?.cwd,userConfigDir:t?.userConfigDir});if(!n||!n.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:l,configValid:s,...a};let d=Ds(n,r);if(d)return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:d.rule,matched:!0,reason:d.reason}]}]},result:"blocked",reason:A(d.reason),segment:A(d.target),...d.ruleId?{ruleId:A(d.ruleId)}:{},configSource:l,configValid:s,...a};let c=Xe(n,r),L=c.decision,i=L?.ruleId??ks(n,r),u=vn.find((p)=>p.id===i&&p.activationCapability),o=u?e.policy.effectiveDestructiveCommandRules[u.id]:void 0;return{trace:js(c.trace),result:L?"blocked":"allowed",reason:L?A(L.reason):void 0,segment:L?A(L.evidence.find((p)=>p.kind==="command")?.segment??n):void 0,ruleId:L?.ruleId?A(L.ruleId):void 0,customRule:qs(zs(L?.ruleId,r.policySnapshot)),configSource:l,configValid:s,...a,...u&&o?{ruleActivation:{id:u.id,...o}}:{}}}function ms(n){let t=P(n?.cwd),r=n?.userConfigPath??I(n),e=N({cwd:n?.cwd,userConfigDir:n?.userConfigDir,userConfigPath:n?.userConfigPath});try{if(m(e.projectConfigTarget)!==null){if(s2(e.projectConfigTarget).errors.length===0)return{configSource:t,configValid:!0};return{configSource:t,configValid:!1}}}catch(a){if(a instanceof X)return{configSource:t,configValid:!1};throw a}try{if(m(e.userConfigTarget)!==null){let a=s2(e.userConfigTarget);return{configSource:r,configValid:a.errors.length===0}}return{configSource:null,configValid:!0}}catch(a){if(a instanceof X)return{configSource:r,configValid:!1};throw a}}function gs(n){let t=$s(n?.cwd??process.cwd()),r=n?.policySnapshot??K({cwd:t,userConfigDir:n?.userConfigDir}),e=c2(r.policy);return{cwd:t,effectiveCwd:t,policySnapshot:r,environment:Ne(),protectedGitMetadata:e1(t),effectiveCapabilities:e.capabilities,strict:n?.strict??e.strict,paranoidRm:e.paranoidRm,paranoidInterpreters:e.paranoidInterpreters,worktreeMode:e.worktreeMode}}function Ds(n,t){let r=t.cwd??process.cwd(),e=n1(U2("",{command:n},{kind:"command",shell:"posix"},{executionCwd:r,configCwd:r},n)),a=d1(e);if(a)return{reason:s1,target:a.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let l=r1(e,t.protectedGitMetadata);if(l)return{reason:t1,target:l.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let s=t.policySnapshot.policy,d=s.secretProtection.enabled===!1?null:L1(e,s.secretProtection,{strict:t.strict});if(d)return{reason:c1,target:d.target,ruleId:d.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function ks(n,t){let r=t.policySnapshot.policy,e=on({...r,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...r.destructiveCommandRuleOverrides,...Object.fromEntries(vn.flatMap((a)=>a.activationCapability?[[a.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return l1(n,{...t,policySnapshot:e,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function qs(n){if(!n)return;return{id:A(n.id),...n.rulebook?{rulebook:{name:A(n.rulebook.name),version:A(n.rulebook.version)}}:{},...n.source?{source:A(n.source)}:{},...n.override?{override:{type:"reason",reason:A(n.override.reason)}}:{}}}function js(n){let t=n.events.flatMap((e)=>e.kind==="step"&&e.scope==="global"?[e.step]:[]),r=new Map;for(let e of n.events){if(e.kind!=="step"||e.scope!=="segment")continue;let a=r.get(e.segmentIndex)??{index:e.segmentIndex,steps:[]};a.steps.push(e.step),r.set(e.segmentIndex,a)}return{steps:t,segments:[...r.values()]}}function zs(n,t){let r=n?.replace(/^custom\./,"");if(!r||!t.policy.rules.some((e)=>e.name===r))return;return t.ruleMetadata[r]??Object.freeze({id:r})}function Xs(n){let t=O2(),r=B({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"]}},n);if(l2(r.errors))return null;if(r.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(r.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let e=r.values.limit===void 0?20:i1(r.values.limit);if(e===null)return console.error("--limit must be a positive number"),null;let a=r.values.since===void 0?Math.min(30,t):i1(r.values.since);if(a===null||a>t)return console.error(`--since must be a positive number of days no greater than ${t}`),null;let l={limit:e,limitExplicit:r.values.limit!==void 0,since:a,sinceExplicit:r.values.since!==void 0,all:r.flags.all,json:r.flags.json,suspect:r.flags.suspect,pruneLegacy:r.flags.pruneLegacy,dryRun:r.flags.dryRun,id:r.values.id,agent:r.values.agent,rule:r.values.rule,session:r.values.session,project:r.values.project===void 0?void 0:Qs(r.values.project)};if(l.id&&(l.agent!==void 0||l.rule!==void 0||l.session!==void 0||l.project!==void 0||l.suspect||l.sinceExplicit||l.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(l.pruneLegacy&&(l.id!==void 0||l.agent!==void 0||l.rule!==void 0||l.session!==void 0||l.project!==void 0||l.suspect||l.all||l.sinceExplicit||l.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(l.dryRun&&!l.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return l}async function v1(n,t={}){let r=Xs(n);if(!r)return 1;let e=t.logsDir??L2();if(r.pruneLegacy)return Ys(e,r.json,r.dryRun);if(!e)return console.log(r.json?"[]":r.id?`No retained audit log entry found for id ${J(r.id)}.`:"No audit log entries found."),0;D2(e);let a={count:0},l=f2(e,a).flatMap((i)=>dn(i,a).map((u)=>({entry:u,file:i})));if(a.count>0)console.error(`warning: ${a.count} audit log ${a.count===1?"source":"sources"} could not be read; these results are incomplete`);if(r.id)return Ws(l,r,t.timeZone);let s=Date.now()-r.since*24*60*60*1000,d=l.filter((i)=>As(i,r,e,s)),c=r.suspect?Xt(d.map((i)=>i.entry)):null,L=(c?d.filter((i)=>c.has(i.entry)):d).sort((i,u)=>Date.parse(u.entry.ts)-Date.parse(i.entry.ts)).slice(0,r.limit);if(r.json)return console.log(JSON.stringify(L.map((i)=>i.entry),null,2)),0;if(L.length===0)return console.log("No audit log entries found."),0;for(let i of L)console.log(Ms(i.entry,t.timeZone));return 0}function Ys(n,t,r){let e=n?Hs(n).map((d)=>Zs(n,d)):[];if(r)return Ss(e,t);let a=[],l=0,s=0;for(let d of e){let c=p1(d,{throwIfNoEntry:!1})?.size??0,L=Rs(d);if(L){a.push(`${u1(d)}: ${L}`);continue}l++,s+=c}if(t)return console.log(JSON.stringify({removedFiles:l,removedBytes:s,failedFiles:a.length})),a.length===0?0:1;console.log(l===0&&a.length===0?"No legacy audit log files found.":`Removed ${l} legacy audit log ${l===1?"file":"files"} (${o1(s)}).`);for(let d of a)console.error(`Could not remove ${J(d)}`);if(console.log("Nested v2 audit logs were not changed."),l>0)console.log("This deletion cannot be undone.");return a.length===0?0:1}function Ss(n,t){let r=n.reduce((e,a)=>e+(p1(a,{throwIfNoEntry:!1})?.size??0),0);if(t)return console.log(JSON.stringify({dryRun:!0,files:n.length,bytes:r})),0;if(console.log(n.length===0?"No legacy audit log files found.":`Would remove ${n.length} legacy audit log ${n.length===1?"file":"files"} (${o1(r)}).`),console.log("Nested v2 audit logs are not included."),n.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Hs(n){try{return Fs(n,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function Rs(n){try{return Bs(n),null}catch(t){return t instanceof Error?t.message:String(t)}}function o1(n){let t=["B","KiB","MiB","GiB"],r=Math.min(Math.floor(Math.log2(Math.max(n,1))/10),t.length-1);return`${Math.round(n/1024**r*10)/10} ${t[r]}`}function Ws(n,t,r){let e=n.filter((l)=>l.entry.id===t.id);if(e.length>1)return console.error(`Multiple audit log entries found for id ${J(t.id??"")}.`),1;if(t.json)return console.log(JSON.stringify(e.map((l)=>l.entry),null,2)),0;let a=e[0];if(!a)return console.log(`No retained audit log entry found for id ${J(t.id??"")}.`),0;return console.log(Gs(a.entry,r)),0}function As(n,t,r,e){if(!t.all&&n.entry.decision==="allow")return!1;if(Date.parse(n.entry.ts)<e)return!1;if(t.agent!==void 0&&n.entry.agent!==t.agent)return!1;if(t.rule!==void 0&&n.entry.ruleId!==t.rule)return!1;if(t.session!==void 0&&!Ks(n,r,t.session))return!1;if(t.project!==void 0&&!Vs(n.entry.cwd,t.project))return!1;return!0}function Ks(n,t,r){if(n.entry.sessionId===r)return!0;return Js(n.file)===t&&u1(n.file,".jsonl")===r}function Vs(n,t){if(!n)return!1;return n===t||n.startsWith(`${t}/`)}function Ms(n,t){let r=J(n.id??"-"),e=J(n.decision??"deny"),a=n.cwd?` [${J(n.cwd)}]`:"",l=n.segment||n.command,s=l===n.command?"":"↳ ",d=l.length>50?`${l.slice(0,50)}…`:l;return`${r.padEnd(16)} ${J(b1(n.ts,t))} ${e.padEnd(5)} ${J(n.agent??"-").padEnd(15)} ${J(n.ruleId??"-").padEnd(20)} ${s}${J(d)}${a}`}function Gs(n,t){let r=(a)=>J(a===void 0||a===null||a===""?"-":a),e=n.shape?`${n.agent??"-"} (shape: ${n.shape})`:n.agent??"-";return[`id: ${r(n.id)}`,`ts: ${r(b1(n.ts,t))}`,`decision: ${r(n.decision)}`,`agent: ${r(e)}`,`level: ${r(n.level)}`,`tool: ${r(n.toolName)}`,`rule: ${r(n.ruleId)}`,`intent: ${r(n.intent)}`,`stage: ${r(n.failureStage)}`,`error: ${r(n.errorCode)}`,`session: ${r(n.sessionId)}`,`cwd: ${r(n.cwd)}`,`version: ${r(n.v)}`,`truncated: ${r(n.truncated===!0?"yes":void 0)}`,`reason: ${r(n.reason)}`,`command: ${r(n.command)}`,`segment: ${r(n.segment)}`].join(`
|
|
5
|
+
`)}function b1(n,t){let r=new Date(n);if(Number.isNaN(r.getTime()))return n;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(r)}function i1(n){let t=Number(n);return Number.isFinite(t)&&t>0?t:null}var f1={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 y1={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 h1={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 j1,relative as td}from"node:path";var Us=8388608;function Cs(n,t){console.log(JSON.stringify(n(x1(t))))}async function Os(n){let t;try{t=(await ir(process.stdin)).trim()}catch{n({reason:"Failed to parse hook input JSON."});return}if(!t){n({reason:"Missing hook input JSON."});return}return pr(t,n,"Failed to parse hook input JSON.")}async function ir(n){let t=[],r=0;for await(let e of n){let a=typeof e==="string"?Buffer.from(e,"utf-8"):Buffer.from(e.buffer,e.byteOffset,e.byteLength);if(r+=a.byteLength,r>Us)throw Ts(n),Error("hook input byte limit exceeded");t.push(a)}return Buffer.concat(t,r).toString("utf-8")}function Ts(n){let t=n.destroy??n.cancel;if(!t)return;try{Promise.resolve(t.call(n)).catch(()=>{})}catch{}}function pr(n,t,r){try{return JSON.parse(n)}catch{t({reason:r});return}}function H(n,t){let r=t.get(n);return r?{kind:"command",shell:r}:{kind:m1(n)}}function n2(n,t,r,e){let a=n===void 0?process.cwd():n,l=typeof a==="string"&&a.trim()!==""?p2([a]):void 0;if(l)return{configCwd:l,executionCwd:l};return Q(e,t,r,Is(a)),null}function Q(n,t,r,e){let a;try{a=Lr(t)}catch(l){if(!(l instanceof i2))throw l}n(Kn({command:a,segment:e,toolName:r}))}async function _s(n){let t=await Os(n.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){Q(n.outputDeny);return}if(!n.isSupported(t))return;let r=n.getAgent?.(t)??n.agent,e=n.agent===r?void 0:n.agent,a=nd(t),l=(p,f)=>{w1(p,()=>n.getSessionId(t),{agent:r,shape:e,toolName:f,cwd:a}),n.outputDeny(p)},s=n.getToolName(t);if(typeof s!=="string"||s.trim()===""){Q((p)=>l(p),Ns(t));return}let d=s,c=(p)=>l(p,d),L;try{L=n.getToolInput(t,d,c)}catch(p){if(!(p instanceof i2))throw p;Q(c,void 0,d);return}if(!L.ok)return;let i=n.getContext(t,L.input,d,c);if(!i)return;let u;try{u=Lr(L.input)}catch(p){if(!(p instanceof i2))throw p;Q(c,void 0,d);return}let o=U2(d,L.input,L.route,i,u??null);try{let p=Vn(o,{guard:{auditAllowed:g1(),dependencies:n.guardDependencies},audit:{agent:r,shape:e,getSessionId:()=>n.getSessionId(t)}}),f=cr(p,{includeEvidence:!0,toolName:p.stage==="command-analysis"?void 0:d});if(f){n.outputDeny(f);return}n.outputAllow?.()}catch(p){if(!(p instanceof D1))throw p;Es(p);let f=cr(p.evaluation,{includeEvidence:!0,toolName:p.evaluation.stage==="command-analysis"?void 0:d});if(f)n.outputDeny(f);return}}function Es(n){if(!bn(k.debug))return;console.error(`CC Safety Net debug: ${Ps(n.stage)}: ${$1(n.cause)}`)}function Ps(n){if(n==="policy-protection")return"hook policy protection failed";if(n==="config-load")return"hook config loading failed";if(n==="secret-protection")return"hook secret protection failed";return"hook analysis failed"}function Is(n){return typeof n==="string"?n:void 0}function Ns(n){if(!n||typeof n!=="object"||Array.isArray(n))return;if(Object.hasOwn(n,"tool_input"))return n.tool_input;let t=n.toolCall;if(t&&typeof t==="object"&&!Array.isArray(t))return t.args;return}function nd(n){if(!n||typeof n!=="object"||Array.isArray(n))return null;let t=n.cwd;if(typeof t==="string")return t;let r=n.toolCall;if(!r||typeof r!=="object"||Array.isArray(r))return null;let e=r.args;if(!e||typeof e!=="object"||Array.isArray(e))return null;let a=e.Cwd;return typeof a==="string"?a:null}async function R(n){let t=(a)=>Cs(n.createDenyOutput,a),r=n.createAllowOutput;await _s({...n,outputDeny:t,outputAllow:r?()=>console.log(JSON.stringify(r())):void 0})}var rd=new Map([["run_command","auto"]]),ed=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function z1(n){return H(n,rd)}async function F1(){await R({agent:"antigravity-cli",createDenyOutput:(n)=>({decision:"deny",reason:n}),isSupported:()=>!0,getToolName:(n)=>n.toolCall?.name,getToolInput:(n,t)=>({ok:!0,input:cd(n.toolCall?.args,t),route:z1(t)}),getContext:ad,getSessionId:(n)=>n.conversationId})}function ad(n,t,r,e){let l=dd(n).flatMap((L)=>{let i=p2([L]);return i?[i]:[]});if(!l[0])return j2(e,t,r),null;if(r!=="run_command"){let L;try{L=ld(t,r,l)}catch(i){if(i instanceof i2)return j2(e,void 0,r),null;if(!(i instanceof k2))throw i;return j2(e,t,r),null}if(!L)return j2(e,t,r),null;return{configCwd:L,executionCwd:L,policyConfigCwds:l}}let s=n.toolCall?.args;if(!s||!Object.hasOwn(s,"Cwd"))return{configCwd:l[0],executionCwd:l[0],policyConfigCwds:l};let d=s.Cwd;if(typeof d!=="string"||d.trim()==="")return j2(e,t,r),null;let c=z2(d,l);if(c){let L=B1(c,l);if(!L)return j2(e,t,r,d),null;return{configCwd:L,executionCwd:c,policyConfigCwds:l}}return j2(e,t,r,d),null}function ld(n,t,r){let e=z1(t),a=[...k1(n,ed),...e.kind==="patch"?q1(n):[]].filter(j1),l=Mn(),s=new Set(a.flatMap((d)=>{let c=B1(hn(d,wn,l),r);return c?[c]:[]}));if(s.size>1)return null;return[...s][0]??r[0]??null}function B1(n,t){return t.filter((r)=>sd(n,r)).reduce((r,e)=>e.length>r.length?e:r,"")||null}function sd(n,t){let r=td(t,n);return r===""||!r.startsWith("..")&&!j1(r)}function j2(n,t,r,e){let a=t&&typeof t==="object"?t.command:void 0;n(Kn({command:typeof a==="string"?a:void 0,segment:e,toolName:r}))}function dd(n){if(n.workspacePaths===void 0)return[process.cwd()];let t=Array.isArray(n.workspacePaths)?n.workspacePaths.filter((r)=>typeof r==="string"&&r.trim()!==""):[];return p2(t)?t:[]}function cd(n,t){if(!n)return;if(t!=="run_command")return n;return{...n,command:typeof n.CommandLine==="string"&&n.CommandLine!==""?n.CommandLine:void 0}}var xn=[{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:"hermes-agent",displayName:"Hermes Agent",doctorOrder:8,runtime:{order:6,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:9,runtime:{order:7,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:10,install:{order:10,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:11,install:{order:11,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:12,install:{order:12,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"]}}],Gn=xn.slice().sort((n,t)=>n.doctorOrder-t.doctorOrder).map((n)=>n.id),J1=xn.filter((n)=>("runtime"in n)).slice().sort((n,t)=>n.runtime.order-t.runtime.order).map((n)=>({id:n.id,displayName:"displayName"in n.runtime?n.runtime.displayName:n.displayName,flags:n.runtime.flags,legacyFlags:"legacyFlags"in n.runtime?n.runtime.legacyFlags:[],description:n.runtime.description,legacyTopLevelFlags:n.runtime.legacyTopLevelFlags})),M=xn.slice().sort((n,t)=>n.install.order-t.install.order).map((n)=>({id:n.id,...n.install})).map(({order:n,...t})=>t),W6=Object.fromEntries(xn.map((n)=>[n.id,n.displayName]));function j(n){return xn.find((t)=>t.id===n)?.displayName??n}import{homedir as Ld}from"node:os";import{isAbsolute as Z1,join as ur}from"node:path";function X1(n){if(n!==void 0&&n!==null&&!Z1(n))return"unknown";try{let t=Mn(),r=n?hn(n,wn,t):void 0,e=process.env.HOME||Ld(),a=[["codex",process.env.CODEX_HOME||ur(e,".codex")],["copilot-cli",process.env.COPILOT_HOME||ur(e,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||ur(e,".claude")]],l=r?a.flatMap(([s,d])=>{if(!Z1(d))return[];return Q1(r,hn(d,wn,t))?[s]:[]}):[];if(l.length===1)return l[0]??"unknown";if(l.length>1)return"unknown"}catch(t){if(t instanceof k2)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var vr="PreToolUse",Y1="BeforeTool",S1="pre_tool_call",or="PreToolUse";var id=new Map([["Bash","posix"],["PowerShell","powershell"]]);function pd(n){return H(n,id)}async function H1(){await R({agent:"claude-code",getAgent:(n)=>X1(n.transcript_path),createDenyOutput:(n)=>({hookSpecificOutput:{hookEventName:vr,permissionDecision:"deny",permissionDecisionReason:n}}),isSupported:(n)=>n.hook_event_name===vr,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:pd(t)}),getContext:(n,t,r,e)=>n2(n.cwd,t,r,e),getSessionId:(n)=>n.session_id})}var ud=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function vd(n){return H(n,ud)}async function R1(){await R({agent:"copilot-cli",createDenyOutput:(n)=>({permissionDecision:"deny",permissionDecisionReason:n}),isSupported:()=>!0,getToolName:(n)=>n.toolName,getToolInput:(n,t,r)=>{if(typeof n.toolArgs!=="string")return r({reason:"Failed to parse toolArgs JSON."}),{ok:!1};let e=pr(n.toolArgs,r,"Failed to parse toolArgs JSON.");if(e===void 0)return{ok:!1};return{ok:!0,input:e,route:vd(t)}},getContext:(n,t,r,e)=>n2(n.cwd,t,r,e),getSessionId:(n)=>typeof n.sessionId==="string"&&n.sessionId.trim()?n.sessionId:void 0})}var od=new Map([["Shell","auto"]]);function bd(n){return H(n,od)}async function W1(){await R({agent:"cursor",createDenyOutput:(n)=>({permission:"deny",user_message:n,agent_message:n}),createAllowOutput:()=>({permission:"allow"}),isSupported:()=>!0,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:bd(t)}),getContext:fd,getSessionId:(n)=>n.conversation_id})}function fd(n,t,r,e){let a=yd(n);if(!a[0])return Q(e,t,r),null;let l=z2(wd(n.cwd),a);if(!l)return Q(e,t,r,typeof n.cwd==="string"?n.cwd:void 0),null;if(t===null||typeof t!=="object"||Array.isArray(t))return{configCwd:l,executionCwd:l,policyConfigCwds:a};if(!Object.hasOwn(t,"working_directory"))return{configCwd:l,executionCwd:l,policyConfigCwds:a};let s=t.working_directory;if(typeof s!=="string"||s.trim()==="")return Q(e,t,r),null;let d=z2(s,a);if(!d)return Q(e,t,r,s),null;return{configCwd:l,executionCwd:d,policyConfigCwds:a}}function yd(n){return hd(n).flatMap((t)=>{let r=p2([t]);return r?[r]:[]})}function hd(n){if(n.workspace_roots===void 0)return typeof n.cwd==="string"&&n.cwd.trim()!==""?[n.cwd]:[];if(!Array.isArray(n.workspace_roots))return[];return n.workspace_roots.filter((t)=>typeof t==="string"&&t.trim()!=="")}function wd(n){return typeof n==="string"&&n.trim()!==""?n:"."}var xd=new Map([["run_shell_command","auto"]]);function $d(n){return H(n,xd)}async function A1(){await R({agent:"gemini-cli",createDenyOutput:(n)=>({decision:"deny",reason:n,systemMessage:n}),isSupported:(n)=>n.hook_event_name===Y1,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:$d(t)}),getContext:(n,t,r,e)=>n2(n.cwd,t,r,e),getSessionId:(n)=>n.session_id})}import{resolve as md}from"node:path";var gd=new Map([["terminal","posix"]]);async function K1(){await R({agent:"hermes-agent",createDenyOutput:(n)=>({action:"block",message:n}),isSupported:(n)=>n.hook_event_name===S1,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:H(t,gd)}),getContext:Dd,getSessionId:(n)=>n.session_id})}function Dd(n,t,r,e){let a=n2(n.cwd,t,r,e);if(!a)return null;if(!t||typeof t!=="object"||Array.isArray(t))return a;if(!Object.hasOwn(t,"workdir"))return a;let l=t.workdir;if(typeof l!=="string"||l.trim()==="")return Q(e,t,r),null;let s=p2([md(a.configCwd,l)]);if(!s)return Q(e,t,r,l),null;return{...a,executionCwd:s}}var V1=new Map([["Bash","posix"]]);function kd(n){return H(n,V1)}async function M1(){await R({agent:"kimi-code",createDenyOutput:(n)=>({hookSpecificOutput:{hookEventName:or,permissionDecision:"deny",permissionDecisionReason:n}}),isSupported:(n)=>n.hook_event_name===or,getToolName:(n)=>n.tool_name,getToolInput:(n,t)=>({ok:!0,input:n.tool_input,route:kd(t)}),getContext:(n,t,r,e)=>{let a=n2(n.cwd,t,r,e);if(!a)return null;let l=n.tool_input;if(!V1.has(r)||!l||!Object.hasOwn(l,"cwd"))return a;let s=l.cwd;if(typeof s!=="string"||s.trim()==="")return Q(e,t,r),null;let d=z2(s,[a.configCwd]);if(!d)return Q(e,t,r,s),null;return{configCwd:a.configCwd,executionCwd:d}},getSessionId:(n)=>n.session_id})}var qd={"antigravity-cli":F1,"claude-code":H1,"copilot-cli":R1,cursor:W1,"gemini-cli":A1,"hermes-agent":K1,"kimi-code":M1},T2=J1.map((n)=>({...n,run:qd[n.id]}));function G1(n){let t=B({label:"hook",booleans:Object.fromEntries(T2.map((e)=>[e.id,[...e.flags,...e.legacyFlags]]))},n);if(t.errors.length>0)return;let r=T2.filter((e)=>t.flags[e.id]);return r.length===1?r[0]:void 0}function U1(n){return T2.find((t)=>t.legacyTopLevelFlags.some((r)=>r===n))}var jd=T2.map((n)=>({flags:n.flags.join(", "),description:n.description})),zd=T2.flatMap((n)=>n.flags.map((t)=>`cc-safety-net hook ${t}`)),C1={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...jd,{flags:"-h, --help",description:"Show this help"}],examples:zd};var O1={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...M.map((n)=>({flags:n.flag,description:`Install ${j(n.id)} ${n.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...M.map((n)=>`cc-safety-net install ${n.flag}`)]},T1={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...M.map((n)=>({flags:n.flag,description:`Uninstall ${j(n.id)} ${n.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...M.map((n)=>`cc-safety-net uninstall ${n.flag}`)]},_1={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 E1={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 _2={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add <source>",description:"Add a rulebook source and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Refresh rulebook lock/cache state"},{usage:"sync",description:"Sync configured rulebooks"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--check",description:"Check without changing lock/cache state"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk","cc-safety-net rule add project-rules","cc-safety-net rule sync","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var P1={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 I1={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 N1=[P1,f1,E1,y1,_2,O1,_1,T1,C1,h1,I1];function Fd(n){return n.aliases??[]}function Bd(n){return!n.hidden}function Un(n){let t=n.toLowerCase();return N1.find((r)=>r.name.toLowerCase()===t||Fd(r).some((e)=>e.toLowerCase()===t))}function na(){return N1.filter(Bd)}import{readFileSync as Jd}from"node:fs";import{basename as Zd}from"node:path";function Cn(n=7,t=L2()){let r=Date.now()-n*24*60*60*1000,e=[],a=new Set,l=0,s,d,c,L;if(t)D2(t);let i={count:0},u=t?f2(t,i):[];for(let p of u)try{let v=Jd(p,"utf-8").trim().split(`
|
|
6
|
+
`).filter(Boolean);for(let h of v)try{let w=JSON.parse(h);if(w.decision==="allow")continue;let $=new Date(w.ts).getTime();if($>=r){if(l++,a.add(w.sessionId??Zd(p,".jsonl")),d===void 0||$<=d)s=w.ts,d=$;if(L===void 0||$>L)c=w.ts,L=$;Qd(e,w,$)}}catch{i.count++}}catch{i.count++}let o=e.map((p)=>({timestamp:p.ts,command:p.command,reason:p.reason,relativeTime:Qt(new Date(p.ts))}));return{totalBlocked:l,sessionCount:a.size,recentEntries:o,oldestEntry:s,newestEntry:c,unreadable:i.count}}function Qd(n,t,r){let e=n.findIndex((a)=>r>new Date(a.ts).getTime());if(e===-1){if(n.length<3)n.push(t);return}if(n.splice(e,0,t),n.length>3)n.pop()}import{dirname as Xd}from"node:path";function ta(n,t,r,e,a){let l;try{if(m(e)===null)return{path:n,exists:!1,valid:!1,ruleCount:0};l=s2(e),l.errors.push(...d2(n,t,{userConfigDir:r},a))}catch(s){if(!(s instanceof X))throw s;l={errors:[s.message],ruleNames:new Set}}return{path:n,exists:!0,valid:l.errors.length===0,ruleCount:l.ruleNames.size,...l.errors.length>0?{errors:l.errors}:{}}}function Yd(n,t){return{source:t,name:n.name,command:n.command,subcommand:n.subcommand,blockArgs:[...n.block_args],reason:n.reason}}function ra(n,t){let r=t?.userConfigPath??I(),e=t?.projectConfigPath??P(n),a=Xd(r),l=y2({cwd:n,userConfigPath:r,projectConfigPath:e,userConfigDir:a}),s=N({cwd:n,userConfigPath:r,projectConfigPath:e,userConfigDir:a}),d=new Map(l.rulebooks.flatMap((c)=>c.rules.map((L)=>[L,c.source])));return{userConfig:ta(r,M2({userConfigPath:r}),a,s.userConfigTarget,s.userScope),projectConfig:ta(e,G2(e),a,s.projectConfigTarget,s.projectScope),effectiveRules:l.rules.map((c)=>Yd(c,d.get(c.name)??"project")),shadowedRules:[]}}var Sd=[{flag:k.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:k.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:k.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:k.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:k.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:k.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:k.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:k.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function ea(){return[...Sd.map((n)=>({name:n.flag.name,value:lr(n.flag),isSet:sr(n.flag),legacyName:n.flag.legacyName,legacyValue:n.flag.legacyName?process.env[n.flag.legacyName]:void 0,legacyIsSet:n.flag.legacyName?process.env[n.flag.legacyName]!==void 0:void 0,description:n.description,defaultBehavior:n.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 aa={error:0,warning:1,info:2},Hd=["policy","config","audit"];function Rd(n){return n.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 Wd=[{derive:(n)=>n.hooks.length>0&&n.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:(n)=>n.hooks.filter((t)=>t.inspectionStatus==="failed").map((t)=>{let r=j(t.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${r} inspection failed`,detail:`Doctor could not verify the ${r} integration configuration.`,fixHint:`Correct the reported ${r} configuration error, then run \`cc-safety-net doctor\` again.`,integration:t.platform}})},{derive:(n)=>n.userConfig.exists&&!n.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:n.userConfig.path}]:[]},{derive:(n)=>n.projectConfig.exists&&!n.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:n.projectConfig.path}]:[]},{derive:(n)=>n.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${n.configState.reason}`,fixHint:"Correct the named source, run `cc-safety-net rule sync` for a rule source, then rerun doctor."}]:[]},{derive:(n)=>{let t=n.environment.find((r)=>r.name==="CC_SAFETY_NET_AUDIT_SCOPE");return ar(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."}]:[]}},...Hd.map((n)=>({derive:(t)=>t.posture.directories.filter((r)=>r.kind===n&&r.status==="unsafe").map((r)=>({checkId:`posture.${n}-directory-unsafe`,severity:"error",title:`${n[0]?.toUpperCase()}${n.slice(1)} directory is unsafe`,detail:`The ${n} directory ${Rd(r.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...r.path?{path:r.path}:{}}))})),{derive:(n)=>{let t=[...n.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 la(n){return Wd.flatMap((t,r)=>t.derive(n).map((e,a)=>({finding:e,catalogOrder:r,occurrence:a}))).sort((t,r)=>aa[t.finding.severity]-aa[r.finding.severity]||t.catalogOrder-r.catalogOrder||t.occurrence-r.occurrence).map((t)=>t.finding)}function t2(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Ad=(n)=>t2()?`\x1B[32m${n}\x1B[0m`:n,Kd=(n)=>t2()?`\x1B[33m${n}\x1B[0m`:n,Vd=(n)=>t2()?`\x1B[34m${n}\x1B[0m`:n,Md=(n)=>t2()?`\x1B[35m${n}\x1B[0m`:n,Gd=(n)=>t2()?`\x1B[36m${n}\x1B[0m`:n,Ud=(n)=>t2()?`\x1B[31m${n}\x1B[0m`:n,Cd=(n)=>t2()?`\x1B[2m${n}\x1B[0m`:n,Od=(n)=>t2()?`\x1B[1m${n}\x1B[0m`:n,b={green:Ad,yellow:Kd,blue:Vd,magenta:Md,cyan:Gd,red:Ud,dim:Cd,bold:Od},Td="\x1B[0m",_d=[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 Ed(n){let t=n;return()=>{return t=(t*1664525+1013904223)%4294967296,t/4294967296}}function Pd(n){let t=[..._d],r=Ed(n);for(let e=t.length-1;e>0;e--){let a=Math.floor(r()*(e+1)),l=t[e];t[e]=t[a],t[a]=l}return t}function Id(n,t=0){if(!t2())return"";let r=Pd(t);return`\x1B[38;5;${r[n%r.length]}m`}function sa(n,t,r=0){if(!t2())return`"${n}"`;return`${Id(t,r)}"${n}"${Td}`}var Nd=new RegExp("\x1B\\[[0-9;]*m","g"),br=(n)=>n.replace(Nd,"").length;function F2(n){let t=(n.headers??n.rows[0]??[]).map((s,d)=>{let c=Math.max(...n.rows.map((L)=>br(L[d]??"")));return Math.max(br(s),c)}),r=(s,d)=>s+" ".repeat(Math.max(0,d-br(s))),e=(s,d)=>d[0]+t.map((c)=>s.repeat(c+2)).join(d[1])+d[2],a=(s)=>`│ ${s.map((d,c)=>r(d,t[c]??0)).join(" │ ")} │`,l=n.headers?[` ${a(n.headers)}`,` ${e("─",["├","┼","┤"])}`]:[];return[` ${e("─",["┌","┬","┐"])}`,...l,...n.rows.map((s)=>` ${a(s)}`),` ${e("─",["└","┴","┘"])}`].join(`
|
|
7
|
+
`)}function da(n){let t=[];t.push("Hook Integration"),t.push(nc(n));let r=[],e=[];for(let a of n){let l=j(a.platform);if(a.errors&&a.errors.length>0)for(let s of a.errors)if(a.configured)r.push({platform:l,message:s});else e.push({platform:l,message:s})}for(let a of r)t.push(` Warning (${a.platform}): ${a.message}`);for(let a of e)t.push(b.red(` Error (${a.platform}): ${a.message}`));return t.join(`
|
|
8
|
+
`)}function nc(n){let t=["Platform","Discovery","Configuration","Inspection"],r=n.map((e)=>{let a=j(e.platform);if(e.inspectionStatus==="not-inspected"){let c=b.dim("Not inspected");return[a,c,c,c]}let l=e.detected?b.green("Detected"):e.inspectionStatus==="failed"?b.red("Unknown"):b.dim("Not detected"),s=e.configured?b.green("Configured"):e.detected?b.yellow("Not configured"):e.inspectionStatus==="failed"?b.red("Unknown"):b.dim("Not applicable"),d=e.inspectionStatus==="verified"?b.green("Verified"):e.inspectionStatus==="failed"?b.red("Failed"):b.dim("Not applicable");return[a,l,s,d]});return F2({headers:t,rows:r})}function ca(n){let r=["Guard Engine Verification",` Synthetic self-test: ${n.failed>0?b.red(`${n.passed}/${n.total} FAIL`):b.green(`${n.passed}/${n.total} passed`)}`],e=n.results.filter((a)=>!a.passed);if(e.length>0){r.push(""),r.push(b.red(" Failures:"));for(let a of e)r.push(b.red(` • ${a.description}`)),r.push(b.red(` expected ${a.expected}, got ${a.actual}`))}return r.join(`
|
|
9
|
+
`)}function tc(n){if(n.length===0)return" (no custom rules)";let t=["Source","Name","Command","Block Args"],r=n.map((e)=>[e.source,e.name,e.subcommand?`${e.command} ${e.subcommand}`:e.command,e.blockArgs.join(", ")]);return F2({headers:t,rows:r})}function La(n){let t=[];if(t.push("Configuration"),t.push(rc(n.userConfig,n.projectConfig)),t.push(""),n.effectiveRules.length>0)t.push(` Effective rules (${n.effectiveRules.length} total):`),t.push(tc(n.effectiveRules));else t.push(" Effective rules: (none - using built-in rules only)");for(let r of n.shadowedRules)t.push(""),t.push(` Note: Project rule "${r.name}" shadows user rule with same name`);return t.join(`
|
|
10
|
+
`)}function rc(n,t){let r=["Scope","Status"],e=(l)=>{if(!l.exists)return b.dim("N/A");if(!l.valid)return b.red(`Invalid (${l.errors?.[0]??"unknown error"})`);return b.green("Configured")},a=[["User",e(n)],["Project",e(t)]];return F2({headers:r,rows:a})}function ia(n){let t=[];return t.push("Environment"),t.push(ec(n)),t.join(`
|
|
11
|
+
`)}function pa(n){let t=["Effective Safety",` Selected preset: ${n.effectiveSafety.selectedPreset}`,` Effective: ${n.effectiveSafety.level}`],r=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[e,a]of r){let l=n.effectiveSafety.capabilities[e],s=l.enabled?b.green("ON"):b.dim("OFF"),d=l.sources.length>0?` (${l.sources.join(", ")})`:"";t.push(` ${a}: ${s} via ${l.source}${d}`)}t.push(` Stored rule customizations: ${n.effectiveSafety.ruleCounts.stored}`),t.push(` Effective rule customizations: ${n.effectiveSafety.ruleCounts.effective}`);for(let[e,a]of Object.entries(n.effectiveSafety.ruleOverrides))t.push(` ${e}: ${a}`);return t.join(`
|
|
12
|
+
`)}function ua(n){let t=["Findings"];if(n.length===0)return t.push(" No findings from inspected doctor facts."),t.join(`
|
|
13
|
+
`);for(let r of n){let e=`[${r.severity.toUpperCase()}] ${r.checkId}: ${J(r.title)}`,a=r.severity==="error"?b.red:r.severity==="warning"?b.yellow:b.blue;if(t.push(` ${a(e)}`),t.push(` ${J(r.detail)}`),r.path)t.push(` Path: ${J(r.path)}`);if(r.fixHint)t.push(` Fix: ${J(r.fixHint)}`)}return t.join(`
|
|
14
|
+
`)}function ec(n){let t=["Variable","Status","Legacy"],r=n.map((e)=>{let a=e.isSet?b.green("✓"):b.dim("✗"),l=e.legacyName&&e.legacyIsSet?`${e.legacyName} ${b.green("✓")}`:e.legacyName??"";return[e.name,a,l]});return F2({headers:t,rows:r})}function va(n){let t=[];if(n.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 (${n.totalBlocked} blocked / ${n.sessionCount} sessions)`),t.push(ac(n.recentEntries));if(n.unreadable>0)t.push(` Warning: ${n.unreadable} audit log ${n.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return t.join(`
|
|
15
|
+
`)}function ac(n){let t=["Time","Command"],r=n.map((e)=>{let a=J(e.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),l=a.length>40?`${a.slice(0,37)}...`:a;return[e.relativeTime,l]});return F2({headers:t,rows:r})}function oa(n){let t=[];if(t.push("Update Check"),n.latestVersion===null&&!n.error)return t.push(On([["Status",b.dim("Skipped")],["Installed",n.currentVersion]])),t.join(`
|
|
16
|
+
`);if(n.error)return t.push(On([["Status",`${b.yellow("⚠")} Error`],["Installed",n.currentVersion],["Error",b.dim(n.error)]])),t.join(`
|
|
17
|
+
`);if(n.updateAvailable)return t.push(On([["Status",`${b.yellow("⚠")} Update Available`],["Current",n.currentVersion],["Latest",b.green(n.latestVersion??"")]])),t.push(""),t.push(" Run: bunx cc-safety-net@latest doctor"),t.push(" Or: npx cc-safety-net@latest doctor"),t.join(`
|
|
18
|
+
`);return t.push(On([["Status",`${b.green("✓")} Up to date`],["Version",n.currentVersion]])),t.join(`
|
|
19
|
+
`)}function On(n){return F2({rows:n})}function ba(n){let t=[];return t.push("System Info"),t.push(lc(n)),t.join(`
|
|
20
|
+
`)}function lc(n){let t=["Component","Version"],r=(l)=>{if(l===null)return b.dim("not found");return l},a=[{label:"cc-safety-net",value:n.version},...Gn.map((l)=>({label:j(l),value:n.versions[l]??null})),{label:"Node.js",value:n.nodeVersion},{label:"npm",value:n.npmVersion},{label:"Bun",value:n.bunVersion},{label:"Platform",value:n.platform}].map((l)=>[l.label,r(l.value)]);return F2({headers:t,rows:a})}function fa(n){if(n.findings.length===0)return b.green(`
|
|
21
|
+
No findings from inspected doctor facts.`);let t={error:n.findings.filter((l)=>l.severity==="error").length,warning:n.findings.filter((l)=>l.severity==="warning").length,info:n.findings.filter((l)=>l.severity==="info").length},r=["error","warning","info"].filter((l)=>t[l]>0).map((l)=>`${t[l]} ${l}`),e=n.findings.length===1?"finding":"findings",a=`
|
|
22
|
+
${n.findings.length} ${e}: ${r.join(", ")}.`;if(t.error>0)return b.red(a);if(t.warning>0)return b.yellow(a);return b.blue(a)}import{lstatSync as sc}from"node:fs";import{dirname as fr}from"node:path";function yr(n,t){try{let r=sc(t);if(r.isSymbolicLink())return{kind:n,path:t,status:"unsafe",issues:["symlink"]};if(!r.isDirectory())return{kind:n,path:t,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:n,path:t,status:"unknown",issues:[]};let e=[...r.uid!==process.getuid()?["ownership"]:[],...(r.mode&18)!==0?["permissions"]:[]];return{kind:n,path:t,status:e.length>0?"unsafe":"safe",issues:e}}catch(r){if(typeof r==="object"&&r!==null&&"code"in r&&r.code==="ENOENT")return{kind:n,path:t,status:"not-applicable",issues:[]};return{kind:n,path:t,status:"unknown",issues:[]}}}function ya(n){let t=L2();return{directories:[yr("policy",fr(fr(n))),yr("config",fr(n)),...t?[yr("audit",t)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as dc}from"node:child_process";import{existsSync as ha}from"node:fs";import{delimiter as cc,extname as Lc,join as ic}from"node:path";import{stripVTControlCharacters as wa}from"node:util";var $a="2.0.7",pc=5000,uc="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function F(){return $a}function hr(n,t){let r=n[t];if(r)return r;let e=Object.keys(n).find((a)=>a.toLowerCase()===t.toLowerCase()&&!!n[a]);return e?n[e]:r}function vc(n){return(hr(n,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((t)=>t.length>0)}function oc(n,t){let r=Lc(n)?[n]:[...vc(t).map((e)=>`${n}${e}`),n];if(n.includes("/")||n.includes("\\"))return r.find((e)=>ha(e))??n;return(hr(t,"PATH")??"").split(cc).flatMap((e)=>r.map((a)=>ic(e,a))).find((e)=>ha(e))??n}function xa(n){if(!/[\s"&|<>^]/.test(n))return n;return`"${n.replace(/"/g,'""')}"`}function h2(n,t){let[r,...e]=n,a=t[uc]==="win32"?"win32":process.platform;if(!r||a!=="win32")return{cmd:r??"",args:e};let l=oc(r,t);if(!/\.(?:bat|cmd)$/i.test(l))return{cmd:l,args:e};return{cmd:hr(t,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",xa(l),...e.map(xa)].join(" ")]}}var E2=async(n,t=pc)=>{let r=await bc(n,{timeoutMs:t});if(r.code!==0)return null;return wa(r.stdout).trim()||wa(r.stderr).trim()||null};function bc(n,t){let[r,...e]=n;if(!r)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((a)=>{try{let l=h2([r,...e],process.env),s=dc(l.cmd,l.args,{stdio:["ignore","pipe","pipe"]}),d=!1,c="",L="";s.stdout.on("data",(o)=>{c+=o.toString()}),s.stderr.on("data",(o)=>{L+=o.toString()});let i=(o)=>{if(d)return;d=!0,clearTimeout(u),a(o)},u=setTimeout(()=>{s.kill(),i({code:null,stdout:c,stderr:L})},t.timeoutMs);s.on("close",(o)=>{i({code:o,stdout:c,stderr:L})}),s.on("error",()=>{i({code:null,stdout:c,stderr:L})})}catch{a({code:null,stdout:"",stderr:""})}})}function Tn(n){if(!n)return null;let t=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(n);if(t)return t[1]??null;let r=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(n);if(r)return r[1]??null;return n.split(`
|
|
23
|
+
`)[0]?.trim()||null}async function $n(n=E2){let[t,r,e,a,l,s]=await Promise.all([Promise.all(M.map(async(d)=>[d.id,Tn(await n([...d.probeCommand]))])),n(["codex","plugin","list"],30000),n(["amp","plugins","list"],30000),n(["node","--version"]),n(["npm","--version"]),n(["bun","--version"])]);return{version:$a,versions:Object.fromEntries(t),codexPluginListOutput:r,ampPluginListOutput:e,nodeVersion:Tn(a),npmVersion:Tn(l),bunVersion:Tn(s),platform:`${process.platform} ${process.arch}`}}function wr(n,t){if(t==="dev")return!1;let r=n.split(".").map(Number),e=t.split(".").map(Number),[a=0,l=0,s=0]=r,[d=0,c=0,L=0]=e;if(a!==d)return a>d;if(l!==c)return l>c;return s>L}async function P2(){let n=F(),t=new AbortController,r=setTimeout(()=>t.abort(),3000);try{let e=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:t.signal});if(!e.ok)return{currentVersion:n,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${e.status}`};let a=await e.json(),l=wr(a.version,n);return{currentVersion:n,latestVersion:a.version,updateAvailable:l}}catch(e){return{currentVersion:n,latestVersion:null,updateAvailable:!1,error:e instanceof Error?e.message:"Network error"}}finally{clearTimeout(r)}}import*as Fa from"node:readline";var ka=(n)=>`\x1B[${n}B`,fc=(n)=>`\x1B[${n}A`;var ma=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function yc(n){return new Promise((t)=>setTimeout(t,n))}function hc(n,t,r){if(!r)return t(n);if(r.aborted)return Promise.resolve();return new Promise((e,a)=>{let l=()=>r.removeEventListener("abort",s),s=()=>{l(),e()};r.addEventListener("abort",s,{once:!0}),t(n).then(()=>{l(),e()},(d)=>{l(),a(d)})})}function mn(n,t){return n&&n>0?n:t}function _n(n){return Math.max(0,Math.min(1,n))}function I2(n){return Math.max(0,Math.min(255,Math.round(n)))}function xr(n){return n<=0.0031308?12.92*n:1.055*n**0.4166666666666667-0.055}function wc(n,t,r){let e=r*Math.PI/180,a=t*Math.cos(e),l=t*Math.sin(e),s=(n+0.3963377774*a+0.2158037573*l)**3,d=(n-0.1055613458*a-0.0638541728*l)**3,c=(n-0.0894841775*a-1.291485548*l)**3;return{blue:I2(xr(_n(-0.0041960863*s-0.7034186147*d+1.707614701*c))*255),green:I2(xr(_n(-1.2684380046*s+2.6097574011*d-0.3413193965*c))*255),red:I2(xr(_n(4.0767416621*s-3.3077115913*d+0.2309699292*c))*255)}}function $r(n,t){let r=(t*n*180/Math.PI%360+360)%360;return wc(0.72,0.15,r)}function qa(n,t=0.1){let r=$r(t,n);return`\x1B[38;2;${r.red};${r.green};${r.blue}m`}function xc(n,t){return{blue:I2(n.blue+(255-n.blue)*t),green:I2(n.green+(255-n.green)*t),red:I2(n.red+(255-n.red)*t)}}function ja(n,t,r){let e=Math.imul(n+2654435769,2246822507)^Math.imul(t+3266489909,668265263)^Math.imul(r+374761393,2654435761),a=e^e>>>15,l=Math.imul(a,739982445),s=l^l>>>12,d=Math.imul(s,695872825);return((d^d>>>15)>>>0)/4294967296}function $c(n,t,r){let e=Math.floor(ja(n,t,r)*ma.length);return ma[e]??"░"}function ga(n){let t=_n(n);return t*t*t*(t*(t*6-15)+10)}function mc(n){if(n.length===0)return"";let t=[],r=!1,e="";for(let a of n){let l=`${a.red};${a.green};${a.blue}`;if(a.bold!==r)t.push(a.bold?"\x1B[1m":"\x1B[22m"),r=a.bold;if(l!==e)t.push(`\x1B[38;2;${l}m`),e=l;t.push(a.character)}return`${t.join("")}\x1B[22m\x1B[39m`}function gc(n,t,r,e,a){return n.map((l,s)=>({...$r(r,e+t+s/a),bold:!1,character:l}))}function Dc(n,t,r,e,a,l,s,d){let c=Math.max(1,e*0.75),L=Math.min(1,r/c),i=a*ga(L),u=Math.max(0,(r-c)/Math.max(1,e-c)),o=(1-ga(r/e))*d*2,p=0.35*Math.max(0,1-u*2),f=L>=1,v=Math.min(n.length,Math.ceil(i+2+1));return n.slice(0,v).map((h,w)=>{let $=$r(l,s+t+w/d+o),y=w+ja(t,w,7919)*2-1;if(y>i+2)return{...$,bold:!1,character:" "};let g=i-y,S=0.8*Math.exp(-(g*g)/12.5),b2=Math.min(0.9,S+p),Jt=!f&&y>i-4;return{...xc($,b2),bold:b2>0.3,character:Jt?$c(t,w,r):h}})}function Da(n){return`\x1B[?2026h${n.map((t,r)=>`\x1B8${r>0?ka(r):""}${mc(t)}`).join("")}\x1B[?2026l`}async function mr(n,t={}){if(!n)return;let r=t.output??process.stdout,e=t.sleep??yc,a=mn(t.frequency,0.1),l=t.seed??0,s=mn(t.speed,40),d=mn(t.spread,3),c=mn(t.frameRate,60),L=Math.max(1,Math.floor(mn(t.duration,12))),i=n.split(`
|
|
24
|
+
`).map((v)=>Array.from(v)),u=Math.max(...i.map((v)=>v.length)),o=1000*L*i.filter((v)=>v.length>0).length/s,p=u>0?Math.max(1,Math.ceil(o/(1000/c))):0,f=p>0?o/p:0;r.write(`\x1B[?25l${i.length>1?`${`
|
|
25
|
+
`.repeat(i.length-1)}${fc(i.length-1)}`:""}\x1B7`);try{for(let v=1;v<=p;v+=1){if(t.signal?.aborted)break;r.write(Da(i.map((h,w)=>Dc(h,w,v,p,u,a,l,d)))),await hc(f,e,t.signal)}}finally{if(r.write(Da(i.map((v,h)=>gc(v,h,a,l,d)))),r.write("\x1B8"),i.length>1)r.write(ka(i.length-1));r.write(`
|
|
26
|
+
\x1B[0m\x1B[?25h`)}}var za=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
|
|
27
|
+
`);function kc(n){return Boolean(n.isTTY)}async function gn(n={}){let t=n.output??process.stdout;if(!kc(t))return;let r=n.input??process.stdin,e={duration:n.duration,frequency:n.frequency,output:t,seed:n.seed??Math.random()*8192,sleep:n.sleep,speed:n.speed,spread:n.spread};if(!r.isTTY||typeof r.setRawMode!=="function"){await mr(za,e);return}let a=new AbortController,l=r.readableFlowing===!0,s=r.isRaw===!0,d=!1,c=(L,i)=>{if(i.ctrl&&i.name==="c")d=!0;if(d||i.name==="return"||i.name==="enter")a.abort()};Fa.emitKeypressEvents(r),r.on("keypress",c),r.setRawMode(!0),r.resume();try{await mr(za,{...e,signal:a.signal})}finally{if(r.off("keypress",c),r.setRawMode(s),!l)r.pause()}if(!d)return;if(n.onInterrupt){n.onInterrupt();return}process.kill(process.pid,"SIGINT")}var Ba="\r\x1B[2K",qc="\x1B[?25l",jc="\x1B[39m",zc="\x1B[?25h",Fc=100,Bc=0.55,Jc=80,Ja=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Zc(n){return new Promise((t)=>setTimeout(t,n))}async function En(n,t={}){let r=t.output??process.stdout;if(!r.isTTY)return n;let e=t.sleep??Zc,a=!1,l=n.then((d)=>{return a=!0,d},(d)=>{throw a=!0,d});if(await Promise.race([l.then(()=>!0),e(Fc).then(()=>!1)]))return l;r.write(qc);try{for(let d=0;!a;d+=1)r.write(`${Ba}${qa(d*Bc)}${Ja[d%Ja.length]}${jc} ${t.loadingMessage??"Loading…"}`),await Promise.race([l,e(Jc)]);return await l}finally{r.write(`${Ba}${zc}`)}}async function Dn(n,t,r,e={}){let a=t();if(n)await r();if(n&&a.ready)await En(a.ready,e);return a.finish()}import{homedir as ni}from"node:os";import{stripVTControlCharacters as Qc}from"node:util";var Pn="amp plugins list",Xc=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Za(n){if(!n.ampPluginListOutput)return{platform:"amp",status:"n/a"};let t=Qc(n.ampPluginListOutput).split(`
|
|
28
|
+
`).map((r)=>Xc.exec(r)?.[1]).find((r)=>r!==void 0);if(!t)return{platform:"amp",status:"n/a"};if(t!=="active")return{platform:"amp",status:"disabled",method:Pn,configPath:Pn,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:Pn,configPath:Pn}}import{existsSync as Sc,readFileSync as Hc}from"node:fs";import{join as Yc}from"node:path";function kn(n){return Yc(n,".gemini","config","hooks.json")}var Rc=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Wc(n){if(!n||typeof n!=="object"||Array.isArray(n))return[];return Object.values(n).flatMap((t)=>{if(!t||typeof t!=="object"||Array.isArray(t))return[];let r=t,e=r.PreToolUse;if(!Array.isArray(e))return[];return e.flatMap((a)=>{if(!a||typeof a!=="object"||Array.isArray(a))return[];let l=a.hooks;if(!Array.isArray(l))return[];return l.flatMap((s)=>{if(!s||typeof s!=="object"||Array.isArray(s))return[];let d=s.command;if(typeof d!=="string"||!Rc.test(d))return[];return[{command:d,enabled:r.enabled!==!1}]})})})}function Qa(n){let t=kn(n.homeDir);if(!Sc(t))return{platform:"antigravity-cli",status:"n/a",configPath:t};let r;try{r=Wc(JSON.parse(Hc(t,"utf-8")))}catch(e){return{platform:"antigravity-cli",status:"n/a",configPath:t,errors:[`Failed to parse Antigravity hooks config ${t}: ${e instanceof Error?e.message:String(e)}`]}}if(r.some((e)=>e.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:t};if(r.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 Xa}from"node:path";import{existsSync as Ac,lstatSync as Kc,readFileSync as Vc}from"node:fs";function r2(n,t=(r)=>r){if(!Ac(n))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(t(Vc(n,"utf-8")))}}catch{return{kind:"unreadable"}}}function W(n){try{return Kc(n)}catch{return}}function In(n,t){let r=W(t);if(!r)return{platform:n,status:"n/a",configPath:t};if(!r.isSymbolicLink()&&r.isDirectory())return;return{platform:n,status:"n/a",configPath:t,errors:[`${t} is a symlink or not a directory; move or remove it before installing`]}}function x(n,t){return typeof n==="object"&&n!==null?n[t]:void 0}var gr="cc-safety-net@cc-marketplace";function Ya(n){return Xa(n,".claude","plugins","installed_plugins.json")}function Sa(n,t){let r=x(x(n,"plugins"),t);return Array.isArray(r)&&r.length>0}function Nn(n,t){let r=r2(Ya(n));return r.kind==="ok"&&Sa(r.value,t)}function Dr(n){let t=Ya(n),r=r2(t);if(r.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(r.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Sa(r.value,gr))return{platform:"claude-code",status:"n/a"};let e=Xa(n,".claude","settings.json"),a=r2(e);if(a.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(a.kind==="ok"&&x(x(a.value,"enabledPlugins"),gr)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:e,errors:[`${gr} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:t}}function Ha(n){return Dr(n.homeDir)}function Ra(n){if(!n.codexPluginListOutput)return{platform:"codex",status:"n/a"};let t=n.codexPluginListOutput.split(`
|
|
29
|
+
`).find((r)=>r.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 rt,readdirSync as Mc,readFileSync as Gc}from"node:fs";import{join as Y}from"node:path";var e2="cc-safety-net@cc-marketplace",nt=["cc-marketplace","cc-safety-net"],Wa=["_direct","copilot-safety-net"],Aa=["cc-marketplace","safety-net"],Ka="safety-net@cc-marketplace";function tt(n,t){let r=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${r}([^a-z0-9-]|$)`,"m").test(n??"")}function Va(n){return tt(n,"cc-safety-net@cc-marketplace")}function Ma(n){return tt(n,"cc-marketplace")}function Ga(n){return tt(n,"copilot-safety-net")}function Ua(n){return tt(n,"safety-net@cc-marketplace")}function V(n){let t="",r=0,e=!1,a=!1,l=-1;while(r<n.length){let s=n[r],d=n[r+1];if(a){t+=s,a=!1,r++;continue}if(s==='"'&&!e){e=!0,l=-1,t+=s,r++;continue}if(s==='"'&&e){e=!1,t+=s,r++;continue}if(s==="\\"&&e){a=!0,t+=s,r++;continue}if(e){t+=s,r++;continue}if(s==="/"&&d==="/"){while(r<n.length&&n[r]!==`
|
|
30
|
+
`)r++;continue}if(s==="/"&&d==="*"){r+=2;while(r<n.length-1){if(n[r]==="*"&&n[r+1]==="/"){r+=2;break}r++}continue}if(s===","){l=t.length,t+=s,r++;continue}if(s==="}"||s==="]"){if(l!==-1){let c=t.slice(l+1);if(/^\s*$/.test(c))t=t.slice(0,l)+c}l=-1,t+=s,r++;continue}if(!/\s/.test(s))l=-1;t+=s,r++}return t}function kr(n){if(!n?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(n)}function Oa(n,t){if(!n)return null;let r=n.match(/(\d+)\.(\d+)\.(\d+)/);if(!r)return null;let e=[Number(r[1]),Number(r[2]),Number(r[3])];for(let a=0;a<t.length;a++){let l=e[a]??0,s=t[a]??0;if(l!==s)return l>s}return!0}function Uc(n){return Oa(n,[0,0,422])}function Cc(n){return Oa(n,[1,0,8])}function qn(n){return process.env.COPILOT_HOME||Y(n,".copilot")}function qr(n){return(n.hooks?.preToolUse??[]).some((r)=>{if(r.type!=="command")return!1;return kr(r.command)||kr(r.bash)||kr(r.powershell)})}function jr(n,t){try{return JSON.parse(V(Gc(n,"utf-8")))}catch(r){t?.push(`Failed to parse ${n}: ${r instanceof Error?r.message:String(r)}`);return}}function Ta(n,t){try{return Mc(n).filter((r)=>r.endsWith(".json")).sort((r,e)=>r.localeCompare(e))}catch(r){return t?.push(`Failed to read ${n}: ${r instanceof Error?r.message:String(r)}`),[]}}function Oc(n,t){if(!rt(n))return[];let r=[];for(let e of Ta(n,t)){let a=Y(n,e),l=jr(a,t);if(l&&qr(l))r.push(a)}return r}function N2(n,t){if(!rt(n))return;let r=jr(n,t);if(!r)return;return{path:n,config:r}}function Ca(n,t,r,e){if(t){n.push(`GitHub Copilot CLI ${t} does not support ${r}; requires ${e}+`);return}n.push(`GitHub Copilot CLI version unavailable; skipping ${r} because it requires ${e}+`)}function Tc(n){for(let t of n){if(t?.config.disableAllHooks===!0)return t.path;if(t?.config.disableAllHooks===!1)return}return}function _c(n,t,r,e){let a=qn(n),l=Y(t,".github","hooks"),s=Y(a,"hooks"),d=Y(t,".github","copilot"),c=Y(t,".claude"),L=Cc(r),i=L===!0?e:void 0,u=[N2(Y(d,"settings.local.json"),i),N2(Y(d,"settings.json"),i),N2(Y(c,"settings.local.json"),i),N2(Y(c,"settings.json"),i)],o=[N2(Y(a,"settings.json"),i),N2(Y(a,"config.json"),i)];if(L!==!1){let g=Tc([...u,...o]);if(g){if(L===null)e.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${g} as active`);return{activeConfigPaths:[],disabledBy:g}}}let p=Oc(l,e),f=Uc(r),v=f===!0?e:void 0,h=rt(s)?Ta(s,v):[],w=[];for(let g of h){let S=Y(s,g),b2=jr(S,v);if(b2&&qr(b2))w.push(S)}if(f!==!0&&w.length>0)Ca(e,r,`user hook files in ${s}`,"0.0.422"),w.length=0;let $=[];for(let g of[...u,...o]){if(!g)continue;if(!qr(g.config))continue;if(L===!0){$.push(g);continue}Ca(e,r,"inline hook definitions in Copilot config files","1.0.8");break}let y=(g)=>g.filter((S)=>!!S&&$.includes(S)).map((S)=>S.path);return{activeConfigPaths:[...y(u),...p,...y(o),...w]}}function _a(n){let t=[],r=_c(n.homeDir,n.cwd,n.copilotCliVersion,t);if(r.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:r.disabledBy,configPaths:[r.disabledBy],errors:t.length>0?t:void 0};let e=qn(n.homeDir),a=Y(e,"installed-plugins",...nt),l=rt(a),s=Y(e,"settings.json"),d=r2(s,V);if(l&&d.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(l&&d.kind==="ok"&&x(x(d.value,"enabledPlugins"),e2)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:s,errors:[`${e2} is installed but not enabled in Copilot CLI`]};if(l||r.activeConfigPaths.length>0){let c=l,L=r.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:c?"plugin config":"hook config",configPath:L??(c?a:void 0),configPaths:r.activeConfigPaths.length>0?r.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 lL,readFileSync as sL}from"node:fs";import{existsSync as Ea,mkdirSync as Ic,readFileSync as Nc}from"node:fs";import{dirname as nL,join as tL}from"node:path";import{renameSync as Ec,writeFileSync as Pc}from"node:fs";function Z(n,t){let r=`${n}.${process.pid}.tmp`;Pc(r,t),Ec(r,n)}var jn="npx -y cc-safety-net hook --cursor",Pa=30;function at(n){return tL(n,".cursor","hooks.json")}function B2(n){return typeof n==="object"&&n!==null&&!Array.isArray(n)}function zr(){return{command:jn,timeout:Pa,failClosed:!0}}function et(n){return B2(n)&&n.command===jn}function rL(n){return Object.keys(n).length===3&&n.command===jn&&n.timeout===Pa&&n.failClosed===!0}function eL(n){try{return JSON.parse(Nc(n,"utf-8"))}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${n}: ${t.message}`);throw t}}function Ia(n){let t=eL(n);if(!B2(t))throw Error(`Cursor hooks config ${n} must be a JSON object`);if(t.version!==1)throw Error(`Cursor hooks config ${n} must set "version": 1`);if(t.hooks!==void 0&&!B2(t.hooks))throw Error(`Cursor hooks config ${n} "hooks" must be an object`);let r=B2(t.hooks)?t.hooks.preToolUse:void 0;if(r!==void 0&&!Array.isArray(r))throw Error(`Cursor hooks config ${n} "hooks.preToolUse" must be an array`);return t}function Na(n){let t=B2(n.hooks)?n.hooks.preToolUse:void 0;return Array.isArray(t)?t:[]}function aL(n){if(!n.some(et))return[...n,zr()];return n.reduce((t,r)=>{if(!et(r))return t.result.push(r),t;if(!t.inserted)t.result.push(zr()),t.inserted=!0;return t},{result:[],inserted:!1}).result}function n0(n,t,r){let e=B2(t.hooks)?t.hooks:{},a={...t,hooks:{...e,preToolUse:r}};Z(n,`${JSON.stringify(a,null,2)}
|
|
31
|
+
`)}function t0(n){let t=at(n);if(!Ea(t))return Ic(nL(t),{recursive:!0}),Z(t,`${JSON.stringify({version:1,hooks:{preToolUse:[zr()]}},null,2)}
|
|
32
|
+
`),{path:t,alreadyInstalled:!1};let r=Ia(t),e=Na(r),a=e.filter(et);if(B2(r.hooks)&&Array.isArray(r.hooks.preToolUse)&&a.length===1&&a[0]!==void 0&&rL(a[0]))return{path:t,alreadyInstalled:!0};return n0(t,r,aL(e)),{path:t,alreadyInstalled:!1}}function r0(n){let t=at(n);if(!Ea(t))return{path:t,alreadyInstalled:!1};let r=Ia(t),e=Na(r),a=e.filter((l)=>!et(l));if(a.length===e.length)return{path:t,alreadyInstalled:!1};return n0(t,r,a),{path:t,alreadyInstalled:!0}}function dL(n){if(!n||typeof n!=="object"||Array.isArray(n))return[];let t=n.hooks;if(!t||typeof t!=="object"||Array.isArray(t))return[];let r=t.preToolUse;if(!Array.isArray(r))return[];return r.filter((e)=>!!e&&typeof e==="object"&&!Array.isArray(e)&&e.command===jn)}function cL(n){let t=[];if(n.length>1)t.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let r=n[0];if(r&&r.failClosed!==!0)t.push('Managed hook is missing "failClosed": true; reinstall to repair');if(r&&r.timeout!==30)t.push('Managed hook "timeout" is not 30; reinstall to repair');return t}function e0(n){let t=at(n.homeDir);if(!lL(t))return{platform:"cursor",status:"n/a",configPath:t};let r;try{r=JSON.parse(sL(t,"utf-8"))}catch(l){return{platform:"cursor",status:"n/a",configPath:t,errors:[`Failed to parse Cursor hooks config ${t}: ${l instanceof Error?l.message:String(l)}`]}}let e=dL(r);if(e.length===0)return{platform:"cursor",status:"n/a",configPath:t};let a=cL(e);return{platform:"cursor",status:"configured",method:"hook config",configPath:t,errors:a.length>0?a:void 0}}import{existsSync as LL}from"node:fs";import{join as Fr}from"node:path";var Br="gemini-safety-net";function Jr(n){let t=Fr(n,".gemini","extensions"),r=Fr(t,Br);if(!LL(r))return{platform:"gemini-cli",status:"n/a"};let e=Fr(t,"extension-enablement.json"),a=r2(e);if(a.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let l=a.kind==="ok"?x(x(a.value,Br),"overrides"):void 0;if(Array.isArray(l)&&l.some((d)=>typeof d==="string"&&d.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:e,errors:[`${Br} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:r}}function a0(n){return Jr(n.homeDir)}import{readFileSync as v0}from"node:fs";import{join as o0}from"node:path";var G="cc-safety-net",l0="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent";function s0(n){return`# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent
|
|
33
33
|
# version: ${n}
|
|
34
|
-
`}function
|
|
34
|
+
`}function iL(n){return`${s0(n)}name: cc-safety-net
|
|
35
35
|
version: "${n}"
|
|
36
36
|
description: "Block destructive commands and secret-file access before Hermes runs a tool."
|
|
37
37
|
author: "cc-safety-net"
|
|
38
38
|
provides_hooks:
|
|
39
39
|
- pre_tool_call
|
|
40
|
-
`}function
|
|
40
|
+
`}function pL(n){return`${s0(n)}"""CC Safety Net guard for Hermes Agent.
|
|
41
41
|
|
|
42
42
|
Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
|
|
43
43
|
adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
|
|
@@ -70,12 +70,18 @@ def _terminal_cwd(task_id, process_cwd):
|
|
|
70
70
|
\`workdir or get_session_cwd(session_key) or default_cwd\`, and that record is rewritten
|
|
71
71
|
after every completed command, so it IS the session's \`cd\` state. The session key is
|
|
72
72
|
derived exactly as terminal_tool derives it: the contextvar when set, the raw task_id
|
|
73
|
-
otherwise. No record yet (first command of a session) means the
|
|
73
|
+
otherwise. No record yet (first command of a session) means \`default_cwd\`, which the local
|
|
74
|
+
terminal backend reads from \`TERMINAL_CWD\` (\`hermes_cli/config.py\` bridges the configured
|
|
75
|
+
\`terminal.cwd\` into it) and only then falls back to the process directory.
|
|
74
76
|
"""
|
|
75
77
|
from tools.approval import get_current_session_key
|
|
76
78
|
from tools.terminal_tool import get_session_cwd
|
|
77
79
|
|
|
78
|
-
return
|
|
80
|
+
return (
|
|
81
|
+
get_session_cwd(get_current_session_key(default="") or (task_id or ""))
|
|
82
|
+
or os.environ.get("TERMINAL_CWD")
|
|
83
|
+
or process_cwd
|
|
84
|
+
)
|
|
79
85
|
|
|
80
86
|
|
|
81
87
|
def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
@@ -169,83 +175,84 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
169
175
|
|
|
170
176
|
def register(ctx):
|
|
171
177
|
ctx.register_hook("pre_tool_call", _pre_tool_call)
|
|
172
|
-
`}function
|
|
173
|
-
`)}function
|
|
174
|
-
`),c=t?.timeoutMs??120000,
|
|
175
|
-
${
|
|
176
|
-
${s()}`.trim())))}),l.on("close",(L)=>{if(clearTimeout(i),L!==0){r(Error(Ye(n,L,s())));return}e(t?.stdoutOnly?d.stdout:s())})})}async function He(n){for(let t of n)await e2(t)}async function v0(n){for(let t of n)try{await e2(t)}catch(e){console.warn(e instanceof Error?e.message:String(e))}}var b0=j2("openclaw",q),mi=[V,I2,N2];function h0(n){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return t;let e=process.env.OPENCLAW_CONFIG_PATH?.trim();return e?f0(e):j2(n,".openclaw")}function y0(n){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?t:j2(h0(n),"openclaw.json")}function Ae(n){return j2(h0(n),"extensions",q)}function ki(n){let t=$i(n);if(t.length===0)return!0;if(t.some((a)=>!mi.includes(a)))return!1;let e=j2(n,V),r=S(e);return r!==void 0&&!r.isSymbolicLink()&&r.isFile()&&gi(e,"utf-8").startsWith(at)}function We(n){let t=Ae(n),e=S(t);if(!e)return;if(!e.isSymbolicLink()&&e.isDirectory()&&ki(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 w0(){let n=f0(Di(import.meta.url));return[j2(n,"..",b0),j2(n,"..","..","..","dist",b0)]}function Re(n=w0()){return n.find((t)=>wi(t)&&xi(t).isDirectory())}function qi(n=w0()){let t=Re(n);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function x0(n=qi()){return[["openclaw","plugins","install",n,"--force"],["openclaw","plugins","enable",q]]}function ji(n){let t=(()=>{try{return JSON.parse(n)}catch{return}})(),e=$($(t,"plugin"),"status");return typeof e==="string"?e:void 0}async function $0(){let n=ji(await e2(["openclaw","plugins","inspect",q,"--runtime","--json"],{stdoutOnly:!0}));if(n==="loaded")return;throw Error(`${n===void 0?`The ${q} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${q} plugin with status "${n}".`} Run \`openclaw plugins inspect ${q} --runtime\` for details.`)}var lt="openclaw",zn=`run \`openclaw plugins enable ${q}\``;function nn(n,t){let e=Bn(n,t),r=S(e);if(!r)return{error:`${t} is missing from ${e}; run install --openclaw`};if(r.isSymbolicLink()||!r.isFile())return{error:`${e} is a symlink or not a regular file; move or remove it`};try{return{content:D0(e,"utf-8")}}catch(a){return{error:`Failed to read ${e}: ${a instanceof Error?a.message:String(a)}`}}}function m0(n){try{return JSON.parse(R(n))}catch{return}}function Fi(n){let t=nn(n,I2);if("error"in t)return t.error;if($(m0(t.content),"id")===q)return;return`${Bn(n,I2)} is not a valid ${q} manifest; run install --openclaw`}function zi(n){let t=nn(n,N2);if("error"in t)return t.error;let e=$($(m0(t.content),"openclaw"),"extensions");if(Array.isArray(e)&&e.includes(`./${V}`))return;return`${Bn(n,N2)} does not point OpenClaw at ${V}; run install --openclaw`}function g0(n){return Array.isArray(n)?n.filter((t)=>typeof t==="string"):[]}function Bi(n){let t=y0(n);if(!S(t))return`${q} is not enabled; ${zn}`;let e=(()=>{try{return JSON.parse(R(D0(t,"utf-8")))}catch{return}})();if(e===void 0)return`Failed to read ${t}; fix it, then ${zn}`;let r=$(e,"plugins");if($(r,"enabled")===!1)return`plugins.enabled is false in ${t}; no OpenClaw plugin loads`;let a=$($($(r,"entries"),q),"enabled");if(g0($(r,"deny")).includes(q)||a===!1)return`${q} is disabled in ${t}; ${zn}`;let l=g0($(r,"allow"));if(l.length>0&&!l.includes(q))return`plugins.allow in ${t} does not list ${q}; add it, then ${zn}`;if(l.includes(q)||a===!0)return;return`${q} is not enabled; ${zn}`}function k0(n){return/^\/\/ version:\s*(.+)$/m.exec(n)?.[1]?.trim()}function Ji(n,t,e){if(e===void 0)return[];let r=nn(e,V);if("error"in r||k0(r.content)!==t)return[];return[V,I2,N2].flatMap((a)=>{let l=nn(n,a),d=nn(e,a);if("error"in l||"error"in d||l.content===d.content)return[];return[`Modified ${a} occupies ${Bn(n,a)}; run install --openclaw to restore it`]})}function q0(n){let t=Ae(n.homeDir),e=En(lt,t);if(e)return e;let r=nn(t,V),l=["error"in r?r.error:r.content.startsWith(at)?void 0:`Unmanaged ${V} occupies ${Bn(t,V)}; move or remove it`,Fi(t),zi(t)].filter((L)=>L!==void 0),d="content"in r?k0(r.content):void 0,s=l.length>0?l:Ji(t,d,Re());if(s.length>0)return{platform:lt,status:"n/a",configPath:t,errors:s};let c=d===j()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],i=Bi(n.homeDir);if(i)return{platform:lt,status:"disabled",method:"plugin directory",configPath:t,errors:[i,...c]};return{platform:lt,status:"configured",method:"plugin directory",configPath:t,errors:c.length>0?c:void 0}}import{existsSync as Zi,readFileSync as Qi}from"node:fs";import{join as j0}from"node:path";function F0(n){let t=[],e=j0(n.homeDir,".config","opencode"),r=["opencode.json","opencode.jsonc"];for(let a of r){let l=j0(e,a);if(Zi(l))try{let d=Qi(l,"utf-8"),s=R(d);if((JSON.parse(s).plugin??[]).some((u)=>u.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:l,errors:t.length>0?t:void 0}}catch(d){t.push(`Failed to parse ${a}: ${d instanceof Error?d.message:String(d)}`)}}return{platform:"opencode",status:"n/a",errors:t.length>0?t:void 0}}import{join as Xi}from"node:path";function Ke(n){return Xi(n,".pi","agent","settings.json")}function Me(n){if(typeof n!=="string")return!1;return n==="npm:cc-safety-net"||n.startsWith("npm:cc-safety-net@")}function z0(n){let t=Ke(n.homeDir),e=n2(t);if(e.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(e.kind==="missing")return{platform:"pi",status:"n/a"};let r=$(e.value,"packages");if(!Array.isArray(r))return{platform:"pi",status:"n/a"};let a=r.find((s)=>Me(typeof s==="string"?s:$(s,"source")));if(a===void 0)return{platform:"pi",status:"n/a"};let l=$(a,"extensions");if(Array.isArray(l)&&l.some((s)=>typeof s==="string"&&s.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 Si={amp:Fa,"antigravity-cli":za,"claude-code":Qa,codex:Xa,"copilot-cli":Ca,cursor:Na,"gemini-cli":n0,"hermes-agent":u0,"kimi-code":Fn,openclaw:q0,opencode:F0,pi:z0};function tn(n,t){let e={...t,cwd:n,homeDir:t?.homeDir??Yi()};return j1.map((r)=>Hi(Si[r](e)))}function Hi(n){if(n.status==="not-inspected")return{platform:n.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:n.platform,detected:n.status!=="n/a",configured:n.status==="configured",inspectionStatus:n.status!=="n/a"?"verified":n.errors&&n.errors.length>0?"failed":"not-applicable",method:n.method,configPath:n.configPath,configPaths:n.configPaths,errors:n.errors}}import{tmpdir as Ai}from"node:os";import{join as Wi}from"node:path";var Ri=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}]),Ki=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([])})})}),Mi={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:[]}},sources:{failClosed:[],paranoidRm:[],paranoidInterpreters:[],worktreeMode:[]}};function B0(){let n=Wi(Ai(),"cc-safety-net-self-test"),t=Ri.map((e)=>{let r=Kn(M2("self-test",{command:e.command},{kind:"command",shell:"auto"},{configCwd:n,executionCwd:n},e.command),{guard:{dependencies:{loadPolicySnapshot:()=>Ki,getModes:()=>Mi,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),a=e.expectBlocked?"blocked":"allowed",l=r.decision.kind==="deny"?"blocked":"allowed";return{command:e.command,description:e.description,expected:a,actual:l,passed:a===l,reason:r.decision.kind==="deny"?r.decision.reason:void 0,ruleId:r.decision.kind==="deny"?r.decision.ruleId:void 0}});return{passed:t.filter((e)=>e.passed).length,failed:t.filter((e)=>!e.passed).length,total:t.length,results:t}}function Ve(n){let t=F({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},n);if(r2(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function J0(n={}){let t=await Dn(!n.json,()=>{let e=Vi(n);return{ready:e,finish:()=>e}},()=>gn(),{loadingMessage:"Checking system status…"});if(n.json)console.log(JSON.stringify(t,null,2));else Ci(t);return Gi(t.hooks,t.engineSelfTest,{userConfig:t.userConfig,projectConfig:t.projectConfig})?1:0}async function Vi(n){let t=n.cwd??process.cwd(),e=await xn(),r=tn(t,{ampPluginListOutput:e.ampPluginListOutput,codexPluginListOutput:e.codexPluginListOutput,copilotCliVersion:e.copilotCliVersion}),a=I1(t),l=N1(),d=W({cwd:t}),s=d.policy,c=d2(s),i=g2(s,c.capabilities),L=Cn(7),u=n.skipUpdateCheck?{currentVersion:j(),latestVersion:null,updateAvailable:!1}:await E2(),v={hooks:r,engineSelfTest:B0(),userConfig:a.userConfig,projectConfig:a.projectConfig,configState:fn(d),effectiveRules:a.effectiveRules,shadowedRules:a.shadowedRules,environment:l,effectiveSafety:{selectedPreset:s.safety.level??"standard",level:c.effectiveLevel,capabilities:c.capabilities,ruleOverrides:s.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(i).filter(([,p])=>p.source==="rule_override"&&p.override==="off"&&p.inheritedEnabled&&p.changesInherited).map(([p])=>p),ruleCounts:{stored:Object.keys(s.destructiveCommandRuleOverrides).length,effective:Object.values(i).filter((p)=>p.changesInherited).length}},posture:oa(a.userConfig.path),activity:L,update:u,system:e};return{...v,findings:ta(v)}}function Gi(n,t,e){return n.length>0&&n.every((r)=>!r.configured)||n.some((r)=>r.inspectionStatus==="failed")||t.failed>0||e.userConfig.exists&&!e.userConfig.valid||e.projectConfig.exists&&!e.projectConfig.valid}function Ci(n){console.log(),console.log(ra(n.hooks)),console.log(),console.log(aa(n.engineSelfTest)),console.log(),console.log(la(n)),console.log(),console.log(da(n.environment)),console.log(),console.log(sa(n)),console.log(),console.log(ca(n.findings)),console.log(),console.log(ia(n.activity)),console.log(),console.log(pa(n.system)),console.log(),console.log(La(n.update)),console.log(ua(n))}import{existsSync as Ui}from"node:fs";var Oi=/^[A-Za-z0-9_@%+=:,./-]+$/,Z0="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Ge(n){let t=F({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},n);if(r2(t.errors))return console.error(Z0),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!Ui(t.values.cwd))return console.error(`Error: --cwd path does not exist: ${t.values.cwd}`),null;let e=t.positionals.length===1?t.positionals[0]:t.positionals.map((r)=>Oi.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!e)return console.error("Error: No command provided"),console.error(Z0),null;return{json:t.flags.json,cwd:t.values.cwd,command:e}}function Q0(n){if(n)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 X0(n,t){let r=t-18;return[`${n.dtl}${n.dh.repeat(t)}${n.dtr}`,`${n.dv} Command Analysis${" ".repeat(r)}${n.dv}`,`${n.dbl}${n.dh.repeat(t)}${n.dbr}`]}function Ce(n){return JSON.stringify(n)}function Y0(n,t=0){return`[${n.map((r,a)=>ea(r,a,t)).join(",")}]`}function dt(n,t,e=70){let r=n.split(" "),a=[],l="";for(let d of r)if(l&&l.length+d.length+1>e)a.push(l),l=d;else l=l?`${l} ${d}`:d;if(l)a.push(l);return a.map((d,s)=>s===0?d:`${t}${d}`)}function S0(n,t,e){let r=[];switch(n.type){case"parse":return null;case"env-strip":{r.push(""),r.push(`STEP ${t} ${e.h} Strip environment variables`);let a=Object.keys(n.envVars);return r.push(` Removed: ${a.map((l)=>`${l}=<redacted>`).join(", ")}`),r.push(` Tokens: ${Ce(n.output)}`),{lines:r,incrementStep:!0}}case"leading-tokens-stripped":return r.push(""),r.push(`STEP ${t} ${e.h} Strip wrappers`),r.push(` Removed: ${n.removed.join(", ")}`),r.push(` Tokens: ${Ce(n.output)}`),{lines:r,incrementStep:!0};case"shell-wrapper":return r.push(""),r.push(`STEP ${t} ${e.h} Detect shell wrapper`),r.push(` Wrapper: ${n.wrapper} -c`),r.push(` Inner: ${n.innerCommand}`),{lines:r,incrementStep:!0};case"interpreter":{if(r.push(""),r.push(`STEP ${t} ${e.h} Detect interpreter`),r.push(` Interpreter: ${n.interpreter}`),r.push(` Code: ${n.codeArg}`),n.paranoidBlocked)r.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:r,incrementStep:!0}}case"busybox":return r.push(""),r.push(`STEP ${t} ${e.h} Busybox wrapper`),r.push(` Subcommand: ${n.subcommand}`),{lines:r,incrementStep:!0};case"transparent-wrapper":return r.push(""),r.push(`STEP ${t} ${e.h} Transparent wrapper`),r.push(` Wrapper: ${n.wrapper}`),r.push(` Tokens: ${Ce(n.output)}`),{lines:r,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{r.push(""),r.push(`STEP ${t} ${e.h} Match rules`);let a=`${n.ruleModule}:${n.ruleFunction}()`;if(r.push(` Rule: ${a}`),n.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} ${e.h} Worktree relaxation`),r.push(` Mode: ${m.worktree.name}`),r.push(` Git cwd: ${n.gitCwd}`),r.push(" Result: Allowed local discard in linked worktree"),{lines:r,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(n.embeddedCommandFound)return r.push(""),r.push(`STEP ${t} ${e.h} Fallback scan`),r.push(` Found: ${n.embeddedCommandFound}`),{lines:r,incrementStep:!0};return null}case"custom-rules-check":{if(n.rulesChecked){if(r.push(""),r.push(`STEP ${t} ${e.h} Custom rules`),n.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(n.matched)return r.push(""),r.push(`STEP ${t} ${e.h} Dangerous text check`),r.push(` Token: ${n.token}`),r.push(" Result: MATCHED"),{lines:r,incrementStep:!0};return null}case"strict-unparseable":return r.push(""),r.push(`STEP ${t} ${e.h} Strict mode check`),r.push(` Command: ${n.rawCommand}`),r.push(" Result: ✗ UNPARSEABLE"),{lines:r,incrementStep:!0};case"segment-skipped":return null;case"error":return r.push(""),r.push(`ERROR: ${n.message}`),{lines:r,incrementStep:!1};default:return null}}function Ue(n,t){let e=Q0(t?.asciiOnly??!1),r=58,a=[],l=1;a.push(...X0(e,58)),a.push("");let d=n.trace.steps.find((p)=>p.type==="error");if(d&&d.type==="error"){a.push("ERROR"),a.push(` ${d.message}`),a.push(""),a.push("RESULT"),a.push(` Status: ${n.result==="blocked"?b.red("BLOCKED"):b.green("ALLOWED")}`),a.push(""),a.push("CONFIG");let p=n.configSource??"none";return a.push(` Path: ${p}`),a.join(`
|
|
177
|
-
|
|
178
|
-
`)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`)}var K0=["global-hook","plugin"];function dL(n,t,e={}){let r=e.color!==!1?b.bold:(l)=>l;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((l,d)=>{let s=d===n,c=`${s?V0:G0} ${l}`;return`${s?C0:U0} ${s?r(c):c}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
182
|
-
`)}
|
|
183
|
-
`),
|
|
184
|
-
|
|
185
|
-
`)
|
|
186
|
-
`)
|
|
178
|
+
`}function zn(n){return[{name:"__init__.py",content:pL(n)},{name:"plugin.yaml",content:iL(n)}]}import{mkdirSync as uL,readdirSync as vL,readFileSync as oL,rmSync as Zr}from"node:fs";import{join as J2}from"node:path";var bL="__pycache__";function Qr(n){let t=process.env.HERMES_HOME?.trim();return t?t:J2(n,".hermes")}function Xr(n){return J2(Qr(n),"plugins",G)}function Yr(n){return n.startsWith(l0)}function Sr(n,t){let r=Xr(n),e=W(r);if(e&&(e.isSymbolicLink()||!e.isDirectory()))throw Error(`Refusing to ${t} ${r}: not a regular directory. Move or remove it and rerun ${t==="install"?"install":"uninstall"} --hermes-agent.`);return r}function d0(n,t){let r=W(n);if(!r)return;if(r.isSymbolicLink()||!r.isFile())throw Error(`Refusing to ${t} ${n}: not a regular file. Move or remove it.`);let e=oL(n,"utf-8");if(!Yr(e))throw Error(`Refusing to ${t} unmanaged file at ${n}. Move or remove it.`);return e}function c0(n){let t=Sr(n,"install"),r=zn(F());if(r.map((a)=>d0(J2(t,a.name),"overwrite")).every((a,l)=>a===r[l]?.content))return{path:t,alreadyInstalled:!0};return uL(t,{recursive:!0}),r.forEach((a)=>{Z(J2(t,a.name),a.content)}),{path:t,alreadyInstalled:!1}}function Hr(n){let t=Sr(n,"remove");if(!W(t))return[];return zn(F()).filter((r)=>d0(J2(t,r.name),"remove")!==void 0)}function L0(n){let t=Sr(n,"remove");if(!W(t))return{path:t,alreadyInstalled:!1};let r=Hr(n);if(r.forEach((e)=>{Zr(J2(t,e.name))}),Zr(J2(t,bL),{recursive:!0,force:!0}),vL(t).length===0)Zr(t,{recursive:!0});return{path:t,alreadyInstalled:r.length>0}}var lt="hermes-agent",i0=/^([^\s#][^:]*):/,fL=/^\s+([A-Za-z_][\w-]*):/,p0=/^\s+-\s*(.*)$/;function yL(n){return n.trim().replace(/^(["'])(.*)\1$/,"$2")}function hL(n){let t=n.split(/\r?\n/),r=t.findIndex((l)=>i0.exec(l)?.[1]?.trim()==="plugins");if(r===-1)return[];let e=t.slice(r+1),a=e.findIndex((l)=>i0.test(l));return a===-1?e:e.slice(0,a)}function u0(n,t){let r=hL(n),e=r.findIndex((s)=>fL.exec(s)?.[1]===t);if(e===-1)return[];let a=r.slice(e+1),l=a.findIndex((s)=>!p0.test(s));return(l===-1?a:a.slice(0,l)).map((s)=>yL(p0.exec(s)?.[1]??""))}function wL(n){try{return v0(o0(Qr(n),"config.yaml"),"utf-8")}catch{return}}function Rr(n){let t=wL(n)??"";return u0(t,"enabled").includes(G)&&!u0(t,"disabled").includes(G)}function b0(n){return/^# version:\s*(.+)$/m.exec(n)?.[1]?.trim()}function xL(n,t){let r=W(n);if(!r)return{error:`${t.name} is missing from ${n}; run install --hermes-agent`};if(r.isSymbolicLink()||!r.isFile())return{error:`${n} is a symlink or not a regular file; move or remove it`};try{let e=v0(n,"utf-8");if(!Yr(e))return{error:`Unmanaged ${t.name} occupies ${n}; move or remove it`};if(b0(e)===F()&&e!==t.content)return{error:`Modified ${t.name} occupies ${n}; run install --hermes-agent to restore it`};return{content:e}}catch(e){return{error:`Failed to read ${n}: ${e instanceof Error?e.message:String(e)}`}}}function f0(n){let t=Xr(n.homeDir),r=In(lt,t);if(r)return r;let e=zn(F()).map((d)=>xL(o0(t,d.name),d)),a=e.flatMap((d)=>("error"in d)?[d.error]:[]);if(a.length>0)return{platform:lt,status:"n/a",configPath:t,errors:a};let l=e.some((d)=>("content"in d)&&b0(d.content)!==F()),s=l?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Rr(n.homeDir))return{platform:lt,status:"disabled",method:"plugin directory",configPath:t,errors:[`${G} is not enabled in Hermes; run \`hermes plugins enable ${G}\``,...s]};return{platform:lt,status:"configured",method:"plugin directory",configPath:t,errors:l?s:void 0}}import{existsSync as $L,readFileSync as mL}from"node:fs";import{join as y0}from"node:path";var gL=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function DL(n){return y0(process.env.KIMI_CODE_HOME||y0(n,".kimi-code"),"config.toml")}function Fn(n){let t=DL(n.homeDir);if(!$L(t))return{platform:"kimi-code",status:"n/a",configPath:t};try{if(!gL.test(mL(t,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:t}}catch(r){return{platform:"kimi-code",status:"n/a",configPath:t,errors:[`Failed to read ${t}: ${r instanceof Error?r.message:String(r)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:t}}import{readFileSync as j0}from"node:fs";import{join as Jn}from"node:path";var z="cc-safety-net",U="index.js",nn="openclaw.plugin.json",tn="package.json";var st="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as jL,lstatSync as zL,readdirSync as FL,readFileSync as BL}from"node:fs";import{dirname as x0,join as w2}from"node:path";import{fileURLToPath as JL}from"node:url";import{spawn as kL}from"node:child_process";function qL(n){return n.join(" ")}function Wr(n,t,r){return[`Failed to run ${qL(n)}${t===null?"":` (exit ${t})`}.`,r.trim()].filter(Boolean).join(`
|
|
179
|
+
`)}function Ar(n){let t={stdout:"",stderr:""};return n.stdout.setEncoding("utf-8"),n.stderr.setEncoding("utf-8"),n.stdout.on("data",(r)=>{t.stdout+=r}),n.stderr.on("data",(r)=>{t.stderr+=r}),t}function a2(n,t){return new Promise((r,e)=>{let a=h2([...n],process.env),l=kL(a.cmd,a.args,{stdio:["ignore","pipe","pipe"]}),s=Ar(l),d=()=>[s.stdout,s.stderr].filter(Boolean).join(`
|
|
180
|
+
`),c=t?.timeoutMs??120000,L=setTimeout(()=>{l.kill(),e(Error(Wr(n,null,`Timed out after ${c}ms.
|
|
181
|
+
${d()}`.trim())))},c);l.on("error",(i)=>{clearTimeout(L),e(Error(Wr(n,null,`${i.message}
|
|
182
|
+
${d()}`.trim())))}),l.on("close",(i)=>{if(clearTimeout(L),i!==0){e(Error(Wr(n,i,d())));return}r(t?.stdoutOnly?s.stdout:d())})})}async function Kr(n){for(let t of n)await a2(t)}async function h0(n){for(let t of n)try{await a2(t)}catch(r){console.warn(r instanceof Error?r.message:String(r))}}var w0=w2("openclaw",z),ZL=[U,nn,tn];function Vr(n,t){if(n==="~")return t;if(n.startsWith("~/")||n.startsWith("~\\"))return w2(t,n.slice(2));return n}function $0(n){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return Vr(t,n);let r=process.env.OPENCLAW_CONFIG_PATH?.trim();return r?x0(Vr(r,n)):w2(n,".openclaw")}function m0(n){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?Vr(t,n):w2($0(n),"openclaw.json")}function Mr(n){return w2($0(n),"extensions",z)}function QL(n){let t=FL(n);if(t.length===0)return!0;if(t.some((a)=>!ZL.includes(a)))return!1;let r=w2(n,U),e=W(r);return e!==void 0&&!e.isSymbolicLink()&&e.isFile()&&BL(r,"utf-8").startsWith(st)}function Gr(n){let t=Mr(n),r=W(t);if(!r)return;if(!r.isSymbolicLink()&&r.isDirectory()&&QL(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 g0(){let n=x0(JL(import.meta.url));return[w2(n,"..",w0),w2(n,"..","..","..","dist",w0)]}function Ur(n=g0()){return n.find((t)=>jL(t)&&zL(t).isDirectory())}function XL(n=g0()){let t=Ur(n);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function D0(n=XL()){return[["openclaw","plugins","install",n,"--force"],["openclaw","plugins","enable",z]]}function YL(n){let t=(()=>{try{return JSON.parse(n)}catch{return}})(),r=x(x(t,"plugin"),"status");return typeof r==="string"?r:void 0}async function k0(){let n=YL(await a2(["openclaw","plugins","inspect",z,"--runtime","--json"],{stdoutOnly:!0}));if(n==="loaded")return;throw Error(`${n===void 0?`The ${z} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${z} plugin with status "${n}".`} Run \`openclaw plugins inspect ${z} --runtime\` for details.`)}var dt="openclaw",Bn=`run \`openclaw plugins enable ${z}\``;function rn(n,t){let r=Jn(n,t),e=W(r);if(!e)return{error:`${t} is missing from ${r}; run install --openclaw`};if(e.isSymbolicLink()||!e.isFile())return{error:`${r} is a symlink or not a regular file; move or remove it`};try{return{content:j0(r,"utf-8")}}catch(a){return{error:`Failed to read ${r}: ${a instanceof Error?a.message:String(a)}`}}}function z0(n){try{return JSON.parse(V(n))}catch{return}}function SL(n){let t=rn(n,nn);if("error"in t)return t.error;if(x(z0(t.content),"id")===z)return;return`${Jn(n,nn)} is not a valid ${z} manifest; run install --openclaw`}function HL(n){let t=rn(n,tn);if("error"in t)return t.error;let r=x(x(z0(t.content),"openclaw"),"extensions");if(Array.isArray(r)&&r.includes(`./${U}`))return;return`${Jn(n,tn)} does not point OpenClaw at ${U}; run install --openclaw`}function q0(n){return Array.isArray(n)?n.filter((t)=>typeof t==="string"):[]}function RL(n){let t=m0(n);if(!W(t))return`${z} is not enabled; ${Bn}`;let r=(()=>{try{return JSON.parse(V(j0(t,"utf-8")))}catch{return}})();if(r===void 0)return`Failed to read ${t}; fix it, then ${Bn}`;let e=x(r,"plugins");if(x(e,"enabled")===!1)return`plugins.enabled is false in ${t}; no OpenClaw plugin loads`;let a=x(x(x(e,"entries"),z),"enabled");if(q0(x(e,"deny")).includes(z)||a===!1)return`${z} is disabled in ${t}; ${Bn}`;let l=q0(x(e,"allow"));if(l.length>0&&!l.includes(z))return`plugins.allow in ${t} does not list ${z}; add it, then ${Bn}`;if(l.includes(z)||a===!0)return;return`${z} is not enabled; ${Bn}`}function F0(n){return/^\/\/ version:\s*(.+)$/m.exec(n)?.[1]?.trim()}function WL(n,t,r){if(r===void 0)return[];let e=rn(r,U);if("error"in e||F0(e.content)!==t)return[];return[U,nn,tn].flatMap((a)=>{let l=rn(n,a),s=rn(r,a);if("error"in l||"error"in s||l.content===s.content)return[];return[`Modified ${a} occupies ${Jn(n,a)}; run install --openclaw to restore it`]})}function B0(n){let t=Mr(n.homeDir),r=In(dt,t);if(r)return r;let e=rn(t,U),l=["error"in e?e.error:e.content.startsWith(st)?void 0:`Unmanaged ${U} occupies ${Jn(t,U)}; move or remove it`,SL(t),HL(t)].filter((i)=>i!==void 0),s="content"in e?F0(e.content):void 0,d=l.length>0?l:WL(t,s,Ur());if(d.length>0)return{platform:dt,status:"n/a",configPath:t,errors:d};let c=s===F()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],L=RL(n.homeDir);if(L)return{platform:dt,status:"disabled",method:"plugin directory",configPath:t,errors:[L,...c]};return{platform:dt,status:"configured",method:"plugin directory",configPath:t,errors:c.length>0?c:void 0}}import{existsSync as EL,readFileSync as PL}from"node:fs";import{join as IL}from"node:path";import{existsSync as Cr,readFileSync as Y0,rmSync as KL}from"node:fs";import{join as u2}from"node:path";import{pathToFileURL as VL}from"node:url";function J0(n){return n!==void 0&&/\s/.test(n)}function AL(n,t,r){let e=t+1,a=!1;while(e<n.length){let l=n[e];if(a){a=!1,e++;continue}if(l==="\\"){a=!0,e++;continue}if(l==='"')return e+1;e++}throw Error(r)}function ct(n,t,r){let e=n[t],a=e==="["?"]":"}",l=0,s=t;while(s<n.length){let d=r.skipComment?.(n,s)??s;if(d!==s){s=d;continue}if(n[s]==='"'){s=AL(n,s,r.stringError);continue}if(n[s]===e)l++;if(n[s]===a){if(l--,l===0)return s}s++}throw Error(r.bracketError)}function Z0(n,t){let r=n.lastIndexOf(`
|
|
183
|
+
`,t)+1;return/^[ \t]*/.exec(n.slice(r))?.[0]??""}function Lt(n,t){let{start:r,end:e,end:a}=t;while(J0(n[a]))a++;if(n[a]===","){if(e=a+1,n[e]===`
|
|
184
|
+
`)e++;return`${n.slice(0,r)}${n.slice(e)}`}a=t.start-1;while(J0(n[a]))a--;if(n[a]===","){r=a;let l=n.lastIndexOf(`
|
|
185
|
+
`,r-1);if(l!==-1&&/^\s*$/.test(n.slice(l+1,r)))r=l}return`${n.slice(0,r)}${n.slice(e)}`}var it="cc-safety-net",S0=`${it}@latest`,H0=["opencode.json","opencode.jsonc"],Q0="CCSafetyNetPlugin";function pt(n){return u2(process.env.XDG_CONFIG_HOME||u2(n,".config"),"opencode")}function ML(n){return u2(pt(n),H0[0])}function GL(n){return H0.map((t)=>u2(pt(n),t))}function R0(n){return u2(process.env.XDG_CACHE_HOME||u2(n,".cache"),"opencode","packages",S0)}function Or(n){KL(R0(n),{recursive:!0,force:!0})}async function W0(n){let t=u2(R0(n),"node_modules",it),r=u2(t,"package.json");if(!Cr(r))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 ${S0}\` for details.`);let e=x(JSON.parse(Y0(r,"utf-8")),"main");if(typeof e!=="string")throw Error(`The cached OpenCode plugin at ${t} declares no "main" entry.`);let a=u2(t,e);if(typeof(await import(VL(a).href))[Q0]==="function")return;throw Error(`The cached OpenCode plugin at ${a} does not export a callable ${Q0}, so OpenCode would load nothing and fail open.`)}function ut(n,t){if(n[t]==="/"&&n[t+1]==="/"){let r=n.indexOf(`
|
|
186
|
+
`,t+2);return r===-1?n.length:r+1}if(n[t]==="/"&&n[t+1]==="*"){let r=n.indexOf("*/",t+2);return r===-1?n.length:r+2}return t}function X0(n,t){let r=t;while(r<n.length){if(/\s/.test(n[r]??"")){r++;continue}let e=ut(n,r);if(e===r)return r;r=e}return r}function A0(n,t){let r=t+1,e=!1;while(r<n.length){if(e){e=!1,r++;continue}if(n[r]==="\\"){e=!0,r++;continue}if(n[r]==='"')return r+1;r++}throw Error("Unterminated string in OpenCode config")}function K0(n,t,r){return JSON.parse(n.slice(t,r))}function UL(n,t){return ct(n,t,{skipComment:ut,stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"})}function CL(n){let t=0,r=0;while(r<n.length){let e=ut(n,r);if(e!==r){r=e;continue}if(n[r]==='"'){let a=A0(n,r);if(t===1&&K0(n,r,a)==="plugin"){let l=X0(n,a),s=X0(n,l+1);if(n[l]===":"&&n[s]==="[")return{start:s,end:UL(n,s)}}r=a;continue}if(n[r]==="{"||n[r]==="[")t++;if(n[r]==="}"||n[r]==="]")t--;r++}return}function OL(n,t){let r=[],e=t.start+1;while(e<t.end){let a=ut(n,e);if(a!==e){e=a;continue}if(n[e]==='"'){let l=A0(n,e),s=K0(n,e,l);if(typeof s==="string"&&s.includes(it))r.push({start:e,end:l});e=l;continue}e++}return r}function V0(n,t){try{return JSON.parse(V(n))}catch(r){if(r instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${t}: ${r.message}`);throw r}}function TL(n){if(!n||typeof n!=="object"||Array.isArray(n))return!1;let t=n.plugin;if(!Array.isArray(t))return!1;return t.some((r)=>typeof r==="string"&&r.includes(it))}function _L(n,t){let r=CL(n);if(!r)throw Error(`Failed to locate OpenCode plugin array in ${t}`);let e=[...OL(n,r)].reverse().reduce(Lt,n);return V0(e,t),e}function M0(n){Or(n);let t=GL(n),r=t.find((a)=>Cr(a)),e=[];for(let a of t){if(!Cr(a))continue;try{let l=Y0(a,"utf-8");if(!TL(V0(l,a)))continue;return Z(a,_L(l,a)),{path:a,alreadyInstalled:!0}}catch(l){e.push(l instanceof Error?l.message:String(l))}}if(e.length>0)throw Error(e.join(`
|
|
187
|
+
`));return{path:r??ML(n),alreadyInstalled:!1}}function G0(n){let t=[],r=pt(n.homeDir),e=["opencode.json","opencode.jsonc"];for(let a of e){let l=IL(r,a);if(EL(l))try{let s=PL(l,"utf-8"),d=V(s);if((JSON.parse(d).plugin??[]).some((u)=>u.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:l,errors:t.length>0?t:void 0}}catch(s){t.push(`Failed to parse ${a}: ${s instanceof Error?s.message:String(s)}`)}}return{platform:"opencode",status:"n/a",errors:t.length>0?t:void 0}}import{join as NL}from"node:path";function Tr(n){return NL(n,".pi","agent","settings.json")}function _r(n){if(typeof n!=="string")return!1;return n==="npm:cc-safety-net"||n.startsWith("npm:cc-safety-net@")}function U0(n){let t=Tr(n.homeDir),r=r2(t);if(r.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(r.kind==="missing")return{platform:"pi",status:"n/a"};let e=x(r.value,"packages");if(!Array.isArray(e))return{platform:"pi",status:"n/a"};let a=e.find((d)=>_r(typeof d==="string"?d:x(d,"source")));if(a===void 0)return{platform:"pi",status:"n/a"};let l=x(a,"extensions");if(Array.isArray(l)&&l.some((d)=>typeof d==="string"&&d.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 ti={amp:Za,"antigravity-cli":Qa,"claude-code":Ha,codex:Ra,"copilot-cli":_a,cursor:e0,"gemini-cli":a0,"hermes-agent":f0,"kimi-code":Fn,openclaw:B0,opencode:G0,pi:U0};function en(n,t){let r={...t,cwd:n,homeDir:t?.homeDir??ni()};return Gn.map((e)=>ri(ti[e](r)))}function ri(n){if(n.status==="not-inspected")return{platform:n.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:n.platform,detected:n.status!=="n/a",configured:n.status==="configured",inspectionStatus:n.status!=="n/a"?"verified":n.errors&&n.errors.length>0?"failed":"not-applicable",method:n.method,configPath:n.configPath,configPaths:n.configPaths,errors:n.errors}}import{tmpdir as ei}from"node:os";import{join as ai}from"node:path";var li=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}]),si=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([])})})}),di={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 C0(){let n=ai(ei(),"cc-safety-net-self-test"),t=li.map((r)=>{let e=Vn(U2("self-test",{command:r.command},{kind:"command",shell:"auto"},{configCwd:n,executionCwd:n},r.command),{guard:{dependencies:{loadPolicySnapshot:()=>si,getModes:()=>di,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),a=r.expectBlocked?"blocked":"allowed",l=e.decision.kind==="deny"?"blocked":"allowed";return{command:r.command,description:r.description,expected:a,actual:l,passed:a===l,reason:e.decision.kind==="deny"?e.decision.reason:void 0,ruleId:e.decision.kind==="deny"?e.decision.ruleId:void 0}});return{passed:t.filter((r)=>r.passed).length,failed:t.filter((r)=>!r.passed).length,total:t.length,results:t}}function Er(n){let t=B({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},n);if(l2(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function O0(n={}){let t=await Dn(!n.json,()=>{let r=ci(n);return{ready:r,finish:()=>r}},()=>gn(),{loadingMessage:"Checking system status…"});if(n.json)console.log(JSON.stringify(t,null,2));else ii(t);return Li(t.hooks,t.engineSelfTest,{userConfig:t.userConfig,projectConfig:t.projectConfig})?1:0}async function ci(n){let t=n.cwd??process.cwd(),r=await $n(),e=en(t,{ampPluginListOutput:r.ampPluginListOutput,codexPluginListOutput:r.codexPluginListOutput,copilotCliVersion:r.versions["copilot-cli"]}),a=ra(t),l=ea(),s=K({cwd:t}),d=s.policy,c=c2(d),L=q2(d,c.capabilities),i=Cn(7),u=n.skipUpdateCheck?{currentVersion:F(),latestVersion:null,updateAvailable:!1}:await P2(),o={hooks:e,engineSelfTest:C0(),userConfig:a.userConfig,projectConfig:a.projectConfig,configState:yn(s),effectiveRules:a.effectiveRules,shadowedRules:a.shadowedRules,environment:l,effectiveSafety:{selectedPreset:d.safety.level??"standard",level:c.effectiveLevel,capabilities:c.capabilities,ruleOverrides:d.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(L).filter(([,p])=>p.source==="rule_override"&&p.override==="off"&&p.inheritedEnabled&&p.changesInherited).map(([p])=>p),ruleCounts:{stored:Object.keys(d.destructiveCommandRuleOverrides).length,effective:Object.values(L).filter((p)=>p.changesInherited).length}},posture:ya(a.userConfig.path),activity:i,update:u,system:r};return{...o,findings:la(o)}}function Li(n,t,r){return n.length>0&&n.every((e)=>!e.configured)||n.some((e)=>e.inspectionStatus==="failed")||t.failed>0||r.userConfig.exists&&!r.userConfig.valid||r.projectConfig.exists&&!r.projectConfig.valid}function ii(n){console.log(),console.log(da(n.hooks)),console.log(),console.log(ca(n.engineSelfTest)),console.log(),console.log(La(n)),console.log(),console.log(ia(n.environment)),console.log(),console.log(pa(n)),console.log(),console.log(ua(n.findings)),console.log(),console.log(va(n.activity)),console.log(),console.log(ba(n.system)),console.log(),console.log(oa(n.update)),console.log(fa(n))}import{existsSync as pi}from"node:fs";var ui=/^[A-Za-z0-9_@%+=:,./-]+$/,T0="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Pr(n){let t=B({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},n);if(l2(t.errors))return console.error(T0),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!pi(t.values.cwd))return console.error(`Error: --cwd path does not exist: ${t.values.cwd}`),null;let r=t.positionals.length===1?t.positionals[0]:t.positionals.map((e)=>ui.test(e)?e:`'${e.replaceAll("'","'\\''")}'`).join(" ");if(!r)return console.error("Error: No command provided"),console.error(T0),null;return{json:t.flags.json,cwd:t.values.cwd,command:r}}function _0(n){if(n)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 E0(n,t){let e=t-18;return[`${n.dtl}${n.dh.repeat(t)}${n.dtr}`,`${n.dv} Command Analysis${" ".repeat(e)}${n.dv}`,`${n.dbl}${n.dh.repeat(t)}${n.dbr}`]}function Ir(n){return JSON.stringify(n)}function P0(n,t=0){return`[${n.map((e,a)=>sa(e,a,t)).join(",")}]`}function vt(n,t,r=70){let e=n.split(" "),a=[],l="";for(let s of e)if(l&&l.length+s.length+1>r)a.push(l),l=s;else l=l?`${l} ${s}`:s;if(l)a.push(l);return a.map((s,d)=>d===0?s:`${t}${s}`)}function I0(n,t,r){let e=[];switch(n.type){case"parse":return null;case"env-strip":return e.push(""),e.push(`STEP ${t} ${r.h} Strip environment variables`),e.push(` Removed: ${n.envVars.map((a)=>`${a}=<redacted>`).join(", ")}`),e.push(` Tokens: ${Ir(n.output)}`),{lines:e,incrementStep:!0};case"leading-tokens-stripped":return e.push(""),e.push(`STEP ${t} ${r.h} Strip wrappers`),e.push(` Removed: ${n.removed.join(", ")}`),e.push(` Tokens: ${Ir(n.output)}`),{lines:e,incrementStep:!0};case"shell-wrapper":return e.push(""),e.push(`STEP ${t} ${r.h} Detect shell wrapper`),e.push(` Wrapper: ${n.wrapper} -c`),e.push(` Inner: ${n.innerCommand}`),{lines:e,incrementStep:!0};case"interpreter":{if(e.push(""),e.push(`STEP ${t} ${r.h} Detect interpreter`),e.push(` Interpreter: ${n.interpreter}`),e.push(` Code: ${n.codeArg}`),n.paranoidBlocked)e.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:e,incrementStep:!0}}case"busybox":return e.push(""),e.push(`STEP ${t} ${r.h} Busybox wrapper`),e.push(` Subcommand: ${n.subcommand}`),{lines:e,incrementStep:!0};case"transparent-wrapper":return e.push(""),e.push(`STEP ${t} ${r.h} Transparent wrapper`),e.push(` Wrapper: ${n.wrapper}`),e.push(` Tokens: ${Ir(n.output)}`),{lines:e,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(e.push(""),e.push(`STEP ${t} ${r.h} Match rules`),e.push(` Rule: ${n.rule}()`),n.matched)e.push(" Result: MATCHED");else e.push(" Result: No match");return{lines:e,incrementStep:!0}}case"worktree-relaxation":return e.push(""),e.push(`STEP ${t} ${r.h} Worktree relaxation`),e.push(` Mode: ${k.worktree.name}`),e.push(` Git cwd: ${n.gitCwd}`),e.push(" Result: Allowed local discard in linked worktree"),{lines:e,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(n.embeddedCommandFound)return e.push(""),e.push(`STEP ${t} ${r.h} Fallback scan`),e.push(` Found: ${n.embeddedCommandFound}`),{lines:e,incrementStep:!0};return null}case"custom-rules-check":{if(n.rulesChecked){if(e.push(""),e.push(`STEP ${t} ${r.h} Custom rules`),n.matched)e.push(" Result: MATCHED");else e.push(" Result: No match");return{lines:e,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(n.matched)return e.push(""),e.push(`STEP ${t} ${r.h} Dangerous text check`),e.push(` Token: ${n.token}`),e.push(" Result: MATCHED"),{lines:e,incrementStep:!0};return null}case"strict-unparseable":return e.push(""),e.push(`STEP ${t} ${r.h} Strict mode check`),e.push(` Command: ${n.rawCommand}`),e.push(" Result: ✗ UNPARSEABLE"),{lines:e,incrementStep:!0};case"segment-skipped":return null;case"error":return e.push(""),e.push(`ERROR: ${n.message}`),{lines:e,incrementStep:!1};default:return null}}function Nr(n,t){let r=_0(t?.asciiOnly??!1),e=58,a=[],l=1;a.push(...E0(r,58)),a.push("");let s=n.trace.steps.find((p)=>p.type==="error");if(s&&s.type==="error"){a.push("ERROR"),a.push(` ${s.message}`),a.push(""),a.push("RESULT"),a.push(` Status: ${n.result==="blocked"?b.red("BLOCKED"):b.green("ALLOWED")}`),a.push(""),a.push("CONFIG");let p=n.configSource??"none";return a.push(` Path: ${p}`),a.join(`
|
|
188
|
+
`)}let d=n.trace.steps.find((p)=>p.type==="parse");if(d&&d.type==="parse"){a.push("INPUT"),a.push(` ${d.input}`),a.push(""),a.push(`STEP ${l} ${r.h} Split shell commands`),l++;for(let p=0;p<d.segments.length;p++){let f=d.segments[p];if(f){let v=Math.random();a.push(` Segment ${p+1}: ${P0(f,v)}`)}}}let c=n.trace.segments,L=c.length>1;for(let p of c){if(L){a.push("");let w="";if(d&&d.type==="parse"){let Zt=d.segments[p.index];if(Zt)w=Zt.join(" ")}let $=54,y=w,g=` Segment ${p.index+1}: `,S=" ";if(w){if(g.length+w.length+S.length>$){let M3=$-g.length-S.length;y=`${w.substring(0,M3-1)}…`}}let b2=w?`${g}${y}${S}`:` Segment ${p.index+1} `,Jt=w?`${g}${b.cyan(y)}${S}`:b2,ge=58-b2.length,De=Math.floor(ge/2),V3=ge-De;a.push(`${r.sh.repeat(De)}${Jt}${r.sh.repeat(V3)}`)}if(p.steps.find((w)=>w.type==="segment-skipped")){a.push(""),a.push(" (skipped — prior segment blocked)");continue}let v=!1,h=!1;for(let w of p.steps){let $=I0(w,l,r);if($){if(h=!0,w.type==="recurse"){a.push("");let y=" RECURSING ",g=58-y.length-4;a.push(` ${r.tl}${r.h}${y}${r.h.repeat(g)}`),a.push(` ${r.v}`),v=!0;continue}for(let y of $.lines)if(v)a.push(` ${r.v} ${y}`);else a.push(y);if($.incrementStep)l++}}if(v)a.push(` ${r.v}`),a.push(` ${r.bl}${r.h.repeat(56)}`),v=!1;if(!h)a.push(""),a.push(` ${b.green("✓")} Allowed (no matching rules)`)}if(a.push(""),a.push("RESULT"),n.result==="blocked"){if(a.push(` Status: ${b.red("BLOCKED")}`),n.customRule){if(a.push(` Rule: ${n.customRule.id}`),n.customRule.rulebook)a.push(` Rulebook: ${n.customRule.rulebook.name} ${n.customRule.rulebook.version}`);if(n.customRule.source)a.push(` Source: ${n.customRule.source}`);if(n.customRule.override)a.push(` Override: reason ${n.customRule.override.reason}`)}if(n.reason){let p=vt(n.reason," ");a.push(` Reason: ${p[0]}`);for(let f=1;f<p.length;f++)a.push(p[f]??"")}}else a.push(` Status: ${b.green("ALLOWED")}`);a.push(""),a.push("CONFIG");let i=n.configSource??"none",u=n.configValid?"":" (invalid)";a.push(` Path: ${i}${u}`),a.push(` Safety preset: ${n.selectedPreset??"standard"}`),a.push(` Effective capabilities: ${n.effectiveLevel}`);let o=Object.entries(n.destructiveCommandRuleOverrides??{});if(a.push(` Rule customizations: ${o.length}`),n.ruleActivation)a.push(` Rule activation: ${n.ruleActivation.id} — ${n.ruleActivation.enabled?"on":"off"} via ${n.ruleActivation.source}`);return a.join(`
|
|
189
|
+
`)}function ne(n){return JSON.stringify(n,null,2)}function N0(n){return new Promise((t)=>{process.stdout.write(`${n}
|
|
190
|
+
`,()=>t())})}async function nl(n){let t=Pr(n);if(!t)return 1;try{let r=C2(t.command,{cwd:t.cwd}),e=!!process.env.NO_COLOR||!process.stdout.isTTY;return await N0(t.json?ne(r):Nr(r,{asciiOnly:e})),0}catch(r){if(!(r instanceof rr)&&!(r instanceof k2)&&!(r instanceof i2))throw r;if(t.json)return await N0(JSON.stringify({error:r.message})),1;return console.error(r.message),1}}var tl="2.0.7",C=" ",Z2="cc-safety-net";function rl(n){return n.argument?`${n.flags} ${n.argument}`:n.flags}function vi(n){return Math.max(...n.map((t)=>rl(t).length))}function oi(n){return Math.max(...n.map((t)=>t.usage.length))}function bi(n){return Math.max(...n.map((t)=>`${Z2} ${t.usage}`.length))}function fi(n,t){let r=`${Z2} ${n.usage}`;return`${C}${r.padEnd(t+2)}${n.description}`}function v2(n,t){return`${C}${n.padEnd(Math.max(40,n.length+2))}${t}`}function ot(n,t=console.log){let r=[];if(r.push(`${Z2} ${n.name}`),r.push(""),r.push(`${C}${n.description}`),r.push(""),r.push("USAGE:"),r.push(`${C}${Z2} ${n.usage}`),r.push(""),n.subcommands&&n.subcommands.length>0){r.push("SUBCOMMANDS:");let e=oi(n.subcommands);for(let a of n.subcommands)r.push(`${C}${a.usage.padEnd(e+2)}${a.description}`);r.push("")}if(n.options.length>0){r.push("OPTIONS:");let e=vi(n.options);for(let a of n.options){let l=rl(a),s=a.default?`${a.description} (default: ${a.default})`:a.description;r.push(`${C}${l.padEnd(e+2)}${s}`)}r.push("")}if(n.examples&&n.examples.length>0){r.push("EXAMPLES:");for(let e of n.examples)r.push(`${C}${e}`)}t(r.join(`
|
|
191
|
+
`))}function te(){let n=na(),t=bi(n),r=[];r.push(`${Z2} v${tl}`),r.push(""),r.push("Blocks destructive commands and secret access."),r.push(""),r.push("COMMANDS:");for(let e of n)r.push(fi(e,t));r.push(""),r.push("GLOBAL OPTIONS:"),r.push(`${C}-h, --help Show help (use with command for command-specific help)`),r.push(`${C}-V, --version Show version`),r.push(""),r.push("HELP:"),r.push(`${C}${Z2} help <command> Show help for a specific command`),r.push(`${C}${Z2} <command> --help Show help for a specific command`),r.push(""),r.push("ENVIRONMENT VARIABLES:"),r.push(v2(`${k.level.name}=standard|strict|paranoid`,"Set session safety level")),r.push(v2(`${k.worktree.name}=1`,"Allow local git discards in linked worktrees")),r.push(v2(`${k.debug.name}=1`,"Print diagnostic messages to stderr")),r.push(v2(`${k.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),r.push(v2("CC_SAFETY_NET_HOME","Override rule config home directory")),r.push(""),r.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),r.push(v2(`${k.strict.name}=1`,"Force safety.overrides.fail_closed on")),r.push(v2(`${k.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),r.push(v2(`${k.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),r.push(v2(`${k.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),r.push(""),r.push("Documentation: https://ccsafetynet.com/docs"),console.log(r.join(`
|
|
192
|
+
`))}function el(){console.log(tl)}function Zn(n,t=console.log){let r=Un(n);if(!r)return!1;if(r.hidden||r.name.toLowerCase()!==n.toLowerCase())return!1;return ot(r,t),!0}import{existsSync as ve,readFileSync as Pl}from"node:fs";import{homedir as e5}from"node:os";import{join as pe}from"node:path";import*as x2 from"node:readline";function yi(n){return n==="install"?"Install":"Uninstall"}function hi(n){return n==="install"?"Installing":"Uninstalling"}function wi(n){return n==="install"?"into":"from"}function sl(n){return n?.available===!0}function xi(n,t){let r=new Set(t);return n.filter((e)=>r.has(e.target)).map((e)=>e.target)}function al(n,t,r){if(n.length===0||n.every((e)=>!e.available))return t;return Array.from({length:n.length},(e,a)=>a+1).map((e)=>(t+e*r+n.length)%n.length).find((e)=>sl(n[e]))}function $i(n,t,r){if(r.ctrl&&r.name==="c")return"interrupt";if(r.name==="escape"||t==="q")return"abort";if(n==="install"&&(t==="u"||t==="U"))return"update";if(r.name==="up"||t==="k")return"up";if(r.name==="down"||t==="j")return"down";if(r.name==="space"||t===" ")return"toggle";if(r.name==="return"||r.name==="enter")return"confirm";return null}function mi(n){return{cursor:n.findIndex((t)=>t.available),selected:[]}}function gi(n,t,r){if(r==="confirm"||r==="update"||r==="abort"||r==="interrupt")return{state:n,done:r};if(r==="up")return{state:{...n,cursor:al(t,n.cursor,-1)}};if(r==="down")return{state:{...n,cursor:al(t,n.cursor,1)}};let e=t[n.cursor];if(!sl(e))return{state:n};let a=n.selected.includes(e.target)?n.selected.filter((l)=>l!==e.target):xi(t,[...n.selected,e.target]);return{state:{...n,selected:a}}}var dl="◉",cl="◯",Ll=">",il=" ";function Di(n,t,r,e={}){let a=e.color!==!1,l=a?b.dim:(c)=>c,s=a?b.green:(c)=>c,d=a?b.bold:(c)=>c;return["",`${yi(n)} CC Safety Net ${wi(n)}:`,"",...t.map((c,L)=>{let i=r.selected.includes(c.target),u=L===r.cursor,o=i?dl:cl,p=u?Ll:il,f=c.available?"":` (${c.unavailableReason??"not installed"})`,v=`${o} ${c.label}${f}`,h=!c.available?l(v):i?s(v):u?d(v):v;return`${p} ${h}`}),"",n==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":t.some((c)=>c.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${n}. q/Esc: close`].join(`
|
|
193
|
+
`)}var ll=["global-hook","plugin"];function ki(n,t,r={}){let e=r.color!==!1?b.bold:(l)=>l;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((l,s)=>{let d=s===n,c=`${d?dl:cl} ${l}`;return`${d?Ll:il} ${d?e(c):c}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
194
|
+
`)}function pl(n){let{input:t,output:r}=n;x2.emitKeypressEvents(t);let e=t.isRaw===!0;t.setRawMode(!0),t.resume();let a=0,l=()=>{if(a===0)return;x2.moveCursor(r,0,-a),x2.cursorTo(r,0),x2.clearScreenDown(r)},s=()=>{l();let d=n.render();r.write(`${d}
|
|
195
|
+
`),a=d.split(`
|
|
196
|
+
`).length};return new Promise((d)=>{let c=(i)=>{t.off("keypress",L),t.setRawMode(e),t.pause(),l(),d(i)};function L(i,u){n.onKey(i,u,{finish:c,draw:s})}t.on("keypress",L),s()})}function ul(n={}){let t=0;return pl({input:n.input??process.stdin,output:n.output??process.stdout,render:()=>ki(t,n.globalHookInstalled===!0),onKey:(r,e,a)=>{if(e.ctrl&&e.name==="c"){a.finish(null),(n.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(e.name==="escape"||r==="q")return a.finish(null);if(e.name==="return"||e.name==="enter")return a.finish(ll[t]);if(e.name==="up"||e.name==="down"||r==="k"||r==="j")t=(t+1)%ll.length,a.draw()}})}function re(n=process.stdin,t=process.stdout){return Boolean(n.isTTY&&t.isTTY&&typeof n.setRawMode==="function")}function vl(n,t,r={}){let e=r.output??process.stdout,a=mi(t);return pl({input:r.input??process.stdin,output:e,render:()=>Di(n,t,a),onKey:(l,s,d)=>{let c=$i(n,l,s);if(!c)return;let L=gi(a,t,c);if(a=L.state,L.done==="interrupt"){d.finish(null),(r.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(L.done==="abort")return d.finish(null);if(L.done==="update")return d.finish("update");if(L.done==="confirm"){if(a.selected.length===0){e.write("\x07"),d.draw();return}d.finish([...a.selected]),e.write(`${hi(n)} selected integrations...
|
|
197
|
+
`);return}d.draw()}})}import{existsSync as bl,lstatSync as fl,mkdtempSync as ji,readFileSync as yt,rmSync as yl}from"node:fs";import{tmpdir as zi}from"node:os";import{dirname as Fi,join as Q2}from"node:path";import{fileURLToPath as Bi}from"node:url";var ee="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp";import{spawn as qi}from"node:child_process";var ae=(n,t)=>{let r=h2([...n],process.env);return new Promise((e)=>{let a=qi(r.cmd,r.args,{cwd:t,stdio:["ignore","pipe","pipe"]}),l=Ar(a),s=!1,d=setTimeout(()=>{s=!0,a.kill()},120000);a.on("error",(c)=>{clearTimeout(d),e({status:null,errorCode:c.code,stdout:l.stdout,stderr:[c.message,l.stderr].filter(Boolean).join(`
|
|
198
|
+
`)})}),a.on("close",(c)=>{clearTimeout(d),e({status:s?null:c,errorCode:s?"ETIMEDOUT":void 0,stdout:l.stdout,stderr:l.stderr})})})};var ol=Q2("amp","cc-safety-net.ts"),o2="cc-safety-net.ts";function Ji(n){return Q2(n,".config","amp","plugins",o2)}function Zi(){let n=Fi(Bi(import.meta.url));return[Q2(n,"..",ol),Q2(n,"..","..","..","dist",ol)]}function Qi(n=Zi()){let t=n.find((r)=>bl(r)&&fl(r).isFile());if(!t)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return t}function hl(n){try{return fl(n)}catch{return}}function wl(n){try{return JSON.parse(n)}catch{return}}function xl(n){return n.subarray(0,Buffer.byteLength(ee)).toString("utf-8")===ee}async function Qn(n,t,r){let e=await n(t,r);if(e.status===0)return e;throw Error([`Failed to run ${t.join(" ")}${e.status===null?"":` (exit ${e.status})`}.`,[e.stdout,e.stderr].filter(Boolean).join(`
|
|
187
199
|
`).trim()].filter(Boolean).join(`
|
|
188
|
-
`))}async function
|
|
200
|
+
`))}async function $l(n){let t=await n(["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.`}
|
|
189
201
|
${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.
|
|
190
202
|
${[t.stdout,t.stderr].filter(Boolean).join(`
|
|
191
|
-
`)}`.trim());let
|
|
192
|
-
`}async function
|
|
193
|
-
`)}function
|
|
194
|
-
`,t)+1;return/^[ \t]*/.exec(n.slice(e))?.[0]??""}function bt(n,t){let{start:e,end:r,end:a}=t;while($l(n[a]))a++;if(n[a]===","){if(r=a+1,n[r]===`
|
|
195
|
-
`)r++;return`${n.slice(0,e)}${n.slice(r)}`}a=t.start-1;while($l(n[a]))a--;if(n[a]===","){e=a;let l=n.lastIndexOf(`
|
|
196
|
-
`,e-1);if(l!==-1&&/^\s*$/.test(n.slice(l+1,e)))e=l}return`${n.slice(0,e)}${n.slice(r)}`}var Qn="npx -y cc-safety-net hook --kimi-code",er=`[[hooks]]
|
|
203
|
+
`)}`.trim());let r=wl(t.stdout),e=(Array.isArray(r)?r:[]).filter((a)=>x(a,"scope")==="user"&&x(a,"exists")===!0&&x(a,"viewerCanWrite")===!0).map((a)=>x(a,"cloneRef")).find((a)=>typeof a==="string"&&a.length>0);if(!e)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 e}async function ml(n,t){let r=ji(Q2(zi(),"cc-safety-net-amp-"));try{return await Qn(n,["amp","clone","user-plugins",r]),await t(r)}finally{yl(r,{recursive:!0,force:!0})}}function gl(n,t){let r=Q2(n,o2),e=hl(r);if(!e)return;if(e.isSymbolicLink()||!e.isFile())throw Error(`Refusing to ${t} ${o2} in your Amp personal plugins repository: not a regular file. Remove it there and rerun install --amp.`);let a=yt(r);if(xl(a))return a;throw Error(`Refusing to ${t} unmanaged file ${o2} in your Amp personal plugins repository. Remove it there and rerun install --amp.`)}async function Dl(n,t,r,e){if(await Qn(n,r,t),(await Qn(n,["git","status","--porcelain"],t)).stdout.trim()==="")return!1;return await Qn(n,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",e],t),await Qn(n,["git","push","origin","HEAD"],t),!0}function bt(n,t){let r=Ji(n),e=hl(r);if(!e)return;if(!e.isSymbolicLink()&&e.isFile()&&xl(yt(r))){yl(r);return}if(t==="keep")return;throw Error(`Local Amp plugin ${r} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function Xi(){let n=fn();if(!bl(n))return"";let t=wl(yt(n,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(ft(t))};
|
|
204
|
+
`}async function kl(n,t=Qi(),r=ae){let e=Buffer.concat([yt(t),Buffer.from(Xi(),"utf-8")]),a=await $l(r);return ml(r,async(l)=>{let s=`${a}/${o2}`;if(gl(l,"overwrite")?.equals(e))return bt(n,"fail"),{path:s,alreadyInstalled:!0};Z(Q2(l,o2),e);let d=await Dl(r,l,["git","add",o2],`chore: update cc-safety-net plugin to v${F()}`);return bt(n,"fail"),{path:s,alreadyInstalled:!d}})}async function ql(n,t=ae){let r=await $l(t);return ml(t,async(e)=>{let a=`${r}/${o2}`;if(!gl(e,"remove"))return bt(n,"keep"),{path:a,alreadyInstalled:!1};return await Dl(t,e,["git","rm",o2],`chore: remove cc-safety-net plugin v${F()}`),bt(n,"keep"),{path:a,alreadyInstalled:!0}})}import{existsSync as jl,mkdirSync as Yi,readFileSync as Si}from"node:fs";import{dirname as Hi}from"node:path";var le="npx -y cc-safety-net hook --agy-cli",$2="cc-safety-net";function wt(){return{PreToolUse:[{hooks:[{type:"command",command:le,timeout:30}]}]}}function zl(n){try{let t=JSON.parse(Si(n,"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 ${n}: ${t.message}`);throw t}}function Fl(n){let t=n[$2];if(t===void 0)return n[$2]=wt(),n[$2];if(!t||typeof t!=="object"||Array.isArray(t))throw Error(`Antigravity hooks config entry "${$2}" must be an object`);if(!Array.isArray(t.PreToolUse))t.PreToolUse=[];return t}function Bl(n){if(!Array.isArray(n.PreToolUse))return!1;return n.PreToolUse.some((t)=>Array.isArray(t.hooks)&&t.hooks.some((r)=>r.command===le))}function Ri(n){return Object.values(n).some((t)=>t.enabled!==!1&&Bl(t))}function Wi(n){if(n[$2]===void 0)return!1;let t=Fl(n);if(t.enabled!==!1||!Bl(t))return!1;return t.enabled=!0,!0}function Ai(n){if(n[$2]===void 0){n[$2]=wt();return}let t=Fl(n);t.PreToolUse??=[],t.enabled=!0,t.PreToolUse.push(wt().PreToolUse?.[0]??{hooks:[]})}function Ki(n){let t=!1;for(let r of Object.values(n)){if(!Array.isArray(r.PreToolUse))continue;r.PreToolUse=r.PreToolUse.flatMap((e)=>{if(!Array.isArray(e.hooks))return[e];let a=e.hooks.filter((l)=>l.command!==le);if(a.length!==e.hooks.length)t=!0;return a.length===0?[]:[{...e,hooks:a}]})}return t}function ht(n,t){Z(n,`${JSON.stringify(t,null,2)}
|
|
205
|
+
`)}function Jl(n){let t=kn(n);if(Yi(Hi(t),{recursive:!0}),!jl(t))return ht(t,{[$2]:wt()}),{path:t,alreadyInstalled:!1};let r=zl(t);if(Ri(r))return{path:t,alreadyInstalled:!0};if(Wi(r))return ht(t,r),{path:t,alreadyInstalled:!1};return Ai(r),ht(t,r),{path:t,alreadyInstalled:!1}}function Zl(n){let t=kn(n);if(!jl(t))return{path:t,alreadyInstalled:!1};let r=zl(t);if(!Ki(r))return{path:t,alreadyInstalled:!1};return ht(t,r),{path:t,alreadyInstalled:!0}}import{spawn as Vi,spawnSync as Mi}from"node:child_process";var O=M.map((n)=>({target:n.id,flag:n.flag,label:j(n.id),probeCommand:n.probeCommand})),Ql=new Map(O.map((n)=>[n.flag,n.target]));function se(n){let t=new Set(n);return O.map((r)=>r.target).filter((r)=>t.has(r))}async function Xl(n,t){for(let r of n)await t(r)}var Yl=5000;function Gi(n){let t=h2([...n],process.env),r=Mi(t.cmd,t.args,{env:process.env,stdio:"ignore",timeout:Yl});return!r.error&&r.status===0}function ce(n){return new Promise((t)=>{let r=h2([...n],process.env),e=Vi(r.cmd,r.args,{env:process.env,stdio:"ignore"}),a=!1,l=(d)=>{if(a)return;a=!0,clearTimeout(s),t(d)},s=setTimeout(()=>{e.kill(),l(!1)},Yl);e.on("error",()=>l(!1)),e.on("close",(d)=>l(d===0))})}function Ui(n=Gi,t={}){let r=new Set(t.configuredTargets??[]);if(t.async)return Promise.all(O.map(async(a)=>({target:a.target,flag:a.flag,label:a.label,...de(t.action,await n(a.probeCommand),r.has(a.target))})));let e=n;return O.map((a)=>({target:a.target,flag:a.flag,label:a.label,...de(t.action,e(a.probeCommand),r.has(a.target))}))}function Sl(n=ce,t={}){return Ui(n,{...t,async:!0})}function Hl(n,t){let r=new Set(t.configuredTargets??[]);return n.map((e)=>({...e,...de(t.action,e.available,r.has(e.target))}))}function de(n,t,r){if(n==="uninstall")return r?{available:!0}:{available:!1,unavailableReason:"not installed"};if(n==="install"&&r)return{available:!1,unavailableReason:"already installed"};if(!t)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as Rl,readdirSync as Ci,rmSync as Oi}from"node:fs";import{join as an}from"node:path";function xt(n,t=process.platform){let r=an(process.env.npm_config_cache||(t==="win32"?an(process.env.LOCALAPPDATA||an(n,"AppData","Local"),"npm-cache"):an(n,".npm")),"_npx");if(!Rl(r))return;Ci(r).filter((e)=>Rl(an(r,e,"node_modules","cc-safety-net"))).forEach((e)=>{Oi(an(r,e),{recursive:!0,force:!0})})}import{existsSync as Al,mkdirSync as Ti,readFileSync as Kl}from"node:fs";import{dirname as _i,join as Wl}from"node:path";var Xn="npx -y cc-safety-net hook --kimi-code",Le=`[[hooks]]
|
|
197
206
|
event = "PreToolUse"
|
|
198
|
-
command = "${
|
|
199
|
-
`).reduce((e
|
|
200
|
-
`)}function
|
|
201
|
-
`,t+1);return
|
|
202
|
-
`,
|
|
203
|
-
${a}${
|
|
204
|
-
`;return`${
|
|
205
|
-
|
|
206
|
-
${
|
|
207
|
-
`}function
|
|
208
|
-
`),{path:t,alreadyInstalled:!1};let
|
|
209
|
-
`;return
|
|
210
|
-
|
|
211
|
-
`)
|
|
212
|
-
`)},
|
|
213
|
-
`)
|
|
214
|
-
|
|
215
|
-
`)}
|
|
216
|
-
|
|
217
|
-
`)
|
|
218
|
-
`)
|
|
219
|
-
`),uninstall:()=>rn("pi")}},Rl=["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(`
|
|
220
|
-
`);function d5(n){if(Fn({homeDir:n,cwd:process.cwd()}).status!=="configured")return Rl;return[Rl,"",b.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(`
|
|
207
|
+
command = "${Xn}"`,ie=`{ event = "PreToolUse", command = "${Xn}" }`;function Vl(n){return Wl(process.env.KIMI_CODE_HOME??Wl(n,".kimi-code"),"config.toml")}function Ei(n){return n.split(`
|
|
208
|
+
`).reduce((r,e)=>{if(/^\s*\[/.test(e))return r.activeTable=!0,r.lines.push(e),r;if(!r.activeTable&&/^\s*hooks\s*=\s*\[\s*]\s*(?:#.*)?$/.test(e))return r;return r.lines.push(e),r},{activeTable:!1,lines:[]}).lines.join(`
|
|
209
|
+
`)}function Pi(n,t){if(n[t]!=="#")return t;let r=n.indexOf(`
|
|
210
|
+
`,t+1);return r===-1?n.length:r+1}function Ii(n,t){return ct(n,t,{skipComment:Pi,stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"})}function Ml(n){let t=!1,r=0;while(r<n.length){let e=n.indexOf(`
|
|
211
|
+
`,r),a=e===-1?n.length:e,l=n.slice(r,a);if(/^\s*\[/.test(l))t=!0;if(!t){let s=/^(\s*)hooks\s*=\s*\[/.exec(l);if(s){let d=r+s[0].lastIndexOf("[");return{start:d,end:Ii(n,d)}}}r=e===-1?n.length:e+1}return}function Ni(n,t){let r=n.slice(0,t.end).trimEnd(),e=Z0(n,t.end),a=e===""?" ":`${e} `,l=!r.endsWith("[")&&!r.endsWith(",");return`${r}${l?",":""}
|
|
212
|
+
${a}${ie}${n.slice(t.end)}`}function n5(n){let t=Ml(n);if(t&&n.slice(t.start+1,t.end).trim())return Ni(n,t);let r=Ei(n).trimEnd();if(r==="")return`${Le}
|
|
213
|
+
`;return`${r}
|
|
214
|
+
|
|
215
|
+
${Le}
|
|
216
|
+
`}function t5(n){return n.split(/(?=^\s*\[)/m).filter((r)=>!/^\s*\[\[hooks]]\s*$/m.test(r)||!r.includes(Xn)).join("").trimEnd()}function r5(n,t){let r=n.indexOf(ie,t.start);if(r===-1||r>t.end)return n;return Lt(n,{start:r,end:r+ie.length})}function Gl(n){let t=Vl(n);if(Ti(_i(t),{recursive:!0}),!Al(t))return Z(t,`${Le}
|
|
217
|
+
`),{path:t,alreadyInstalled:!1};let r=Kl(t,"utf-8");if(r.includes(Xn))return{path:t,alreadyInstalled:!0};return Z(t,n5(r)),{path:t,alreadyInstalled:!1}}function Ul(n){let t=Vl(n);if(!Al(t))return{path:t,alreadyInstalled:!1};let r=Kl(t,"utf-8");if(!r.includes(Xn))return{path:t,alreadyInstalled:!1};let e=Ml(r),a=e?r5(r,e):`${t5(r)}
|
|
218
|
+
`;return Z(t,a),{path:t,alreadyInstalled:!0}}var ue="safety-net@cc-marketplace",Cl=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),Ol=new Set(["antigravity-cli","cursor","hermes-agent","kimi-code"]);function oe(n){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(n??"")}function Il(n){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(n??"")}function a5(n){return/^Marketplace `cc-marketplace`\s*$/m.test(n??"")}var Nl={"claude-code":{installCommands:(n)=>{let t=Nn(n,"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"]],...Dr(n).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:Nn(n,ue)?[["claude","plugin","uninstall",ue]]:[],update:t}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(n,t)=>{let r=t??await a2(["codex","plugin","list"]),e=Il(r);return{commands:[e||a5(r)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:oe(r)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:e}},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 n=await a2(["copilot","plugin","list"]),t=[...Ga(n)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...Ua(n)?[["copilot","plugin","uninstall",Ka]]:[]];if(Va(n))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",e2]],cleanupCommands:t,update:!0};return{commands:[Ma(await a2(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",e2]],cleanupCommands:t}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(n)=>{let t=Jr(n);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:Gr,installCommands:()=>({commands:D0()}),uninstallCommands:[["openclaw","plugins","uninstall",z,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
|
|
219
|
+
`)},opencode:{beforeInstall:Or,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 gt(){return process.env.HOME??e5()}function n3(n,t=(r)=>r){try{let r=JSON.parse(t(Pl(n,"utf-8")));if(!r||typeof r!=="object"||Array.isArray(r))throw Error(`Settings file ${n} must be a JSON object`);return r}catch(r){if(r instanceof SyntaxError)throw Error(`Failed to parse ${n}: ${r.message}`);throw r}}function l5(n){let t=pe(qn(n),"settings.json");if(!ve(t))return;let r=n3(t,V),e=r.enabledPlugins;if(!e||typeof e!=="object"||Array.isArray(e))return;if(e[e2]!==!1)return;let a=Pl(t,"utf-8"),l=a.replace(new RegExp(`("${e2}"\\s*:\\s*)false`),"$1true");return e[e2]=!0,Z(t,l!==a?l:`${JSON.stringify(r,null,2)}
|
|
220
|
+
`),`Enabled ${e2} plugin in ${t}`}function s5(n){let t=Tr(n);if(!ve(t))return;let r=n3(t);if(!Array.isArray(r.packages))return;let e=r.packages.find((a)=>!!a&&typeof a==="object"&&!Array.isArray(a)&&_r(a.source)&&("extensions"in a));if(!e)return;return delete e.extensions,Z(t,`${JSON.stringify(r,null,2)}
|
|
221
|
+
`),`Enabled npm:cc-safety-net extensions in ${t}`}function Tl(n,t){let r=B({label:t,booleans:Object.fromEntries(O.map((l)=>[l.target,[l.flag]]))},n),e=r.errors[0];if(e)throw Error(e);let a=O.filter((l)=>r.flags[l.target]).map((l)=>l.target);if(a.length!==1)throw Error(`Choose exactly one ${t} target: ${[...Ql.keys()].join(", ")}`);return a[0]}async function t3(n=gt(),t=E2){let[r,e,a]=await Promise.all([t(["amp","plugins","list"],30000),t(["codex","plugin","list"],30000),t(["copilot","--binary-version"])]);return{codexPluginListOutput:e,hooks:en(process.cwd(),{homeDir:n,ampPluginListOutput:r,codexPluginListOutput:e,copilotCliVersion:a})}}async function d5(n,t=E2){let r=await t3(gt(),t);return r.hooks.filter((e)=>n==="install"?e.configured:e.detected||e.inspectionStatus==="not-inspected").filter((e)=>e.platform!=="codex"||!oe(r.codexPluginListOutput)||Il(r.codexPluginListOutput)).map((e)=>e.platform)}function c5(n,t,r){if(t.length>0)return{finish:async()=>[Tl(t,n)]};if(!r.selectTargets&&!re(r.input,r.output))return{finish:async()=>[Tl(t,n)]};let e=r.detectConfiguredTargets??(()=>d5(n,r.fetchVersion)),a=Promise.all([Sl(r.probeTargets),e()]);return{ready:a,finish:async()=>{let[l,s]=await a,d=Hl(l,{action:n,configuredTargets:s}),c=r.selectTargets?await r.selectTargets(n,El(n,d)):await vl(n,El(n,d),{input:r.input,output:r.output});if(c==="update")return c;if(!c||c.length===0)return null;return se(c)}}}async function X2(n,t,r=!1,e){let a=Nl[n];a.beforeInstall?.(t);let l=typeof a.installCommands==="function"?await a.installCommands(t,e):{commands:a.installCommands};return await Kr(l.commands),await h0(l.cleanupCommands??[]),[`${l.update||r?"Updated":"Installed"} ${j(n)} integration`,a.postInstallMessage].filter(Boolean).join(`
|
|
222
|
+
`)}async function ln(n){let t=Nl[n];if(!t.uninstallCommands)throw Error(`${j(n)} uninstall is not supported`);return await Kr(t.uninstallCommands),`Uninstalled ${j(n)} integration`}function L5(n){let t=M0(n);return t.alreadyInstalled?`Uninstalled OpenCode plugin from ${t.path}`:`OpenCode plugin not installed in ${t.path}`}var i5={"antigravity-cli":{install:Jl,uninstall:Zl},cursor:{install:t0,uninstall:r0},"kimi-code":{install:Gl,uninstall:Ul}};function sn(n,t,r,e=!1){if(n==="install"&&!e)xt(r);let a=i5[t][n](r),l=j(t),s=n!=="install"?"Uninstalled":e?"Updated":"Installed";return n==="install"&&a.alreadyInstalled?e?`${l} hook up to date in ${a.path}`:`${l} hook already installed in ${a.path}`:n==="uninstall"&&!a.alreadyInstalled?`${l} hook not installed in ${a.path}`:`${s} ${l} hook ${n==="install"?"in":"from"} ${a.path}`}var p5={amp:{install:kl,uninstall:ql,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:c0,uninstall:L0,afterInstall:async(n)=>{let t=Rr(n);return await a2(["hermes","plugins","enable",G,"--no-allow-tool-override"]),!t},beforeUninstall:async(n)=>{Hr(n);try{await a2(["hermes","plugins","disable",G])}catch(t){console.warn(`${t instanceof Error?t.message:String(t)}
|
|
223
|
+
Removing the plugin files anyway; ${G} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function $t(n,t,r,e=!1){let a=p5[t];if(n==="uninstall")await a.beforeUninstall?.(r);let l=n==="install"?await a.install(r):await a.uninstall(r),s=n==="install"&&await a.afterInstall?.(r),d=j(t),c=!s&&(n==="install"&&l.alreadyInstalled||n==="uninstall"&&!l.alreadyInstalled);return[c?n==="install"?`${d} plugin ${e?"up to date":"already installed"} at ${l.path}`:`${d} plugin not installed at ${l.path}`:`${n!=="install"?"Uninstalled":e?"Updated":"Installed"} ${d} plugin ${n==="install"?"at":"from"} ${l.path}`,c?void 0:a.restartNote].filter(Boolean).join(`
|
|
224
|
+
`)}var u5={amp:{install:(n,t)=>$t("install","amp",n,t),uninstall:(n)=>$t("uninstall","amp",n)},"antigravity-cli":{install:(n,t)=>sn("install","antigravity-cli",n,t),uninstall:(n)=>sn("uninstall","antigravity-cli",n)},"claude-code":{install:(n,t)=>X2("claude-code",n,t),uninstall:()=>ln("claude-code")},codex:{install:(n,t,r)=>X2("codex",n,t,r),uninstall:()=>ln("codex")},"copilot-cli":{install:async(n,t)=>[await X2("copilot-cli",n,t),l5(n)].filter(Boolean).join(`
|
|
225
|
+
`),uninstall:()=>ln("copilot-cli")},cursor:{install:(n,t)=>sn("install","cursor",n,t),uninstall:(n)=>sn("uninstall","cursor",n)},"gemini-cli":{install:(n,t)=>X2("gemini-cli",n,t),uninstall:()=>ln("gemini-cli")},"hermes-agent":{install:(n,t)=>{if(!t)xt(n);return $t("install","hermes-agent",n,t)},uninstall:(n)=>$t("uninstall","hermes-agent",n)},"kimi-code":{install:(n,t)=>sn("install","kimi-code",n,t),uninstall:(n)=>sn("uninstall","kimi-code",n)},openclaw:{install:async(n,t)=>{let r=await X2("openclaw",n,t);return await k0(),r},uninstall:(n)=>{return Gr(n),ln("openclaw")}},opencode:{install:async(n,t)=>{let r=await X2("opencode",n,t);return await W0(n),r},uninstall:(n)=>L5(n)},pi:{install:async(n,t)=>[await X2("pi",n,t),s5(n)].filter(Boolean).join(`
|
|
226
|
+
`),uninstall:()=>ln("pi")}},_l=["Install CC Safety Net as a native Kimi Code plugin:",""," 1. Start Kimi Code and run: /plugins install https://github.com/kenryu42/cc-safety-net"," Confirm the trust prompt; it defaults to cancel."," 2. Run /reload, or start a new session.","","Note: Kimi Code hooks are fail-open. When the hook process cannot start, crashes, or times","out, Kimi Code allows the tool call."].join(`
|
|
227
|
+
`);function v5(n){if(Fn({homeDir:n,cwd:process.cwd()}).status!=="configured")return _l;return[_l,"",b.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(`
|
|
221
228
|
`))].join(`
|
|
222
|
-
`)}function
|
|
223
|
-
`)}),
|
|
224
|
-
`),0;if(
|
|
225
|
-
`);return}if(c==="plugin"){l.write(`${
|
|
226
|
-
`);return}}let
|
|
227
|
-
`)}),0}catch(
|
|
228
|
-
Check file permissions for the target config file and parent directory.`;if(
|
|
229
|
-
Check that the target config path and parent directory exist.`;if(
|
|
230
|
-
Check that every parent path component is a directory.`;return t}import{join as T5}from"node:path";var Tl="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Cache path | Priority |\n|-------|-------------|---------------|------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | `~/.cc-safety-net/cache/rulebooks/` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | `.cc-safety-net/cache/rulebooks/` | Second |\n| GitHub source | Listed in a local `rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` in the source repository | Consumer local cache | Source order |\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule sync`/`rule verify` report the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- GitHub sources use `owner/repo#ref/<rulebook-name>`.\n- GitHub refs must be one path segment, such as a tag, SHA, or branch name without `/`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Fixtures are shape-validated only; CC Safety Net does not execute them.\n\n## Matching Behavior\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; it adds the source and syncs it.\n5. Run `cc-safety-net rule sync` after manual `rule.json` changes or local rulebook edits.\n6. Run `cc-safety-net rule verify` to validate config, lock/cache state, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n7. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nAn edited or invalid local rulebook keeps its last synced, digest-verified cached version enforced until `cc-safety-net rule sync` validates the edit. A missing lock entry or cache, a cache digest mismatch, or an invalid cached rulebook makes that source inactive; a missing lockfile or an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Repair the reported condition, then run `cc-safety-net rule sync`. Run `cc-safety-net status` to see degraded sources.\n";function Yn(n,t){if(!n.ok){v5(n);return}b5(n),console.log(t),console.log("Rule config synced."),console.log(""),p5(n.entries)}function p5(n){if(n.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${n.length}):`);for(let t of n)console.log(` - ${t.name} ${t.version} (${u5(t.ruleCount??0)})`),console.log(` Source: ${Ot(t)}`)}function u5(n){return`${n} ${n===1?"rule":"rules"}`}function El(n,t){J2("Active sources",n.rulebooks,(e)=>[`[${e.source}] ${e.name} ${e.version}`,` Source: ${t[e.source].get(e.spec)??e.spec}`]),J2("Active rules",n.rules,(e)=>[`[${o5(n,e.name)}] ${e.name}`,` Command: ${e.subcommand?`${e.command} ${e.subcommand}`:e.command}`,` Block args: ${e.block_args.join(", ")}`,` Reason: ${e.reason}`]),J2("Disabled rules",_l(n,"off"),(e)=>[e.key]),J2("Reason overrides",_l(n,"reason"),(e)=>[e.key,` Reason: ${e.value.reason}`]),J2("Transparent wrappers",n.transparent_wrappers,(e)=>[e]),J2("Issues",n.errors,(e)=>[e]),J2("Warnings",n.warnings,(e)=>[e])}function J2(n,t,e){if(t.length===0){console.log(`${n}: (none)`);return}console.log(`${n} (${t.length}):`);for(let r of t){let[a,...l]=e(r);console.log(` - ${a}`);for(let d of l)console.log(` ${d}`)}}function o5(n,t){return n.rulebooks.find((e)=>e.rules.includes(t))?.source??"project"}function _l(n,t){return Object.entries({...n.userConfig?.overrides??{},...n.projectConfig?.overrides??{}}).filter((e)=>{if(t==="off")return e[1]==="off";return!!e[1]&&typeof e[1]==="object"}).map(([e,r])=>({key:e,value:r}))}function v5(n){for(let t of n.errors)console.error(t)}function b5(n){if(!n.warnings||n.warnings.length===0)return;for(let t of n.warnings)console.warn(t)}import{dirname as Pl,join as xt}from"node:path";var f5=".safety-net.json",h5="~/.cc-safety-net/config.json";async function n3(n){return[await Il({legacyPath:Nl({cwd:n.cwd}),configPath:_(n.cwd),defaultRulebookName:"project-rules",migratedFrom:f5,cleanup:n.cleanup,syncOptions:{cwd:n.cwd}}),await Il({legacyPath:pn(),configPath:E(),defaultRulebookName:"user-rules",migratedFrom:h5,cleanup:n.cleanup,syncOptions:{cwd:n.cwd,global:!0}})].every((e)=>e)?0:1}async function Il(n){let t=U(n.syncOptions),e=D(t.filesystemScope,n.legacyPath),r=g(e);if(r===null)return console.log(`No legacy config found at ${n.legacyPath}`),!0;let a=w5(r);if(!a.ok){for(let v of a.errors)console.error(v);return!1}let l=O(t.configTarget);if(l.errors.length>0){for(let v of l.errors)console.error(v);return!1}let d=l.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},s=x5(Pl(n.configPath),d.rules,n.defaultRulebookName,n.migratedFrom,t.filesystemScope),c=xt(Pl(n.configPath),s,"rulebook.json"),i=D(t.filesystemScope,c),L=[ur(t.configTarget),ur(i),ur(t.lockTarget)],u=await y5(n,t.configTarget,i,s,a.config.rules,d.rules.includes(s)?d.rules:[...d.rules,s],d.overrides??{},d.transparent_wrappers??[]);if(!u.ok){D5(L);for(let v of u.errors)console.error(v);return!1}if(!n.cleanup)return console.log(`Migrated legacy config at ${n.legacyPath}. Legacy file is no longer used.`),!0;if(!g5(t.configTarget,i,s,n.migratedFrom,a.config.rules))return console.error(`Migration cleanup verification failed for ${n.legacyPath}`),!1;return cn(e),console.log(`Deleted legacy config at ${n.legacyPath}`),!0}async function y5(n,t,e,r,a,l,d,s){try{return T(t,{version:1,rules:l,overrides:d,transparent_wrappers:s}),T(e,$5(r,n.migratedFrom,a)),await W2(n.syncOptions)}catch(c){return{ok:!1,errors:[c instanceof Error?c.message:String(c)]}}}function w5(n){try{let t=JSON.parse(n),e=Xt(t);if(e.errors.length>0)return{ok:!1,errors:e.errors};return{ok:!0,config:{version:1,rules:t.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function x5(n,t,e,r,a){let l=t.find((d)=>m5(D(a,xt(n,d,"rulebook.json")))===r);if(l)return l;if(g(D(a,xt(n,e,"rulebook.json")))===null)return e;for(let d=2;;d++){let s=`${e}-${d}`;if(g(D(a,xt(n,s,"rulebook.json")))===null)return s}}function $5(n,t,e){return{rulebook_version:1,name:n,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:t,allowed_commands:[...new Set(e.map((r)=>r.command))],rules:e,tests:e.map((r)=>({command:[r.command,r.subcommand,r.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:r.name}))}}function g5(n,t,e,r,a){if(!O(n).config?.rules.includes(e))return!1;try{let d=g(t);if(d===null)return!1;let s=JSON.parse(d);return s.migrated_from===r&&JSON.stringify(s.rules)===JSON.stringify(a)}catch{return!1}}function ur(n){return{target:n,content:g(n)}}function D5(n){for(let t of n){if(t.content===null){cn(t.target);continue}w2(t.target,t.content)}}function m5(n){let t=g(n);if(t===null)return null;try{let e=JSON.parse(t);return typeof e.migrated_from==="string"?e.migrated_from:null}catch{return null}}import{mkdir as k5,readFile as q5,writeFile as j5}from"node:fs/promises";import{dirname as F5,join as z5}from"node:path";var B5=86400000,J5=604800000;async function e3(n=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=Et();if(!t)return null;let e=z5(t,".cc-safety-net","update-check.json"),r=await Z5(e,n);if(!r.lastCheck||n-r.lastCheck>B5){let d=await E2();if(r.lastCheck=n,d.latestVersion)r.latestVersion=d.latestVersion;if(!await t3(e,r))return null;if(d.error)return null}let a=r.latestVersion,l=j();if(!a||!ve(a,l))return null;if(r.notifiedVersion===a&&r.notifiedAt!==void 0&&n-r.notifiedAt<J5)return null;if(r.notifiedVersion=a,r.notifiedAt=n,!await t3(e,r))return null;return`UPDATE_AVAILABLE: cc-safety-net v${a} is available (running v${l}). 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 Z5(n,t){let e=await q5(n,"utf8").then((l)=>JSON.parse(l)).catch(()=>{return});if(!e||typeof e!=="object"||Array.isArray(e))return{};let r=e,a=(l)=>typeof l==="number"&&Number.isFinite(l)&&l<=t?l:void 0;return{lastCheck:a(r.lastCheck),latestVersion:typeof r.latestVersion==="string"?r.latestVersion:void 0,notifiedVersion:typeof r.notifiedVersion==="string"?r.notifiedVersion:void 0,notifiedAt:a(r.notifiedAt)}}async function t3(n,t){return k5(F5(n),{recursive:!0,mode:448}).then(()=>j5(n,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{dirname as Q5,join as X5,resolve as or}from"node:path";var a3="CC Safety Net Config",Y5="═".repeat(a3.length),S5="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",H5=new Set(["rule.json","rule.lock","cache"]);function l3(n={}){try{return A5(n)}catch(t){if(t instanceof Z)return console.error(t.message),1;throw t}}function A5(n){let t=n.cwd??process.cwd(),e=n.userConfigPath??E(),r=n.projectConfigPath??_(t),a=n.legacyUserConfigPath??pn(),l=n.legacyProjectConfigPath??Sr(t),d=or(t,Ut),s=Q5(e),c=P({cwd:t,userConfigPath:e,projectConfigPath:r}),i=P({cwd:t}),L=D(c.userScope,e),u=D(c.projectScope,r),v=n.legacyUserConfigPath?sn(n.legacyUserConfigPath,"user policy"):D(i.userScope,a),p=n.legacyProjectConfigPath?sn(n.legacyProjectConfigPath,"project policy"):D(i.projectScope,l),f=!1,o=!1,h=[],x=[],w=W5(D(i.projectScope,d));if(K5(),g(L)!==null){let y=a2(L);if(y.errors.push(...l2(e,R2({userConfigDir:s}),{userConfigDir:s},c.userScope)),h.push({scope:"User",path:e,result:y,schema:"rules",sourceDisplayMap:x2(e,c.userScope),target:L}),y.errors.length>0)f=!0}if(g(v)!==null)if(o=!0,g(L)!==null)x.push($t("user","cleanup"));else{let y=Yt(v);if(h.push({scope:"User",path:a,result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:v}),x.push($t("user",y.errors.length>0?"fix-or-delete":"migrate")),y.errors.length>0)f=!0}if(g(u)!==null){let y=a2(u);if(y.errors.push(...l2(r,K2(r),{userConfigDir:s},c.projectScope)),h.push({scope:"Project",path:or(r),result:y,schema:"rules",sourceDisplayMap:x2(r,c.projectScope),target:u}),y.errors.length>0)f=!0;if(g(p)!==null)o=!0,x.push($t("project","cleanup"))}else if(g(p)!==null){o=!0,f=!0;let y=Yt(p);h.push({scope:"Project",path:or(l),result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:p}),x.push($t("project",y.errors.length>0?"fix-or-delete":"migrate"))}if(w?.result.errors.length)f=!0;if(h.length===0&&!w)return console.log(`
|
|
231
|
-
No config files found. Using built-in rules only.`),0;for(let y of h)if(y.inactive)
|
|
232
|
-
Added $schema to ${y.scope.toLowerCase()} config.`);
|
|
233
|
-
${b.red(y)}`);if(
|
|
234
|
-
Config validation failed.`),1;return console.log(
|
|
229
|
+
`)}function El(n,t){return t.map((r)=>n==="install"&&r.target==="kimi-code"&&r.unavailableReason==="already installed"?{...r,available:!0,unavailableReason:void 0,label:`${r.label} (global hook installed)`}:r)}function o5(n,t){if(n.selectKimiInstallMethod)return n.selectKimiInstallMethod();if(!re(n.input,n.output))return Promise.resolve("global-hook");return ul({input:n.input,output:n.output,globalHookInstalled:Fn({homeDir:t,cwd:process.cwd()}).status==="configured"})}async function r3(n,t,r,e=!1,a){return u5[t][n](r,e,a)}function b5(n){let t=B({label:"update"},n).errors[0];if(t)throw Error(t)}async function f5(n,t=E2){let r=await t3(n,t),e=pe(qn(n),"installed-plugins");return{targets:se([...r.hooks.filter((l)=>l.platform!=="copilot-cli"&&l.detected).map((l)=>l.platform),...[nt,Aa,Wa].flatMap((l)=>ve(pe(e,...l))?["copilot-cli"]:[]),...Nn(n,ue)?["claude-code"]:[],...oe(r.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:r.codexPluginListOutput}}async function y5(n){let t=gt(),r=n.output??process.stdout,e=f5(t,n.fetchVersion??E2).then(async(d)=>{let c=new Set(d.targets);return{targets:d.targets,codexPluginListOutput:d.codexPluginListOutput,available:new Map(await Promise.all(O.filter((L)=>c.has(L.target)&&Cl.has(L.target)).map(async(L)=>[L.target,await ce(L.probeCommand)])))}}),a=await Dn(n.showBanner??!0,()=>({ready:e,finish:()=>e}),()=>gn({input:n.input??process.stdin,output:r}),{loadingMessage:"Checking installed integrations…",output:r});if(a.targets.length===0)return r.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),0;let l=a.targets.some((d)=>Ol.has(d))?await Promise.resolve().then(()=>{return xt(t),null}).catch((d)=>mt(d)):null,s=await En(Promise.all(a.targets.map((d)=>{if(Cl.has(d)&&!a.available.get(d))return Promise.resolve({message:`${j(d)} not found; skipped`,failed:!1});if(l!==null&&Ol.has(d))return Promise.resolve({message:l,failed:!0});return r3("install",d,t,!0,a.codexPluginListOutput).then((c)=>({message:c,failed:!1}),(c)=>({message:mt(c),failed:!0}))})),{loadingMessage:`Updating ${a.targets.length} integration${a.targets.length===1?"":"s"}…`,output:r});return s.forEach((d)=>{d.failed?console.error(d.message):r.write(`${d.message}
|
|
230
|
+
`)}),s.some((d)=>d.failed)?1:0}function be(n,t={}){return Promise.resolve().then(()=>b5(n)).then(()=>y5(t)).catch((r)=>{return console.error(mt(r)),1})}async function Yn(n,t,r={}){try{let e=await Dn(!0,()=>c5(n,t,r),()=>gn({input:r.input??process.stdin,output:r.output??process.stdout}),{loadingMessage:n==="install"?"Checking available integrations…":"Checking installed integrations…",output:r.output??process.stdout});if(!e)return(r.output??process.stdout).write(`Cancelled: nothing was ${n}ed.
|
|
231
|
+
`),0;if(e==="update")return(r.runUpdate??(()=>be([],{fetchVersion:r.fetchVersion,input:r.input,output:r.output,showBanner:!1})))();let a=gt(),l=r.output??process.stdout;return await Xl(e,async(s)=>{if(s==="kimi-code"&&n==="install"){let c=await o5(r,a);if(c===null){l.write(`Cancelled: Kimi Code integration was not installed.
|
|
232
|
+
`);return}if(c==="plugin"){l.write(`${v5(a)}
|
|
233
|
+
`);return}}let d=await En(r3(n,s,a),{loadingMessage:`${n==="install"?"Installing":"Uninstalling"} ${j(s)} integration…`,output:l});l.write(`${d}
|
|
234
|
+
`)}),0}catch(e){return console.error(mt(e)),1}}function mt(n){let t=n instanceof Error?n.message:String(n),r=typeof n==="object"&&n!==null&&"code"in n?n.code:null;if(r==="EACCES"||r==="EPERM")return`${t}
|
|
235
|
+
Check file permissions for the target config file and parent directory.`;if(r==="ENOENT")return`${t}
|
|
236
|
+
Check that the target config path and parent directory exist.`;if(r==="ENOTDIR")return`${t}
|
|
237
|
+
Check that every parent path component is a directory.`;return t}import{join as t8}from"node:path";var e3="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Cache path | Priority |\n|-------|-------------|---------------|------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | `~/.cc-safety-net/cache/rulebooks/` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | `.cc-safety-net/cache/rulebooks/` | Second |\n| GitHub source | Listed in a local `rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` in the source repository | Consumer local cache | Source order |\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule sync`/`rule verify` report the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- GitHub sources use `owner/repo#ref/<rulebook-name>`.\n- GitHub refs must be one path segment, such as a tag, SHA, or branch name without `/`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Fixtures are shape-validated only; CC Safety Net does not execute them.\n\n## Matching Behavior\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; it adds the source and syncs it.\n5. Run `cc-safety-net rule sync` after manual `rule.json` changes or local rulebook edits.\n6. Run `cc-safety-net rule verify` to validate config, lock/cache state, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n7. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nAn edited or invalid local rulebook keeps its last synced, digest-verified cached version enforced until `cc-safety-net rule sync` validates the edit. A missing lock entry or cache, a cache digest mismatch, or an invalid cached rulebook makes that source inactive; a missing lockfile or an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Repair the reported condition, then run `cc-safety-net rule sync`. Run `cc-safety-net status` to see degraded sources.\n";function Sn(n,t){if(!n.ok){$5(n);return}m5(n),console.log(t),console.log("Rule config synced."),console.log(""),h5(n.entries)}function h5(n){if(n.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${n.length}):`);for(let t of n)console.log(` - ${t.name} ${t.version} (${w5(t.ruleCount??0)})`),console.log(` Source: ${Pt(t)}`)}function w5(n){return`${n} ${n===1?"rule":"rules"}`}function l3(n,t){Y2("Active sources",n.rulebooks,(r)=>[`[${r.source}] ${r.name} ${r.version}`,` Source: ${t[r.source].get(r.spec)??r.spec}`]),Y2("Active rules",n.rules,(r)=>[`[${x5(n,r.name)}] ${r.name}`,` Command: ${r.subcommand?`${r.command} ${r.subcommand}`:r.command}`,` Block args: ${r.block_args.join(", ")}`,` Reason: ${r.reason}`]),Y2("Disabled rules",a3(n,"off"),(r)=>[r.key]),Y2("Reason overrides",a3(n,"reason"),(r)=>[r.key,` Reason: ${r.value.reason}`]),Y2("Transparent wrappers",n.transparent_wrappers,(r)=>[r]),Y2("Issues",n.errors,(r)=>[r]),Y2("Warnings",n.warnings,(r)=>[r])}function Y2(n,t,r){if(t.length===0){console.log(`${n}: (none)`);return}console.log(`${n} (${t.length}):`);for(let e of t){let[a,...l]=r(e);console.log(` - ${a}`);for(let s of l)console.log(` ${s}`)}}function x5(n,t){return n.rulebooks.find((r)=>r.rules.includes(t))?.source??"project"}function a3(n,t){return Object.entries({...n.userConfig?.overrides??{},...n.projectConfig?.overrides??{}}).filter((r)=>{if(t==="off")return r[1]==="off";return!!r[1]&&typeof r[1]==="object"}).map(([r,e])=>({key:r,value:e}))}function $5(n){for(let t of n.errors)console.error(t)}function m5(n){if(!n.warnings||n.warnings.length===0)return;for(let t of n.warnings)console.warn(t)}import{dirname as s3,join as Dt}from"node:path";var g5=".safety-net.json",D5="~/.cc-safety-net/config.json";async function L3(n){return[await d3({legacyPath:c3({cwd:n.cwd}),configPath:P(n.cwd),defaultRulebookName:"project-rules",migratedFrom:g5,cleanup:n.cleanup,syncOptions:{cwd:n.cwd}}),await d3({legacyPath:un(),configPath:I(),defaultRulebookName:"user-rules",migratedFrom:D5,cleanup:n.cleanup,syncOptions:{cwd:n.cwd,global:!0}})].every((r)=>r)?0:1}async function d3(n){let t=T(n.syncOptions),r=D(t.filesystemScope,n.legacyPath),e=m(r);if(e===null)return console.log(`No legacy config found at ${n.legacyPath}`),!0;let a=q5(e);if(!a.ok){for(let o of a.errors)console.error(o);return!1}let l=_(t.configTarget);if(l.errors.length>0){for(let o of l.errors)console.error(o);return!1}let s=l.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},d=j5(s3(n.configPath),s.rules,n.defaultRulebookName,n.migratedFrom,t.filesystemScope),c=Dt(s3(n.configPath),d,"rulebook.json"),L=D(t.filesystemScope,c),i=[fe(t.configTarget),fe(L),fe(t.lockTarget)],u=await k5(n,t.configTarget,L,d,a.config.rules,s.rules.includes(d)?s.rules:[...s.rules,d],s.overrides??{},s.transparent_wrappers??[]);if(!u.ok){B5(i);for(let o of u.errors)console.error(o);return!1}if(!n.cleanup)return console.log(`Migrated legacy config at ${n.legacyPath}. Legacy file is no longer used.`),!0;if(!F5(t.configTarget,L,d,n.migratedFrom,a.config.rules))return console.error(`Migration cleanup verification failed for ${n.legacyPath}`),!1;return Ln(r),console.log(`Deleted legacy config at ${n.legacyPath}`),!0}async function k5(n,t,r,e,a,l,s,d){try{return E(t,{version:1,rules:l,overrides:s,transparent_wrappers:d}),E(r,z5(e,n.migratedFrom,a)),await V2(n.syncOptions)}catch(c){return{ok:!1,errors:[c instanceof Error?c.message:String(c)]}}}function q5(n){try{let t=JSON.parse(n),r=Rt(t);if(r.errors.length>0)return{ok:!1,errors:r.errors};return{ok:!0,config:{version:1,rules:t.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function j5(n,t,r,e,a){let l=t.find((s)=>J5(D(a,Dt(n,s,"rulebook.json")))===e);if(l)return l;if(m(D(a,Dt(n,r,"rulebook.json")))===null)return r;for(let s=2;;s++){let d=`${r}-${s}`;if(m(D(a,Dt(n,d,"rulebook.json")))===null)return d}}function z5(n,t,r){return{rulebook_version:1,name:n,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:t,allowed_commands:[...new Set(r.map((e)=>e.command))],rules:r,tests:r.map((e)=>({command:[e.command,e.subcommand,e.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:e.name}))}}function F5(n,t,r,e,a){if(!_(n).config?.rules.includes(r))return!1;try{let s=m(t);if(s===null)return!1;let d=JSON.parse(s);return d.migrated_from===e&&JSON.stringify(d.rules)===JSON.stringify(a)}catch{return!1}}function fe(n){return{target:n,content:m(n)}}function B5(n){for(let t of n){if(t.content===null){Ln(t.target);continue}m2(t.target,t.content)}}function J5(n){let t=m(n);if(t===null)return null;try{let r=JSON.parse(t);return typeof r.migrated_from==="string"?r.migrated_from:null}catch{return null}}import{mkdir as Z5,readFile as Q5,writeFile as X5}from"node:fs/promises";import{dirname as Y5,join as S5}from"node:path";var H5=86400000,R5=604800000;async function p3(n=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=nr();if(!t)return null;let r=S5(t,".cc-safety-net","update-check.json"),e=await W5(r,n);if(!e.lastCheck||n-e.lastCheck>H5){let s=await P2();if(e.lastCheck=n,s.latestVersion)e.latestVersion=s.latestVersion;if(!await i3(r,e))return null;if(s.error)return null}let a=e.latestVersion,l=F();if(!a||!wr(a,l))return null;if(e.notifiedVersion===a&&e.notifiedAt!==void 0&&n-e.notifiedAt<R5)return null;if(e.notifiedVersion=a,e.notifiedAt=n,!await i3(r,e))return null;return`UPDATE_AVAILABLE: cc-safety-net v${a} is available (running v${l}). 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 W5(n,t){let r=await Q5(n,"utf8").then((l)=>JSON.parse(l)).catch(()=>{return});if(!r||typeof r!=="object"||Array.isArray(r))return{};let e=r,a=(l)=>typeof l==="number"&&Number.isFinite(l)&&l<=t?l:void 0;return{lastCheck:a(e.lastCheck),latestVersion:typeof e.latestVersion==="string"?e.latestVersion:void 0,notifiedVersion:typeof e.notifiedVersion==="string"?e.notifiedVersion:void 0,notifiedAt:a(e.notifiedAt)}}async function i3(n,t){return Z5(Y5(n),{recursive:!0,mode:448}).then(()=>X5(n,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{dirname as A5,join as K5,resolve as ye}from"node:path";var v3="CC Safety Net Config",V5="═".repeat(v3.length),M5="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",G5=new Set(["rule.json","rule.lock","cache"]);function o3(n={}){try{return U5(n)}catch(t){if(t instanceof X)return console.error(t.message),1;throw t}}function U5(n){let t=n.cwd??process.cwd(),r=n.userConfigPath??I(),e=n.projectConfigPath??P(t),a=n.legacyUserConfigPath??un(),l=n.legacyProjectConfigPath??Ae(t),s=ye(t,Et),d=A5(r),c=N({cwd:t,userConfigPath:r,projectConfigPath:e}),L=N({cwd:t}),i=D(c.userScope,r),u=D(c.projectScope,e),o=n.legacyUserConfigPath?cn(n.legacyUserConfigPath,"user policy"):D(L.userScope,a),p=n.legacyProjectConfigPath?cn(n.legacyProjectConfigPath,"project policy"):D(L.projectScope,l),f=!1,v=!1,h=[],w=[],$=C5(D(L.projectScope,s));if(T5(),m(i)!==null){let y=s2(i);if(y.errors.push(...d2(r,M2({userConfigDir:d}),{userConfigDir:d},c.userScope)),h.push({scope:"User",path:r,result:y,schema:"rules",sourceDisplayMap:g2(r,c.userScope),target:i}),y.errors.length>0)f=!0}if(m(o)!==null)if(v=!0,m(i)!==null)w.push(kt("user","cleanup"));else{let y=Wt(o);if(h.push({scope:"User",path:a,result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:o}),w.push(kt("user",y.errors.length>0?"fix-or-delete":"migrate")),y.errors.length>0)f=!0}if(m(u)!==null){let y=s2(u);if(y.errors.push(...d2(e,G2(e),{userConfigDir:d},c.projectScope)),h.push({scope:"Project",path:ye(e),result:y,schema:"rules",sourceDisplayMap:g2(e,c.projectScope),target:u}),y.errors.length>0)f=!0;if(m(p)!==null)v=!0,w.push(kt("project","cleanup"))}else if(m(p)!==null){v=!0,f=!0;let y=Wt(p);h.push({scope:"Project",path:ye(l),result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:p}),w.push(kt("project",y.errors.length>0?"fix-or-delete":"migrate"))}if($?.result.errors.length)f=!0;if(h.length===0&&!$)return console.log(`
|
|
238
|
+
No config files found. Using built-in rules only.`),0;for(let y of h)if(y.inactive)E5(y.scope,y.path,y.result,y.sourceDisplayMap);else if(y.result.errors.length>0)P5(y.scope,y.path,y.result.errors);else{if(y.schema==="rules"&&n8(y.target))console.log(`
|
|
239
|
+
Added $schema to ${y.scope.toLowerCase()} config.`);_5(y.scope,y.path,y.result,y.schema,y.sourceDisplayMap)}for(let y of w)console.error(`
|
|
240
|
+
${b.red(y)}`);if($)if($.result.errors.length>0)N5($.path,$.result.errors);else I5($.path,$.result);if(f)return console.error(`
|
|
241
|
+
Config validation failed.`),1;return console.log(v?`
|
|
235
242
|
Configs valid with warnings.`:`
|
|
236
|
-
All configs valid.`),0}function
|
|
237
|
-
✓ ${n} config: ${t}`),console.log(` Schema: ${
|
|
238
|
-
✗ Legacy ${n.toLowerCase()} config: ${t}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),
|
|
239
|
-
✓ GitHub source rules: ${n}`),console.log(" Rulebooks:");let
|
|
240
|
-
✗ ${n}: ${t}`),console.error(" Errors:");let
|
|
241
|
-
`))}import{spawn as
|
|
242
|
-
return POSIX path of (choose folder with prompt "${
|
|
243
|
+
All configs valid.`),0}function kt(n,t){let r=`legacy ${n} config`;if(t==="cleanup")return`Warning: Legacy ${n} 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 ${n} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${n} config is no longer supported. Fix or delete the ${r}, then run \`npx -y cc-safety-net rule migrate\`.`}function C5(n){if(K2(n)===null)return null;let t=O5(n);if(t.ruleNames.size===0&&t.errors.length===0)return null;return{path:n.path,result:t}}function O5(n){let t=[],r=new Set,e=(K2(n)??[]).filter((a)=>!G5.has(a.name)).sort((a,l)=>a.name.localeCompare(l.name));if(e.length===0)return{errors:t,ruleNames:r};for(let a of e){if(!pn.test(a.name)){t.push(`rulebook directory names must match ${pn}: ${a.name}`);continue}if(a.kind!=="directory"){t.push(`${a.name} must be a rulebook directory`);continue}let l=D(n.scope,K5(n.path,a.name,"rulebook.json")),s=m(l);if(s===null){t.push(`${a.name}/rulebook.json is required`);continue}try{let d;try{d=JSON.parse(s)}catch{t.push(`${a.name}/rulebook.json: invalid JSON`);continue}let c=u3(d);if(c.name!==a.name){t.push(`rulebook name "${c.name}" must match folder "${a.name}"`);continue}r.add(a.name)}catch(d){t.push(d instanceof Error?`${a.name}/rulebook.json: ${d.message}`:`${a.name}/rulebook.json: ${String(d)}`)}}return{errors:t,ruleNames:r}}function T5(){console.log(v3),console.log(V5)}function _5(n,t,r,e,a){if(console.log(`
|
|
244
|
+
✓ ${n} config: ${t}`),console.log(` Schema: ${e==="rules"?"rulebook sources":"legacy inline rules"}`),r.ruleNames.size>0){console.log(` ${e==="rules"?"Sources":"Rules"}:`);let l=1;for(let s of r.ruleNames)console.log(` ${l}. ${a.get(s)??s}`),l++}else console.log(` ${e==="rules"?"Sources":"Rules"}: (none)`)}function E5(n,t,r,e){if(console.error(`
|
|
245
|
+
✗ Legacy ${n.toLowerCase()} config: ${t}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),r.errors.length>0){console.error(" Errors:");let a=1;for(let l of r.errors)for(let s of l.split("; "))console.error(` ${a}. ${s}`),a++;return}if(r.ruleNames.size>0){console.error(" Rules:");let a=1;for(let l of r.ruleNames)console.error(` ${a}. ${e.get(l)??l}`),a++;return}console.error(" Rules: (none)")}function P5(n,t,r){b3(`${n} config`,t,r)}function I5(n,t){console.log(`
|
|
246
|
+
✓ GitHub source rules: ${n}`),console.log(" Rulebooks:");let r=1;for(let e of t.ruleNames)console.log(` ${r}. ${e}`),r++}function N5(n,t){b3("GitHub source rules",n,t)}function b3(n,t,r){console.error(`
|
|
247
|
+
✗ ${n}: ${t}`),console.error(" Errors:");let e=1;for(let a of r)for(let l of a.split("; "))console.error(` ${e}. ${l}`),e++}function n8(n){try{let t=m(n);if(t===null)return!1;let r=JSON.parse(t);if(r.$schema)return!1;return m2(n,JSON.stringify({$schema:M5,...r},null,2)),!0}catch(t){if(t instanceof X)throw t;return!1}}var f3=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),r8=new Set(["add","remove","list"]);async function h3(n){try{return await e8(n)}catch(t){if(t instanceof X)return console.error(t.message),1;throw t}}async function e8(n){let t=l8(n),r=t.help?a8(t.positionals):null;if(r)return ot(r),0;if(t.errors.length>0){for(let s of t.errors)console.error(s);return 1}let e=t.positionals[0];if(!e)return ot(_2,console.error),1;let a=t.positionals[1],l={global:t.global,check:t.check};if(e==="init"){let s=T(l),d=s.configDir;c8(s.configTarget),y3(D(s.filesystemScope,An({...l,cacheConfigDir:d})));let c=t8(d,"example-rules","rulebook.json"),L=D(s.filesystemScope,c);if(t.example&&m(L)===null)Nt(L,"example-rules");let i=await V2(l);return Sn(i,"Rule config initialized."),i.ok?0:1}if(e==="add"){if(!a)return console.error("rule add requires a source"),1;let s=await Ot(a,l);return Sn(s,`Added rulebook source: ${a}`),s.ok?0:1}if(e==="remove"){if(!a)return console.error("rule remove requires a source"),1;let s=await _t(a,{...l,deleteSource:t.deleteSource});return Sn(s,`Removed rulebook source: ${a}`),s.ok?0:1}if(e==="update"||e==="sync"){let s=await V2({...l,only:e==="update"?a:void 0});return Sn(s,t.check?"Rule config checked.":"Rule config synced."),s.ok?0:1}if(e==="list"){let s=y2(),d=N({});return l3(s,{user:g2(s.userConfigPath,d.userScope),project:g2(s.projectConfigPath,d.projectScope)}),s.errors.length>0?1:0}if(e==="wrapper")return L8(t);if(e==="migrate")return L3({cleanup:t.cleanup,cwd:process.cwd()});if(e==="doc"){console.log(e3);let s=await p3();if(s)console.error(s);return 0}if(e==="verify")return o3();return 1}function a8(n){if(n.length===0)return _2;let t=_2.subcommands.filter((e)=>e.usage.split(" ")[0]===n[0]);if(t.length===0)return null;if(n.length===1&&t.length>1)return{name:`rule ${n[0]}`,description:`Subcommands of rule ${n[0]}`,usage:`rule ${n[0]} <subcommand>`,subcommands:t,options:[]};let r=n.length===1?t[0]:t.find((e)=>e.usage.split(" ")[1]===n[1]);if(!r)return null;return{name:`rule ${n[0]}`,description:r.description,usage:`rule ${r.usage}`,options:[]}}function l8(n){let t=B({label:"rule",booleans:{global:["-g","--global"],check:["--check"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},positionals:"list"},n),r={...t.flags,help:t.help,positionals:t.positionals,errors:t.errors};return s8(r),r}function s8(n){let[t]=n.positionals;if(t&&!f3.has(t))n.errors.push(`Unknown rule subcommand: ${t}`);if(n.deleteSource&&t!=="remove")if(t&&f3.has(t))n.errors.push(`Unknown option for rule ${t}: --delete-source`);else n.errors.push("--delete-source is only valid with 'rule remove'");if(n.cleanup&&t!=="migrate")n.errors.push(qt(t,"--cleanup"));if(n.example&&t!=="init")n.errors.push(qt(t,"--example"));if(t==="migrate"){if(n.global)n.errors.push(qt(t,"--global"));if(n.check)n.errors.push(qt(t,"--check"));if(n.positionals.length>1)n.errors.push(`Unexpected rule migrate argument: ${n.positionals[1]}`)}else if(t==="wrapper")d8(n);else if(n.positionals.length>2)n.errors.push(`Unexpected rule argument: ${n.positionals[2]}`);if(t==="list"&&n.global)n.errors.push("Unknown option for rule list: --global")}function qt(n,t){return n?`Unknown option for rule ${n}: ${t}`:`Unknown option for rule: ${t}`}function d8(n){let t=n.positionals[1],r=n.positionals[2];if(!t){n.errors.push("rule wrapper requires add, remove, or list");return}if(!r8.has(t)){n.errors.push(`Unknown rule wrapper action: ${t}`);return}if(t==="list"){if(r)n.errors.push(`Unexpected rule wrapper argument: ${r}`);return}if(!r){n.errors.push(`rule wrapper ${t} requires a command`);return}if(n.positionals.length>3)n.errors.push(`Unexpected rule wrapper argument: ${n.positionals[3]}`)}function c8(n){if(m(n)===null){It(n);return}let t=_(n);if(!t.config)return;E(n,{version:1,rules:t.config.rules,overrides:t.config.overrides??{},transparent_wrappers:t.config.transparent_wrappers??[]})}async function L8(n){let t=n.positionals[1],r=n.positionals[2],e=T({global:n.global}).configTarget;if(t==="list"){let d=_(e);if(d.errors.length>0){for(let c of d.errors)console.error(c);return 1}return i8(d.config?.transparent_wrappers??[]),0}if(!r||!tr.test(r))return console.error("transparent wrapper must match command pattern"),1;if(er(r))return console.error(`reserved command "${r}" cannot be a wrapper`),1;let a=_(e);if(a.errors.length>0){for(let d of a.errors)console.error(d);return 1}let l=a.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},s=t==="add"?[...new Set([...l.transparent_wrappers??[],r])]:(l.transparent_wrappers??[]).filter((d)=>d!==r);return E(e,{version:1,rules:l.rules,overrides:l.overrides??{},transparent_wrappers:s}),console.log(t==="add"?`Added transparent wrapper: ${r}`:`Removed transparent wrapper: ${r}`),0}function i8(n){if(n.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${n.length}):`);for(let t of n)console.log(` - ${t}`)}import{homedir as w3}from"node:os";import{existsSync as p8,readFileSync as u8}from"node:fs";import{homedir as v8}from"node:os";import{join as o8}from"node:path";async function b8(n){if(n.isTTY)return null;return(await ir(n).catch(()=>null))?.trim()||null}function f8(){if(process.env.CLAUDE_SETTINGS_PATH)return process.env.CLAUDE_SETTINGS_PATH;return o8(v8(),".claude","settings.json")}function he(){let n=f8();if(!p8(n))return!1;try{let t=u8(n,"utf-8"),r=JSON.parse(t);if(!r.enabledPlugins)return!1;let e="cc-safety-net@cc-marketplace";if(!(e in r.enabledPlugins))return!1;return r.enabledPlugins[e]===!0}catch(t){if(bn(k.debug))console.error(`CC Safety Net debug: failed to read Claude settings: ${n}: ${t instanceof Error?t.message:String(t)}`);return!1}}async function we(n=process.stdin){let t=he(),r;if(!t)r="\uD83D\uDEE1️ CC Safety Net ❌";else{let a=K({cwd:process.cwd()}),l=a.policy,s=c2(l),d=Object.values(q2(l,s.capabilities)).some((L)=>L.changesInherited);r=`\uD83D\uDEE1️ CC Safety Net ${{standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[d?"custom":s.effectiveLevel]}${s.worktreeMode?"\uD83C\uDF33":""}${a.state==="degraded"?"⚠️":""}`}let e=await b8(n);if(e&&!e.startsWith("{"))console.log(`${e} | ${r}`);else console.log(r)}function x3(){let n=K({cwd:process.cwd()}),t=n.policy,r=c2(t),e=!!process.env.NO_COLOR||!process.stdout.isTTY,a=Math.min(process.stdout.columns||80,100),l=e?"ok":"✔",s=e?"OFF":"✘",d=(p,f)=>{let v=` ${p.padEnd(13)}${f}`;return(v.length>a?`${v.slice(0,a-1)}…`:v).replaceAll(s,b.red(s))},c=Object.values(q2(t,r.capabilities)).some((p)=>p.changesInherited),L=fn(),i={ready:b.green,degraded:b.yellow}[n.state],u=[...he()?[]:["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."],...n.diagnostics],o=e?"-":"·";console.log([`${e?"":"\uD83D\uDEE1️ "}CC Safety Net — ${i(n.state)}`,"",d("Protection",`destructive ${t.destructiveCommandProtectionEnabled?l:s} secrets ${t.secretProtection.enabled?l:s}`),d("Level",c?`${r.effectiveLevel} (customised)`:r.effectiveLevel),d("Rules",t.rules.length===0?"none active":`${t.rules.length} active`),d("Policy",L.startsWith(w3())?`~${L.slice(w3().length)}`:L),...r.worktreeMode?[d("Worktree","relaxations active")]:[],"",...u.length===0?[" Everything configured is active."]:[" Not active",...u.flatMap((p)=>vt(p," ",a-6).map((f,v)=>v===0?` ${o} ${f}`:f)),""," Full report: cc-safety-net doctor"]].join(`
|
|
248
|
+
`))}import{spawn as W3}from"node:child_process";import{randomBytes as j8}from"node:crypto";import{createServer as z8}from"node:http";import{Writable as F8}from"node:stream";import{homedir as y8}from"node:os";var jt=500;function h8(n){let t=n.filter((a)=>a.decision!=="allow"),r=n.filter((a)=>a.decision==="allow"),e=Math.min(t.length,Math.max(jt-r.length,Math.ceil(jt/2)));return[...t.slice(0,e),...r.slice(0,jt-e)]}function $3(n,t=L2()){if(t)D2(t);let r=(v)=>new Date(v.getFullYear(),v.getMonth(),v.getDate()).getTime(),e=r(new Date),a=new Date(e);a.setDate(a.getDate()-(n-1));let l=a.getTime(),s=[],d={count:0};for(let v of t?f2(t,d):[])for(let h of dn(v,d)){if(!h||typeof h.ts!=="string"||typeof h.command!=="string")continue;let w=new Date(h.ts).getTime();if(!Number.isFinite(w))continue;if(w>=l)s.push(h)}s.sort((v,h)=>new Date(h.ts).getTime()-new Date(v.ts).getTime());let c=Array.from({length:n},()=>0),L=Array.from({length:n},()=>0),i={},u={},o={},p=0,f=0;for(let v of s){let h=v.agent||"unknown";i[h]=(i[h]??0)+1;let w=Math.round((e-r(new Date(v.ts)))/86400000),$=n-1-w,y=w>=0&&w<n;if(y)L[$]=(L[$]??0)+1;if(v.decision!=="allow"){if(p++,v.ruleId)u[v.ruleId]=(u[v.ruleId]??0)+1;let g=S2(v.segment||v.command);if(g)o[g]=(o[g]??0)+1;if(v.failureStage)f++;if(y)c[$]=(c[$]??0)+1}}return{days:n,logsDir:t,homeDir:y8(),totalInWindow:s.length,truncated:s.length>jt,unreadable:d.count,counts:{blocked:p,allowed:s.length-p,agents:i,blockedByDay:c,analyzedByDay:L,rules:u,commands:o,errors:f},entries:h8(s).sort((v,h)=>new Date(h.ts).getTime()-new Date(v.ts).getTime())}}import{spawn as w8}from"node:child_process";import{existsSync as m3,statSync as x8}from"node:fs";import{delimiter as $8,join as m8}from"node:path";var g8=120000,zt="Choose the project folder",D8=`try
|
|
249
|
+
return POSIX path of (choose folder with prompt "${zt}")
|
|
243
250
|
on error number -128
|
|
244
251
|
return ""
|
|
245
|
-
end try`,
|
|
252
|
+
end try`,k8=`Add-Type -AssemblyName System.Windows.Forms
|
|
246
253
|
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
247
|
-
$dialog.Description = '${
|
|
248
|
-
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,
|
|
254
|
+
$dialog.Description = '${zt}'
|
|
255
|
+
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,g3=[{binary:"zenity",args:["--file-selection","--directory",`--title=${zt}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",zt]}],D3=(n,t)=>(t.PATH??"").split($8).some((r)=>r.length>0&&m3(m8(r,n)));function k3(n,t){if(n==="darwin"||n==="win32")return!0;if(n!=="linux")return!1;if(!t.DISPLAY&&!t.WAYLAND_DISPLAY)return!1;return g3.some((r)=>D3(r.binary,t))}function q8(n,t){if(n==="darwin")return{cmd:"osascript",args:["-e",D8]};if(n==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",k8]};let r=g3.find((e)=>D3(e.binary,t));return r?{cmd:r.binary,args:r.args}:null}function q3(n=process.platform,t=process.env){let r=q8(n,t);if(!r)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((e)=>{let a=w8(r.cmd,r.args,{env:t,stdio:["ignore","pipe","pipe"]}),l="",s=!1,d=(L)=>{if(s)return;s=!0,clearTimeout(c),e(L)},c=setTimeout(()=>{a.kill(),d({error:"The folder dialog timed out"})},g8);a.stdout.on("data",(L)=>{l+=L.toString()}),a.on("error",()=>d({error:`Could not open the folder dialog (${r.cmd})`})),a.on("close",()=>{let L=l.trim().replace(/\/+$/,"");if(!L)return d({cancelled:!0});if(!m3(L)||!x8(L).isDirectory())return d({error:"That selection is not a folder on disk"});d({path:L})})})}var j3=`<!doctype html>
|
|
249
256
|
<html lang="en">
|
|
250
257
|
<head>
|
|
251
258
|
<meta charset="utf-8">
|
|
@@ -3077,8 +3084,7 @@ var catalog = [
|
|
|
3077
3084
|
install: {
|
|
3078
3085
|
order: 2,
|
|
3079
3086
|
flag: "--agy-cli",
|
|
3080
|
-
|
|
3081
|
-
helpTarget: "Antigravity CLI hook config",
|
|
3087
|
+
artifactKind: "hook config",
|
|
3082
3088
|
probeCommand: ["agy", "--version"]
|
|
3083
3089
|
}
|
|
3084
3090
|
},
|
|
@@ -3097,8 +3103,7 @@ var catalog = [
|
|
|
3097
3103
|
install: {
|
|
3098
3104
|
order: 3,
|
|
3099
3105
|
flag: "--claude-code",
|
|
3100
|
-
|
|
3101
|
-
helpTarget: "Claude Code plugin",
|
|
3106
|
+
artifactKind: "plugin",
|
|
3102
3107
|
probeCommand: ["claude", "--version"]
|
|
3103
3108
|
}
|
|
3104
3109
|
},
|
|
@@ -3109,8 +3114,7 @@ var catalog = [
|
|
|
3109
3114
|
install: {
|
|
3110
3115
|
order: 4,
|
|
3111
3116
|
flag: "--codex",
|
|
3112
|
-
|
|
3113
|
-
helpTarget: "Codex plugin",
|
|
3117
|
+
artifactKind: "plugin",
|
|
3114
3118
|
probeCommand: ["codex", "--version"]
|
|
3115
3119
|
}
|
|
3116
3120
|
},
|
|
@@ -3127,8 +3131,7 @@ var catalog = [
|
|
|
3127
3131
|
install: {
|
|
3128
3132
|
order: 7,
|
|
3129
3133
|
flag: "--copilot-cli",
|
|
3130
|
-
|
|
3131
|
-
helpTarget: "GitHub Copilot CLI plugin",
|
|
3134
|
+
artifactKind: "plugin",
|
|
3132
3135
|
probeCommand: ["copilot", "--binary-version"]
|
|
3133
3136
|
}
|
|
3134
3137
|
},
|
|
@@ -3145,8 +3148,7 @@ var catalog = [
|
|
|
3145
3148
|
install: {
|
|
3146
3149
|
order: 6,
|
|
3147
3150
|
flag: "--gemini-cli",
|
|
3148
|
-
|
|
3149
|
-
helpTarget: "Gemini CLI extension",
|
|
3151
|
+
artifactKind: "extension",
|
|
3150
3152
|
probeCommand: ["gemini", "--version"]
|
|
3151
3153
|
}
|
|
3152
3154
|
},
|
|
@@ -3163,8 +3165,7 @@ var catalog = [
|
|
|
3163
3165
|
install: {
|
|
3164
3166
|
order: 8,
|
|
3165
3167
|
flag: "--hermes-agent",
|
|
3166
|
-
|
|
3167
|
-
helpTarget: "Hermes Agent plugin",
|
|
3168
|
+
artifactKind: "plugin",
|
|
3168
3169
|
probeCommand: ["hermes", "--version"]
|
|
3169
3170
|
}
|
|
3170
3171
|
},
|
|
@@ -3181,8 +3182,7 @@ var catalog = [
|
|
|
3181
3182
|
install: {
|
|
3182
3183
|
order: 9,
|
|
3183
3184
|
flag: "--kimi-code",
|
|
3184
|
-
|
|
3185
|
-
helpTarget: "Kimi Code hook config",
|
|
3185
|
+
artifactKind: "hook config",
|
|
3186
3186
|
probeCommand: ["kimi", "--version"]
|
|
3187
3187
|
}
|
|
3188
3188
|
},
|
|
@@ -3193,8 +3193,7 @@ var catalog = [
|
|
|
3193
3193
|
install: {
|
|
3194
3194
|
order: 10,
|
|
3195
3195
|
flag: "--openclaw",
|
|
3196
|
-
|
|
3197
|
-
helpTarget: "OpenClaw plugin",
|
|
3196
|
+
artifactKind: "plugin",
|
|
3198
3197
|
probeCommand: ["openclaw", "--version"]
|
|
3199
3198
|
}
|
|
3200
3199
|
},
|
|
@@ -3205,8 +3204,7 @@ var catalog = [
|
|
|
3205
3204
|
install: {
|
|
3206
3205
|
order: 11,
|
|
3207
3206
|
flag: "--opencode",
|
|
3208
|
-
|
|
3209
|
-
helpTarget: "OpenCode plugin",
|
|
3207
|
+
artifactKind: "plugin",
|
|
3210
3208
|
probeCommand: ["opencode", "--version"]
|
|
3211
3209
|
}
|
|
3212
3210
|
},
|
|
@@ -3217,8 +3215,7 @@ var catalog = [
|
|
|
3217
3215
|
install: {
|
|
3218
3216
|
order: 12,
|
|
3219
3217
|
flag: "--pi",
|
|
3220
|
-
|
|
3221
|
-
helpTarget: "Pi package",
|
|
3218
|
+
artifactKind: "package",
|
|
3222
3219
|
probeCommand: ["pi", "--version"]
|
|
3223
3220
|
}
|
|
3224
3221
|
},
|
|
@@ -3235,8 +3232,7 @@ var catalog = [
|
|
|
3235
3232
|
install: {
|
|
3236
3233
|
order: 5,
|
|
3237
3234
|
flag: "--cursor",
|
|
3238
|
-
|
|
3239
|
-
helpTarget: "Cursor hook config",
|
|
3235
|
+
artifactKind: "hook config",
|
|
3240
3236
|
probeCommand: ["cursor", "--version"]
|
|
3241
3237
|
}
|
|
3242
3238
|
},
|
|
@@ -3247,8 +3243,7 @@ var catalog = [
|
|
|
3247
3243
|
install: {
|
|
3248
3244
|
order: 1,
|
|
3249
3245
|
flag: "--amp",
|
|
3250
|
-
|
|
3251
|
-
helpTarget: "Amp Code plugin",
|
|
3246
|
+
artifactKind: "plugin",
|
|
3252
3247
|
probeCommand: ["amp", "--version"]
|
|
3253
3248
|
}
|
|
3254
3249
|
}
|
|
@@ -5366,5 +5361,5 @@ load().then((loaded) => {
|
|
|
5366
5361
|
</script>
|
|
5367
5362
|
</body>
|
|
5368
5363
|
</html>
|
|
5369
|
-
`;var
|
|
5370
|
-
`)}}finally{console.log=
|
|
5364
|
+
`;var z3='<script id="ccsn-data" type="application/json">';function F3(n){return j3.replace(z3,()=>z3+JSON.stringify({token:n}).replaceAll("<","\\u003c"))}var Bt="kenryu42/cc-safety-net",B8=`https://github.com/${Bt}`,me=1e4,J8=7;async function A3(n,t={}){let r=B({label:"gui",booleans:{noOpen:["--no-open"]}},n),e=t.log??console.log,a=t.error??console.error;if(r.errors.length>0){for(let s of r.errors)a(s);return a("Usage: cc-safety-net gui [--no-open]"),1}let l=await Z8(t);if(e(`CC Safety Net policy GUI: ${l.url}`),!r.flags.noOpen)try{await(t.openBrowser??A8)(l.url)}catch(s){a(`Failed to open browser: ${s instanceof Error?s.message:String(s)}`),a(`Open this URL manually: ${l.url}`)}if(t.keepAlive===!1)return await l.close(),0;return await W8(l),0}async function Z8(n={}){let t=n.token??j8(24).toString("base64url"),r=z8((l,s)=>{Q8(l,s,t,n)});await new Promise((l,s)=>{r.once("error",s),r.listen(0,"127.0.0.1",()=>{r.off("error",s),l()})});let a=`http://127.0.0.1:${r.address().port}`;return{origin:a,token:t,url:`${a}/?token=${encodeURIComponent(t)}`,close:()=>R8(r)}}async function Q8(n,t,r,e){let a=new URL(n.url??"/","http://127.0.0.1");if(n.method==="GET"&&a.pathname==="/favicon.ico"){t.writeHead(204,{"cache-control":"no-store"}),t.end();return}if(!S8(n,a,r)){q(t,403,{error:"Forbidden"});return}if(n.method==="GET"&&a.pathname==="/"){H8(t,F3(r));return}if(n.method==="GET"&&a.pathname==="/api/policy"){let l=Q3(e);q(t,200,{...l,configState:yn(K(e)),destructiveCommandRules:vn,secretPatterns:J3,version:F(),preview:l.errors.length>0?null:Y3(l.policy)});return}if(n.method==="POST"&&a.pathname==="/api/policy/preview"){let l=await Ft(n);if(!l.ok){q(t,400,{errors:[l.error]});return}let s=X3(l.value);q(t,s.errors.length>0?400:200,s);return}if(n.method==="POST"&&a.pathname==="/api/policy/explain"){let l=await Ft(n);if(!l.ok){q(t,400,{errors:[l.error]});return}let s=l.value;if(s===null||typeof s.command!=="string"){q(t,400,{errors:["command must be a string"]});return}let d=dr(s.policy);if(d.length>0){q(t,400,{errors:d});return}q(t,200,X8(s.command,s.policy,e));return}if(n.method==="POST"&&a.pathname==="/api/policy"){let l=await Ft(n);if(!l.ok){q(t,400,{errors:[l.error]});return}let s=xe(l.value,e);q(t,s.errors.length>0?400:200,s);return}if(n.method==="POST"&&a.pathname==="/api/reset"){q(t,200,xe(Z3,e));return}if(n.method==="POST"&&a.pathname==="/api/repair"){q(t,200,S3(e));return}if(n.method==="GET"&&a.pathname==="/api/activity"){let l=O2(e),s=Y8(a.searchParams.get("days"),l);if(s===null){q(t,400,{error:`days must be an integer between 1 and ${l}`});return}q(t,200,$3(s,e.activityLogsDir));return}if(n.method==="POST"&&a.pathname==="/api/rules/choose-directory"){q(t,200,await q3());return}if(n.method==="GET"&&a.pathname==="/api/rules"){let l=y2(e),s=new Map(l.rules.map((d)=>[d.name,d]));q(t,200,{projectPath:e.cwd??process.cwd(),canPickDirectory:k3(process.platform,process.env),rulebooks:l.rulebooks.map((d)=>({source:d.source,spec:d.spec,name:d.name,version:d.version,rules:d.rules.flatMap((c)=>{let L=s.get(c);if(!L)return[];return[{name:L.name,command:L.command,subcommand:L.subcommand,block_args:L.block_args,reason:L.reason}]})})),errors:l.errors,warnings:l.warnings});return}if(n.method==="GET"&&a.pathname==="/api/star/context"){q(t,200,await(e.fetchStarContext??(()=>U8({logsDir:e.activityLogsDir})))());return}if(n.method==="POST"&&a.pathname==="/api/star"){let l=await(e.starRepo??K8)();q(t,200,l.ok?{ok:!0}:{ok:!1,fallbackUrl:B8});return}if(n.method==="GET"&&a.pathname==="/api/integrations"){q(t,200,await(e.fetchIntegrations??V8)());return}if(n.method==="GET"&&a.pathname==="/api/health"){q(t,200,await(e.fetchHealth??M8)());return}if(n.method==="POST"&&(a.pathname==="/api/install"||a.pathname==="/api/uninstall")){let l=await Ft(n);if(!l.ok){q(t,400,{errors:[l.error]});return}let s=l.value?.target;if(typeof s!=="string"||!O.some((c)=>c.target===s)){q(t,400,{error:"unknown target"});return}let d=a.pathname==="/api/install"?"install":"uninstall";q(t,200,await(e.runIntegration??G8)(d,s));return}q(t,404,{error:"Not found"})}function X8(n,t,r){let e=ft(t),a=K(r),l=on({rules:a.policy.rules,transparentWrappers:a.policy.transparentWrappers,safety:R3(e.safety),worktreeMode:e.workflow.worktree_mode,destructiveCommandProtectionEnabled:e.destructive_command_protection.enabled,destructiveCommandRuleOverrides:e.destructive_command_protection.overrides,destructiveCommandAllowPaths:e.destructive_command_protection.allow_paths,secretProtection:{enabled:e.secret_protection.enabled,disabledRules:[...H3(e.secret_protection.overrides)],denyPaths:e.secret_protection.deny_paths,allowPaths:e.secret_protection.allow_paths}});return C2(n,{policySnapshot:l,cwd:r.cwd,userConfigDir:r.userConfigDir})}function Y8(n,t){if(n===null)return Math.min(J8,t);let r=Number(n);if(!Number.isInteger(r)||r<1||r>t)return null;return r}function S8(n,t,r){if(t.searchParams.get("token")!==r)return!1;if(n.method!=="POST")return!0;return n.headers["x-cc-safety-net-token"]===r}async function Ft(n){let t=[];for await(let r of n)t.push(r);try{return{ok:!0,value:JSON.parse(Buffer.concat(t).toString("utf-8")||"{}")}}catch(r){return{ok:!1,error:`Invalid JSON: ${r instanceof Error?r.message:String(r)}`}}}function H8(n,t){n.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),n.end(t)}function q(n,t,r){n.writeHead(t,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),n.end(JSON.stringify(r))}function R8(n){return new Promise((t,r)=>{n.close((e)=>e?r(e):t())})}function W8(n){return new Promise((t)=>{let r=()=>{process.off("SIGINT",e),process.off("SIGTERM",e)},e=()=>{r(),n.close().then(t)};process.once("SIGINT",e),process.once("SIGTERM",e)})}function A8(n){let t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",r=process.platform==="win32"?["/c","start","",n]:[n];return new Promise((e,a)=>{let l=W3(t,r,{detached:!0,stdio:"ignore"}),s=(c)=>{l.off("spawn",d),a(c)},d=()=>{l.off("error",s),l.unref(),e()};l.once("error",s),l.once("spawn",d)})}async function K8(n="gh",t=me){return{ok:await $e(n,["api","-X","PUT",`/user/starred/${Bt}`],t)===0}}async function V8(n={}){let t=await $n(n.fetcher),r=K3(t,n.homeDir);return{targets:M.map((e)=>{let a=r.find((l)=>l.platform===e.id);return{target:e.id,label:j(e.id),version:t.versions[e.id]??null,status:a?.configured?"active":a?.detected?"disabled":a?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:t.version,nodeVersion:t.nodeVersion,platform:t.platform}}}function K3(n,t){return en(process.cwd(),{homeDir:t,ampPluginListOutput:n.ampPluginListOutput,codexPluginListOutput:n.codexPluginListOutput,copilotCliVersion:n.versions["copilot-cli"]})}async function M8(n={}){let[t,r]=await Promise.all([$n(n.fetcher),(n.checkUpdates??P2)()]);return{hooks:K3(t,n.homeDir).filter((e)=>e.detected).map((e)=>({platform:e.platform,label:j(e.platform),configured:e.configured})),update:{currentVersion:r.currentVersion,latestVersion:r.latestVersion??null,updateAvailable:r.updateAvailable}}}var B3=Promise.resolve();function G8(n,t,r={}){let e=async()=>{let l=[],s=console.log,d=console.error;console.log=(...c)=>l.push(c.map(String).join(" ")),console.error=console.log;try{return{ok:await Yn(n,[],{selectTargets:async()=>[t],output:new F8({write(L,i,u){l.push(String(L).replace(/\n$/,"")),u()}}),...r})===0,output:l.join(`
|
|
5365
|
+
`)}}finally{console.log=s,console.error=d}},a=B3.then(e);return B3=a.then(()=>{return},()=>{return}),a}async function U8(n={}){let[t,r,e]=await Promise.all([C8(n.command),O8(n.fetchRepo),Promise.resolve(Cn(O2(),n.logsDir).totalBlocked)]);return{starred:t,starCount:r,blockedTotal:e}}async function C8(n="gh",t=me){if(await $e(n,["auth","status"],t)!==0)return null;let r=await $e(n,["api",`/user/starred/${Bt}`],t);if(r===0)return!0;if(r===null)return null;return!1}function $e(n,t,r){return new Promise((e)=>{let a=W3(n,t,{stdio:"ignore",windowsHide:!0}),l=!1,s,d=(c)=>{if(l)return;if(l=!0,s)clearTimeout(s);e(c)};a.once("error",()=>d(null)),a.once("close",d),s=setTimeout(()=>{a.kill(),d(null)},r)})}async function O8(n=fetch){try{let t=await n(`https://api.github.com/repos/${Bt}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(me)});if(!t.ok)return null;let r=await t.json();return typeof r.stargazers_count==="number"?r.stargazers_count:null}catch{return null}}function T8(n){if(n[0]!=="help")return!1;let t=n[1];if(!t)te(),process.exit(0);if(Zn(t))process.exit(0);console.error(`Unknown command: ${t}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var _8={hook:async(n)=>{let t=G1(n);if(t){await t.run();return}console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),Zn("hook",console.error),process.exit(1)},install:async(n)=>{process.exit(await Yn("install",n))},update:async(n)=>{process.exit(await be(n))},uninstall:async(n)=>{process.exit(await Yn("uninstall",n))},rule:async(n)=>{process.exit(await h3(n))},status:async(n)=>{if(l2(B({label:"status"},n).errors))process.exit(1);x3()},statusline:async(n)=>{let t=B({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},n);if(t.errors.length===0&&t.flags.claudeCode){await we();return}if(l2(t.errors),!t.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");Zn("statusline",console.error),process.exit(1)},doctor:async(n)=>{let t=Er(n);if(!t)process.exit(1);let r=await O0({json:t.json,skipUpdateCheck:t.skipUpdateCheck});process.exit(r)},logs:async(n)=>{process.exit(await v1(n))},gui:async(n)=>{process.exit(await A3(n))},explain:async(n)=>{process.exit(await nl(n))}};async function E8(){let n=process.argv.slice(2),t=B({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},n);if(T8(n))return;let r=n[0],e=r?Un(r):void 0;if(t.help&&e&&e.name!=="rule")Zn(e.name),process.exit(0);if(!r||t.help&&!e)te(),process.exit(0);if(t.flags.version)el(),process.exit(0);if(e){await _8[e.name](n.slice(1));return}let a=U1(r);if(a){await a.run();return}if(r==="--statusline"){await we();return}console.error(r.startsWith("-")?`Unknown option: ${r}`:`Unknown command: ${r}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}E8().catch((n)=>{console.error("CC Safety Net error:",n),process.exit(1)});
|