cc-safety-net 2.0.7 → 2.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/amp/cc-safety-net/index.ts +100 -0
- package/dist/bin/cc-safety-net.js +175 -227
- package/dist/chunks/index-tdm5076r.js +62 -0
- package/dist/index.js +1 -1
- package/dist/openclaw/cc-safety-net/index.js +73 -75
- 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/dist/vendor/zod.cjs +21 -21
- package/package.json +3 -3
- package/dist/amp/cc-safety-net.ts +0 -102
- package/dist/chunks/index-4pw6zr4t.js +0 -64
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{$ as
|
|
3
|
-
${
|
|
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
|
|
7
|
-
`)}function
|
|
8
|
-
`)}function
|
|
9
|
-
`)}function
|
|
10
|
-
`)}function
|
|
11
|
-
`)}function
|
|
12
|
-
`)}function
|
|
13
|
-
`);for(let
|
|
14
|
-
`)}function
|
|
15
|
-
`)}function
|
|
16
|
-
`);if(
|
|
17
|
-
`);if(
|
|
18
|
-
`);return t.push(
|
|
19
|
-
`)}function
|
|
20
|
-
`)}function
|
|
21
|
-
No findings from inspected doctor facts.`);let t={error:
|
|
22
|
-
${
|
|
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
|
|
33
|
-
# version: ${
|
|
34
|
-
`}function
|
|
35
|
-
version: "${
|
|
2
|
+
import{$ as gr,$a as Xn,A as gt,Aa as Go,B as dc,Ba as Bo,C as ee,Ca as fr,D as J,Da as qo,E as rr,Ea as Vo,F as Kn,Fa as Y,G as Bt,Ga as Zn,H as Wn,Ha as or,I as Je,Ia as ir,J as ke,Ja as Z,K as sr,Ka as Oc,L as ue,La as vt,M as Di,Ma as $c,N as mr,Na as Ro,O as qt,Oa as Nc,P as Ri,Pa as Fc,Q as Ai,Qa as Hc,R as Se,Ra as wn,S as zt,Sa as Mc,T as wt,Ta as jc,U as xt,Ua as fi,V as si,Va as mi,W as ht,Wa as gi,X as De,Xa as hi,Y as ar,Ya as mc,Z as pe,Za as ti,_ as Ei,_a as ni,aa as Ii,ab as ri,b as Io,ba as _i,bb as oi,c as _o,ca as lr,cb as Le,d as G,da as ai,db as Ce,e as Oo,ea as Ho,eb as ce,f as Bn,fa as li,fb as ii,g as N,ga as ci,gb as B,h as k,ha as di,hb as bt,i as pt,ia as cr,ib as yt,j as x,ja as Mo,jb as Ti,k as xe,ka as S,kb as Ae,l as Jo,la as dr,lb as fe,m as Be,ma as Pi,mb as ji,n as ft,na as de,nb as Vt,o as vc,oa as Lt,p as zn,pa as ur,q as Yo,qa as pr,r as mt,ra as ui,s as Zo,sa as pi,t as nr,ta as jo,u as Xo,ua as Ke,v as Qo,va as Jn,w as X,wa as Yn,x as Q,xa as ei,y as Ve,ya as Ue,z as ze,za as _c}from"../chunks/index-tdm5076r.js";var zc=["-h","--help"];function T(e,t){let n=Object.entries(e.booleans??{}),r=Object.entries(e.values??{}),o=Object.fromEntries(n.map(([d])=>[d,!1])),i={},s=[],a=[],l=!1,c=-1;for(let[d,p]of t.entries()){if(d<=c)continue;if(p==="--"){s.push(...t.slice(d+1));break}if(zc.includes(p)){l=!0;continue}let m=n.find(([,h])=>h.includes(p));if(m){o[m[0]]=!0;continue}let u=r.find(([,h])=>h.includes(p));if(u){let h=t[d+1];if(h===void 0||h.startsWith("-")){a.push(`${p} requires a value`);continue}i[u[0]]=h,c=d+1;continue}if(p.startsWith("-")){a.push(`Unknown option for ${e.label}: ${p}`);continue}if(e.positionals==="tail"){s.push(...t.slice(d));break}s.push(p)}if(e.positionals!=="list"&&e.positionals!=="tail")a.push(...s.map((d)=>`Unexpected argument for ${e.label}: ${d}`));return{flags:o,values:i,positionals:s,help:l,errors:a}}function ae(e){for(let t of e)console.error(t);return e.length>0}import{readdirSync as Td,statSync as Li,unlinkSync as Id}from"node:fs";import{basename as vi,dirname as _d,join as Od,resolve as $d}from"node:path";function I(e){return Array.from(e,(t)=>{let n=t.charCodeAt(0);if(n<=31||n>=127&&n<=159)return`\\x${n.toString(16).padStart(2,"0")}`;return t}).join("")}var Mn=(e)=>{let t=Date.now()-new Date(e).getTime();if(!Number.isFinite(t))return"";let n=Math.floor(t/60000),r=Math.floor(n/60),o=Math.floor(r/24);if(o>0)return`${o}d ago`;if(r>0)return`${r}h ago`;if(n>0)return`${n}m ago`;return"just now"},He=(e)=>{let t=(e??"").trim().split(/\s+/).filter((o)=>o&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(o)),n=t[0]?.split("/").pop();if(!n)return null;let r=t[1];return r&&/^[a-z][a-z0-9-]*$/.test(r)?`${n} ${r}`:n};import{existsSync as Kc,readdirSync as Wc,readFileSync as Jc}from"node:fs";import{join as Yc}from"node:path";function ye(e,t){try{return Wc(e,{withFileTypes:!0,encoding:"utf8"}).flatMap((n)=>{let r=Yc(e,n.name);if(n.isDirectory())return ye(r,t);if(n.name.endsWith(".jsonl"))return[r];return[]})}catch{if(t&&Kc(e))t.count++;return[]}}function jn(e){let t=(o)=>`${o.sessionId}
|
|
3
|
+
${He(o.segment||o.command)}`,n=e.filter((o)=>o.decision!=="allow"),r=n.filter((o)=>o.sessionId).reduce((o,i)=>o.set(t(i),(o.get(t(i))??0)+1),new Map);return new Set(n.filter((o)=>o.failureStage||(r.get(t(o))??0)>=2))}function ut(e,t){try{return Jc(e,"utf-8").split(`
|
|
4
|
+
`).filter(Boolean).flatMap((n)=>{try{return[JSON.parse(n)]}catch{if(t)t.count++;return[]}})}catch{if(t)t.count++;return[]}}import{resolve as Cd}from"node:path";var Zc=["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 $o(e){let t=0,n={allocateSegment(){return t++},getNextSegmentIndex(){return t},recordGlobal(r){e.record({kind:"step",scope:"global",step:r})},recordSegment(r,o=n.currentSegmentIndex){if(o===void 0)return;e.record({kind:"step",scope:"segment",segmentIndex:o,step:r})}};return n}function No(e={}){let t=[],n=e.maxEvents??512,r={maxTextLength:e.maxTextLength??2048,maxListLength:e.maxListLength??128,maxObjectProperties:e.maxObjectProperties??e.maxListLength??128,maxDepth:e.maxDepth??16},o=0,i,s=new Set;return{record(a){if(i)return;try{if(!a||t.length>=n){o++;return}t.push(Gn(Xc(a,r,s)))}catch{o++}},finish(a){if(i)return i;try{i=Gn({events:Object.freeze(t),droppedEvents:o,terminal:Qc(a,r,s)})}catch{o++,i=Object.freeze({events:Object.freeze(t),droppedEvents:o,terminal:Object.freeze({result:"blocked",reason:"trace unavailable".slice(0,r.maxTextLength),segment:"trace unavailable".slice(0,r.maxTextLength)})})}return i}}}function Xc(e,t,n){if(e.kind!=="step")throw TypeError("invalid trace event");let{scope:r,step:o}=e;jt(o,n,t);let i=Me(o,t,n);if(r==="global")return{kind:"step",scope:"global",step:i};if(r!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:e.segmentIndex,step:i}}function Qc(e,t,n){let r=e.result;if(r==="allowed")return Object.freeze({result:"allowed"});if(r!=="blocked")throw TypeError("invalid trace terminal");let o=e.ruleId;return Object.freeze({result:"blocked",reason:Me(e.reason,t,n),segment:Me(e.segment,t,n),...o?{ruleId:Me(o,t,n)}:{}})}function jt(e,t,n,r=0,o=new WeakSet){if(typeof e==="string"){let a=e.slice(0,n.maxTextLength);if(!Bn(a))return;for(let l of Oo(a))for(let c of l.match(/[^\s"'()$]+/g)??[])t.add(Fo(c));return}if(!e||typeof e!=="object"||r>=n.maxDepth||o.has(e))return;if(o.add(e),Array.isArray(e)){let a=Math.min(e.length,n.maxListLength);for(let l=0;l<a;l++)jt(e[l],t,n,r+1,o);return}let i=0,s=new Set;for(let a in e){if(!Object.hasOwn(e,a))continue;if(i>=n.maxObjectProperties)break;i++,jt(a,t,n);let l=Un(a,n,t);if(s.has(l))continue;s.add(l),jt(e[a],t,n,r+1,o)}}function Me(e,t,n,r=0,o=new WeakSet){if(typeof e==="string")return Un(e,t,n);if(!e||typeof e!=="object")return e;if(r>=t.maxDepth)return;if(o.has(e))return;if(o.add(e),Array.isArray(e)){let a=[],l=Math.min(e.length,t.maxListLength);for(let c=0;c<l;c++)a.push(Me(e[c],t,n,r+1,o));return a}let i={},s=0;for(let a in e){if(!Object.hasOwn(e,a))continue;if(s>=t.maxObjectProperties)break;s++;let l=Un(a,t,n);if(Object.hasOwn(i,l))continue;Object.defineProperty(i,l,{value:Me(e[a],t,n,r+1,o),enumerable:!0,configurable:!0,writable:!0})}return i}function Un(e,t,n){let r=e.slice(0,t.maxTextLength),o=Bn(r)?_o(r):r,i=n.size>0?td(o,n):o;return(ed(i)?Io(i):i).slice(0,t.maxTextLength)}function ed(e){return e.includes("PRIVATE KEY")||e.includes("://")||e.includes("eyJ")||e.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(e)||e.length>=14&&Zc.some((t)=>e.includes(t))||e.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(e)}function td(e,t){return e.replace(/[^\s"'()$]+/g,(n)=>t.has(Fo(n))?"<redacted>":n)}function Fo(e){let t=2166136261,n=2166136261;for(let r=0;r<e.length;r++)t=Math.imul(t^e.charCodeAt(r),16777619),n=Math.imul(n^e.charCodeAt(e.length-r-1),16777619);return`${t>>>0}:${n>>>0}:${e.length}`}function Gn(e){if(e&&typeof e==="object"&&!Object.isFrozen(e)){for(let t of Object.values(e))Gn(t);Object.freeze(e)}return e}function Uo(e,t,n){let r=n??Ho(),o=r.getCommandProgram(e,t.shell??"auto"),i=No(),s=$o(i),a=o.dialect==="powershell"?r.getCommandProgram(e,"posix"):o,l=Mo(a);s.recordGlobal({type:"parse",input:e,segments:l.map((p)=>[...p])});let c=jo(e,{...t,analyzePartialProgram:!0,trace:s},o,r),d=s.getNextSegmentIndex();if(c&&d>0&&d<l.length)s.recordSegment({type:"segment-skipped",index:d,reason:"prior-segment-blocked"},d);return Object.freeze({decision:c,trace:i.finish(c?{result:"blocked",reason:c.reason,segment:c.evidence.find((p)=>p.kind==="command")?.segment??e,...c.ruleId?{ruleId:c.ruleId}:{}}:{result:"allowed"}),program:o})}import{resolve as nd}from"node:path";function qn(e){let t=Go().safeParse(e);return{errors:t.success?[]:qo(t.error.issues),ruleNames:new Set(Bo(e).map((n)=>n.toLowerCase()))}}function Vn(e){let t=zo(e);if(!t.ok)return t.result;return qn(t.parsed)}function zo(e){let t=[],n=new Set;try{let r=typeof e==="string"?pt(e):e,o=x(r);if(o===null)return t.push(`File not found: ${r.path}`),{ok:!1,result:{errors:t,ruleNames:n}};if(!o.trim())return t.push("Config file is empty"),{ok:!1,result:{errors:t,ruleNames:n}};return{ok:!0,parsed:JSON.parse(o)}}catch(r){if(r instanceof N)return t.push(r.message),{ok:!1,result:{errors:t,ruleNames:n}};let o=r instanceof Error?r.message:String(r);return t.push(r instanceof SyntaxError?"Invalid JSON":o),{ok:!1,result:{errors:t,ruleNames:n}}}}function Ko(e){return nd(e??process.cwd(),".safety-net.json")}function le(e){let t=zo(e);if(!t.ok)return t.result;let n=Vo(t.parsed);return{errors:n.errors,ruleNames:n.sources}}import{isAbsolute as rd,join as Ut,relative as od,resolve as Wo,sep as id}from"node:path";async function qe(e={}){let t=er(e);return sd(t,await Gt(t,Ue()))}function sd(e,t){if(!t.ok)return t;let n=J(e),r=[...new Set(ce(n.configPath,n.lockPath,e,n.filesystemScope))];if(r.length===0)return t;return{ok:!1,errors:r,warnings:t.warnings,entries:t.entries}}async function Gt(e,t,n,r={}){let o=null,i=!1;try{let s=J(e),a=Zn(s.configTarget);if(!a.ok)return a.result;let l=a.config;if(e.check)return pd(l,s,e);o={target:s.lockTarget,content:x(s.lockTarget)};let c=Xn(s.lockTarget);if(c.errors.some((L)=>L.startsWith("Unable to access ")))return{ok:!1,errors:c.errors,warnings:[],entries:[]};if(e.only&&c.errors.length>0)return{ok:!1,errors:c.errors,warnings:[],entries:[]};let d=c.errors.length>0?null:c.lock,p=e.only?ti(l,d,e.only):{ok:!0,specs:l.rules};if(!p.ok)return p.result;if(e.only&&!d&&p.specs.length<l.rules.length)return{ok:!1,errors:[`No lockfile available for partial update; run ${Qo}`],warnings:[],entries:[]};let m=(await ld(p.specs,(L)=>ri(L,s.configDir,e,d,s.filesystemScope,t),t)).map((L)=>fd(L,d,n));for(let L of m)hd(L.content,L.entry,s.configDir,e,s.filesystemScope);let u=e.only?md(l,d,m):m.map((L)=>L.entry);i=!0,Z(s.lockTarget,{version:1,rulebooks:u},void 0,r._testAfterPolicyRename);let h=new Map(m.map((L)=>[L.entry.spec,L.rulebook.rules.length])),f=yd(u,s.configDir,e,s.filesystemScope,r);return{ok:!0,errors:[],warnings:f,entries:u.map((L)=>gd(L,h))}}catch(s){if(i&&o)try{je(o.target,o.content)}catch(a){return Ge(a)}return Ge(s)}}async function Qn(e,t={}){return ad(e,er(t),Ue())}async function ad(e,t,n,r={}){let o=null,i=!1;try{let s=J(t),a=x(s.configTarget);o={target:s.configTarget,content:a};let l=Zn(s.configTarget);if(!l.ok)return l.result;let c=l.config,d=Xo(e)?await oi(e,n):[{spec:e}],p=d.map((h)=>h.spec),m=[...new Set([...c.rules,...p])];if(m.length>Jn)return cd();if(m.length!==c.rules.length)i=!0,Z(s.configTarget,{version:1,rules:m,overrides:c.overrides??{},transparent_wrappers:c.transparent_wrappers??[]},void 0,r._testAfterPolicyRename);let u=await Gt(t,n,new Map(d.filter((h)=>!!h.display_ref).map((h)=>[h.spec,h.display_ref])),r);if(!u.ok)je(s.configTarget,a);return u}catch(s){if(i&&o)try{je(o.target,o.content)}catch(a){return Ge(a)}return Ge(s)}}async function ld(e,t,n=Ue()){if(e.length>Jn)throw Error(Yn);let r=Array(e.length),o=0,i,s=Array.from({length:Math.min(e.length,ei.concurrency)},async()=>{while(!i){let a=o;if(a>=e.length)return;o++;try{r[a]=await t(e[a],a,n.controller.signal)}catch(l){if(!i)i={value:l},o=e.length,n.controller.abort(l);return}}});if(await Promise.all(s),i)throw i.value;return r}function cd(){return{ok:!1,errors:[Yn],warnings:[],entries:[]}}function er(e){return{cwd:e.cwd,cacheConfigDir:e.cacheConfigDir,userConfigDir:e.userConfigDir,userConfigPath:e.userConfigPath,projectConfigPath:e.projectConfigPath,global:e.global,check:e.check,only:e.only,refresh:e.refresh}}function dd(e){return{...er(e),deleteSource:e.deleteSource}}async function tr(e,t={}){try{return await ud(e,dd(t),{})}catch(n){return Ge(n)}}async function ud(e,t,n){let r=J(t),o=Y(r.configTarget);if(o.errors.length>0)return{ok:!1,errors:o.errors,warnings:[],entries:[]};if(!o.config)return{ok:!1,errors:[`No config found at ${r.configPath}`],warnings:[],entries:[]};let i=Xn(r.lockTarget);if(i.errors.length>0)return{ok:!1,errors:i.errors,warnings:[],entries:[]};let s=ni(o.config.rules,i.lock,e);if(!s.ok)return s.result;let a=t.deleteSource?Ld(r.configDir,s.specs,i.lock,r.filesystemScope):{ok:!0,dirs:[]};if(!a.ok)return a.result;let l=x(r.configTarget);if(l===null)return Ge(Error("Rules config is unavailable."));try{Z(r.configTarget,{version:1,rules:o.config.rules.filter((p)=>!s.specs.includes(p)),overrides:o.config.overrides??{},transparent_wrappers:o.config.transparent_wrappers??[]},void 0,n._testAfterPolicyRename)}catch(p){throw je(r.configTarget,l),p}let c=await Gt(t,Ue(),void 0,n);if(!c.ok)return je(r.configTarget,l),c;let d=bd(a.dirs,n,r.filesystemScope);if(!d.ok){je(r.configTarget,l);let p=await Gt(t,Ue(),void 0,n);if(!p.ok)return{ok:!1,errors:[...d.result.errors,...p.errors],warnings:p.warnings,entries:p.entries};return d.result}return c}async function pd(e,t,n){let r=ii(e,t.lockPath,t.configDir,n,n.global?"user":"project",t.filesystemScope);return{ok:r.errors.length===0&&r.warnings.length===0,errors:[...r.errors,...r.warnings],warnings:[],entries:r.entries}}function fd(e,t,n){let r=t?.rulebooks.find((i)=>i.spec===e.entry.spec&&i.kind==="github"),o=n?.get(e.entry.spec)??(r?.kind==="github"?r.display_ref:void 0);if(!o||e.entry.kind!=="github")return e;return{...e,entry:{...e.entry,display_ref:o}}}function md(e,t,n){let r=new Set(e.rules),o=new Set(t?.rulebooks.map((s)=>s.spec)??[]),i=new Map(n.map((s)=>[s.entry.spec,s.entry]));return[...(t?.rulebooks.filter((s)=>r.has(s.spec))??[]).map((s)=>i.get(s.spec)??s),...n.filter((s)=>!o.has(s.entry.spec)).map((s)=>s.entry)]}function gd(e,t){return{...e,ruleCount:t.get(e.spec)}}function hd(e,t,n,r,o){let i=Kn(t,Wn(n,r));xe(k(o,i),e)}function yd(e,t,n,r,o){let i=Wn(t,n),s=Bt(i),a=k(r,s),l=Be(a);if(!l)return[];let c=e.map((p)=>k(r,Kn(p,i))),d=l.filter((p)=>p.kind==="directory").map((p)=>({directory:k(r,Ut(s,p.name)),identity:k(r,Ut(s,p.name,Zo))})).filter((p)=>!c.some((m)=>Jo(p.identity,m))).map((p)=>p.directory);for(let p of d)Yo(p);return d.flatMap((p)=>{try{return wd(p,o),[]}catch{return["Unable to prune rules policy cache safely."]}})}function Ld(e,t,n,r){let o=new Map(n?.rulebooks.map((c)=>[c.spec,c])??[]),i=t.flatMap((c)=>{let d=o.get(c);if(!d)return mt.test(c)?[]:["--delete-source can only delete local rulebook sources"];return d.kind==="local-directory"?[]:["--delete-source can only delete local rulebook sources"]}),s=t.map((c)=>{let d=o.get(c);return Ut(e,d?.kind==="local-directory"?d.path:c)}),a=i.length>0?[]:s.flatMap((c)=>vd(e,c,r)),l=[...i,...a];return l.length>0?{ok:!1,result:{ok:!1,errors:l,warnings:[],entries:[]}}:{ok:!0,dirs:s}}function vd(e,t,n){let r=Wo(e),o=Wo(t),i=od(r,o);if(i===""||i===".."||i.startsWith(`..${id}`)||rd(i))return[`Refusing to delete local rulebook source outside ${e}: ${t}`];let s=k(n,o),a=Be(s);if(!a)return[`Local rulebook source directory not found: ${t}`];let l=a.find((c)=>c.name==="rulebook.json");if(!l)return[`Local rulebook source directory is missing rulebook.json: ${t}`];if(l.kind!=="file")throw new N(n.label);if(x(k(n,Ut(o,"rulebook.json"))),a.length>1)return[`Local rulebook source directory contains extra files: ${t}. delete manually if you really want to remove the directory.`];return[]}function bd(e,t,n){let r=e.flatMap((o)=>{try{return xd(k(n,o),t),[]}catch(i){return[`Failed to delete local rulebook source ${o}: ${i instanceof Error?i.message:String(i)}`]}});return r.length>0?{ok:!1,result:{ok:!1,errors:r,warnings:[],entries:[]}}:{ok:!0}}function wd(e,t){if(t._testPruneRulebookCacheDir){t._testPruneRulebookCacheDir(e.path);return}zn(e)}function xd(e,t){if(t._testDeleteLocalSourceDir){t._testDeleteLocalSourceDir(e.path);return}zn(e)}function je(e,t){if(t===null){ft(e);return}xe(e,t)}function Ge(e){return{ok:!1,errors:[e instanceof Error?e.message:String(e)],warnings:[],entries:[]}}function We(e,t){let n=Sd(t),r=ui(n),o={effectiveLevel:r.effectiveLevel,selectedPreset:n.policySnapshot.policy.safety.level??"standard",effectiveCapabilities:r.effectiveCapabilities,destructiveCommandRuleOverrides:n.policySnapshot.policy.destructiveCommandRuleOverrides},{configSource:i,configValid:s}=kd({cwd:t?.cwd,userConfigDir:t?.userConfigDir});if(!e||!e.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:i,configValid:s,...o};let a=Dd(e,n);if(a)return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:a.rule,matched:!0,reason:a.reason}]}]},result:"blocked",reason:G(a.reason),segment:G(a.target),...a.ruleId?{ruleId:G(a.ruleId)}:{},configSource:i,configValid:s,...o};let l=Uo(e,n),c=l.decision,d=c?.ruleId??Rd(e,n),p=ht.find((u)=>u.id===d&&u.activationCapability),m=p?r.policy.effectiveDestructiveCommandRules[p.id]:void 0;return{trace:Ed(l.trace),result:c?"blocked":"allowed",reason:c?G(c.reason):void 0,segment:c?G(c.evidence.find((u)=>u.kind==="command")?.segment??e):void 0,ruleId:c?.ruleId?G(c.ruleId):void 0,customRule:Ad(Pd(c?.ruleId,n.policySnapshot)),configSource:i,configValid:s,...o,...p&&m?{ruleActivation:{id:p.id,...m}}:{}}}function kd(e){let t=X(e?.cwd),n=e?.userConfigPath??Q(e),r=ee({cwd:e?.cwd,userConfigDir:e?.userConfigDir,userConfigPath:e?.userConfigPath});try{if(x(r.projectConfigTarget)!==null){if(le(r.projectConfigTarget).errors.length===0)return{configSource:t,configValid:!0};return{configSource:t,configValid:!1}}}catch(o){if(o instanceof N)return{configSource:t,configValid:!1};throw o}try{if(x(r.userConfigTarget)!==null){let o=le(r.userConfigTarget);return{configSource:n,configValid:o.errors.length===0}}return{configSource:null,configValid:!0}}catch(o){if(o instanceof N)return{configSource:n,configValid:!1};throw o}}function Sd(e){let t=Cd(e?.cwd??process.cwd()),n=e?.policySnapshot??B({cwd:t,userConfigDir:e?.userConfigDir}),r=de(n.policy);return{cwd:t,effectiveCwd:t,policySnapshot:n,environment:si(),protectedGitMetadata:di(t),effectiveCapabilities:r.capabilities,strict:e?.strict??r.strict,paranoidRm:r.paranoidRm,paranoidInterpreters:r.paranoidInterpreters,worktreeMode:r.worktreeMode}}function Dd(e,t){let n=t.cwd??process.cwd(),r=ai(Ke("",{command:e},{kind:"command",shell:"posix"},{executionCwd:n,configCwd:n},e)),o=mi(r);if(o)return{reason:fi,target:o.target,ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};let i=ci(r,t.protectedGitMetadata);if(i)return{reason:li,target:i.target,ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};let s=t.policySnapshot.policy,a=s.secretProtection.enabled===!1?null:hi(r,s.secretProtection,{strict:t.strict});if(a)return{reason:gi,target:a.target,ruleId:a.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"};return null}function Rd(e,t){let n=t.policySnapshot.policy,r=yt({...n,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...n.destructiveCommandRuleOverrides,...Object.fromEntries(ht.flatMap((o)=>o.activationCapability?[[o.id,"on"]]:[]))}},t.policySnapshot.state==="degraded"?{diagnostics:t.policySnapshot.diagnostics,reason:t.policySnapshot.reason}:void 0);return pi(e,{...t,policySnapshot:r,strict:!0,paranoidRm:!0,paranoidInterpreters:!0})?.ruleId}function Ad(e){if(!e)return;return{id:G(e.id),...e.rulebook?{rulebook:{name:G(e.rulebook.name),version:G(e.rulebook.version)}}:{},...e.source?{source:G(e.source)}:{},...e.override?{override:{type:"reason",reason:G(e.override.reason)}}:{}}}function Ed(e){let t=e.events.flatMap((r)=>r.kind==="step"&&r.scope==="global"?[r.step]:[]),n=new Map;for(let r of e.events){if(r.kind!=="step"||r.scope!=="segment")continue;let o=n.get(r.segmentIndex)??{index:r.segmentIndex,steps:[]};o.steps.push(r.step),n.set(r.segmentIndex,o)}return{steps:t,segments:[...n.values()]}}function Pd(e,t){let n=e?.replace(/^custom\./,"");if(!n||!t.policy.rules.some((r)=>r.name===n))return;return t.ruleMetadata[n]??Object.freeze({id:n})}function Nd(e){let t=Je(),n=T({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},e);if(ae(n.errors))return null;if(n.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(n.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let r=n.values.limit===void 0?20:yi(n.values.limit);if(r===null)return console.error("--limit must be a positive number"),null;let o=n.values.since===void 0?Math.min(30,t):yi(n.values.since);if(o===null||o>t)return console.error(`--since must be a positive number of days no greater than ${t}`),null;let i={limit:r,limitExplicit:n.values.limit!==void 0,since:o,sinceExplicit:n.values.since!==void 0,all:n.flags.all,json:n.flags.json,suspect:n.flags.suspect,pruneLegacy:n.flags.pruneLegacy,dryRun:n.flags.dryRun,id:n.values.id,agent:n.values.agent,rule:n.values.rule,session:n.values.session,project:n.values.project===void 0?void 0:$d(n.values.project)};if(i.id&&(i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.sinceExplicit||i.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(i.pruneLegacy&&(i.id!==void 0||i.agent!==void 0||i.rule!==void 0||i.session!==void 0||i.project!==void 0||i.suspect||i.all||i.sinceExplicit||i.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(i.dryRun&&!i.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return i}async function bi(e,t={}){let n=Nd(e);if(!n)return 1;let r=t.logsDir??ue();if(n.pruneLegacy)return Fd(r,n.json,n.dryRun);if(!r)return console.log(n.json?"[]":n.id?`No retained audit log entry found for id ${I(n.id)}.`:"No audit log entries found."),0;ke(r);let o={count:0},i=ye(r,o).flatMap((d)=>ut(d,o).map((p)=>({entry:p,file:d})));if(o.count>0)console.error(`warning: ${o.count} audit log ${o.count===1?"source":"sources"} could not be read; these results are incomplete`);if(n.id)return Ud(i,n,t.timeZone);let s=Date.now()-n.since*24*60*60*1000,a=i.filter((d)=>Gd(d,n,r,s)),l=n.suspect?jn(a.map((d)=>d.entry)):null,c=(l?a.filter((d)=>l.has(d.entry)):a).sort((d,p)=>Date.parse(p.entry.ts)-Date.parse(d.entry.ts)).slice(0,n.limit);if(n.json)return console.log(JSON.stringify(c.map((d)=>d.entry),null,2)),0;if(c.length===0)return console.log("No audit log entries found."),0;for(let d of c)console.log(Vd(d.entry,t.timeZone));return 0}function Fd(e,t,n){let r=e?Md(e).map((a)=>Od(e,a)):[];if(n)return Hd(r,t);let o=[],i=0,s=0;for(let a of r){let l=Li(a,{throwIfNoEntry:!1})?.size??0,c=jd(a);if(c){o.push(`${vi(a)}: ${c}`);continue}i++,s+=l}if(t)return console.log(JSON.stringify({removedFiles:i,removedBytes:s,failedFiles:o.length})),o.length===0?0:1;console.log(i===0&&o.length===0?"No legacy audit log files found.":`Removed ${i} legacy audit log ${i===1?"file":"files"} (${wi(s)}).`);for(let a of o)console.error(`Could not remove ${I(a)}`);if(console.log("Nested v2 audit logs were not changed."),i>0)console.log("This deletion cannot be undone.");return o.length===0?0:1}function Hd(e,t){let n=e.reduce((r,o)=>r+(Li(o,{throwIfNoEntry:!1})?.size??0),0);if(t)return console.log(JSON.stringify({dryRun:!0,files:e.length,bytes:n})),0;if(console.log(e.length===0?"No legacy audit log files found.":`Would remove ${e.length} legacy audit log ${e.length===1?"file":"files"} (${wi(n)}).`),console.log("Nested v2 audit logs are not included."),e.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Md(e){try{return Td(e,{withFileTypes:!0}).filter((t)=>t.isFile()&&t.name.endsWith(".jsonl")).map((t)=>t.name)}catch{return[]}}function jd(e){try{return Id(e),null}catch(t){return t instanceof Error?t.message:String(t)}}function wi(e){let t=["B","KiB","MiB","GiB"],n=Math.min(Math.floor(Math.log2(Math.max(e,1))/10),t.length-1);return`${Math.round(e/1024**n*10)/10} ${t[n]}`}function Ud(e,t,n){let r=e.filter((i)=>i.entry.id===t.id);if(r.length>1)return console.error(`Multiple audit log entries found for id ${I(t.id??"")}.`),1;if(t.json)return console.log(JSON.stringify(r.map((i)=>i.entry),null,2)),0;let o=r[0];if(!o)return console.log(`No retained audit log entry found for id ${I(t.id??"")}.`),0;return console.log(zd(o.entry,n)),0}function Gd(e,t,n,r){if(!t.all&&e.entry.decision==="allow")return!1;if(Date.parse(e.entry.ts)<r)return!1;if(t.agent!==void 0&&e.entry.agent!==t.agent)return!1;if(t.rule!==void 0&&e.entry.ruleId!==t.rule)return!1;if(t.session!==void 0&&!Bd(e,n,t.session))return!1;if(t.project!==void 0&&!qd(e.entry.cwd,t.project))return!1;return!0}function Bd(e,t,n){if(e.entry.sessionId===n)return!0;return _d(e.file)===t&&vi(e.file,".jsonl")===n}function qd(e,t){if(!e)return!1;return e===t||e.startsWith(`${t}/`)}function Vd(e,t){let n=I(e.id??"-"),r=I(e.decision??"deny"),o=e.cwd?` [${I(e.cwd)}]`:"",i=e.segment||e.command,s=i===e.command?"":"↳ ",a=i.length>50?`${i.slice(0,50)}…`:i;return`${n.padEnd(16)} ${I(xi(e.ts,t))} ${r.padEnd(5)} ${I(e.agent??"-").padEnd(15)} ${I(e.ruleId??"-").padEnd(20)} ${s}${I(a)}${o}`}function zd(e,t){let n=(o)=>I(o===void 0||o===null||o===""?"-":o),r=e.shape?`${e.agent??"-"} (shape: ${e.shape})`:e.agent??"-";return[`id: ${n(e.id)}`,`ts: ${n(xi(e.ts,t))}`,`decision: ${n(e.decision)}`,`agent: ${n(r)}`,`level: ${n(e.level)}`,`tool: ${n(e.toolName)}`,`rule: ${n(e.ruleId)}`,`intent: ${n(e.intent)}`,`stage: ${n(e.failureStage)}`,`error: ${n(e.errorCode)}`,`session: ${n(e.sessionId)}`,`cwd: ${n(e.cwd)}`,`version: ${n(e.v)}`,`truncated: ${n(e.truncated===!0?"yes":void 0)}`,`reason: ${n(e.reason)}`,`command: ${n(e.command)}`,`segment: ${n(e.segment)}`].join(`
|
|
5
|
+
`)}function xi(e,t){let n=new Date(e);if(Number.isNaN(n.getTime()))return e;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:t}).format(n)}function yi(e){let t=Number(e);return Number.isFinite(t)&&t>0?t:null}var Ci={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 ki={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 Si={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 Oi,join as ru,relative as ou}from"node:path";var Kd=8388608;function Wd(e,t){console.log(JSON.stringify(e(Ri(t))))}async function Jd(e){let t;try{t=(await hr(process.stdin)).trim()}catch{e({reason:"Failed to parse hook input JSON."});return}if(!t){e({reason:"Missing hook input JSON."});return}return yr(t,e,"Failed to parse hook input JSON.")}async function hr(e){let t=[],n=0;for await(let r of e){let o=typeof r==="string"?Buffer.from(r,"utf-8"):Buffer.from(r.buffer,r.byteOffset,r.byteLength);if(n+=o.byteLength,n>Kd)throw Yd(e),Error("hook input byte limit exceeded");t.push(o)}return Buffer.concat(t,n).toString("utf-8")}function Yd(e){let t=e.destroy??e.cancel;if(!t)return;try{Promise.resolve(t.call(e)).catch(()=>{})}catch{}}function yr(e,t,n){try{return JSON.parse(e)}catch{t({reason:n});return}}function M(e,t){let n=t.get(e);return n?{kind:"command",shell:n}:{kind:Ei(e)}}function te(e,t,n,r){let o=e===void 0?process.cwd():e,i=typeof o==="string"&&o.trim()!==""?fe([o]):void 0;if(i)return{configCwd:i,executionCwd:i};return O(r,t,n,eu(o)),null}function O(e,t,n,r){let o;try{o=gr(t)}catch(i){if(!(i instanceof pe))throw i}e(qt({command:o,segment:r,toolName:n}))}async function Zd(e){let t=await Jd(e.outputDeny);if(t===void 0)return;if(!t||typeof t!=="object"||Array.isArray(t)){O(e.outputDeny);return}if(!e.isSupported(t))return;let n=e.getAgent?.(t)??e.agent,r=e.agent===n?void 0:e.agent,o=nu(t),i=(u,h)=>{Di(u,()=>e.getSessionId(t),{agent:n,shape:r,toolName:h,cwd:o}),e.outputDeny(u)},s=e.getToolName(t);if(typeof s!=="string"||s.trim()===""){O((u)=>i(u),tu(t));return}let a=s,l=(u)=>i(u,a),c;try{c=e.getToolInput(t,a,l)}catch(u){if(!(u instanceof pe))throw u;O(l,void 0,a);return}if(!c.ok)return;let d=e.getContext(t,c.input,a,l);if(!d)return;let p;try{p=gr(c.input)}catch(u){if(!(u instanceof pe))throw u;O(l,void 0,a);return}let m=Ke(a,c.input,c.route,d,p??null);try{let u=Vt(m,{guard:{auditAllowed:Pi(),dependencies:e.guardDependencies},audit:{agent:n,shape:r,getSessionId:()=>e.getSessionId(t)}}),h=mr(u,{includeEvidence:!0,toolName:u.stage==="command-analysis"?void 0:a});if(h){e.outputDeny(h);return}e.outputAllow?.()}catch(u){if(!(u instanceof Ti))throw u;Xd(u);let h=mr(u.evaluation,{includeEvidence:!0,toolName:u.evaluation.stage==="command-analysis"?void 0:a});if(h)e.outputDeny(h);return}}function Xd(e){if(!Lt(S.debug))return;console.error(`CC Safety Net debug: ${Qd(e.stage)}: ${Ai(e.cause)}`)}function Qd(e){if(e==="policy-protection")return"hook policy protection failed";if(e==="config-load")return"hook config loading failed";if(e==="secret-protection")return"hook secret protection failed";return"hook analysis failed"}function eu(e){return typeof e==="string"?e:void 0}function tu(e){if(!e||typeof e!=="object"||Array.isArray(e))return;if(Object.hasOwn(e,"tool_input"))return e.tool_input;let t=e.toolCall;if(t&&typeof t==="object"&&!Array.isArray(t))return t.args;return}function nu(e){if(!e||typeof e!=="object"||Array.isArray(e))return null;let t=e.cwd;if(typeof t==="string")return t;let n=e.toolCall;if(!n||typeof n!=="object"||Array.isArray(n))return null;let r=n.args;if(!r||typeof r!=="object"||Array.isArray(r))return null;let o=r.Cwd;return typeof o==="string"?o:null}async function j(e){let t=(o)=>Wd(e.createDenyOutput,o),n=e.createAllowOutput;await Zd({...e,outputDeny:t,outputAllow:n?()=>console.log(JSON.stringify(n())):void 0})}function Ct(e){return ru(e,".gemini","config","hooks.json")}var iu=new Map([["run_command","auto"]]),su=new Set(["absolutepath","directorypath","file_path","filepath","path","searchdirectory","searchpath","target_file","targetfile"]);function $i(e){return M(e,iu)}async function Ni(){await j({agent:"antigravity-cli",createDenyOutput:(e)=>({decision:"deny",reason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolCall?.name,getToolInput:(e,t)=>({ok:!0,input:uu(e.toolCall?.args,t),route:$i(t)}),getContext:au,getSessionId:(e)=>e.conversationId})}function au(e,t,n,r){let i=du(e).flatMap((c)=>{let d=fe([c]);return d?[d]:[]});if(!i[0])return Re(r,t,n),null;if(n!=="run_command"){let c;try{c=lu(t,n,i)}catch(d){if(d instanceof pe)return Re(r,void 0,n),null;if(!(d instanceof Se))throw d;return Re(r,t,n),null}if(!c)return Re(r,t,n),null;return{configCwd:c,executionCwd:c}}let s=e.toolCall?.args;if(!s||!Object.hasOwn(s,"Cwd"))return{configCwd:i[0],executionCwd:i[0]};let a=s.Cwd;if(typeof a!=="string"||a.trim()==="")return Re(r,t,n),null;let l=Ae(a,i);if(l){let c=Fi(l,i);if(!c)return Re(r,t,n,a),null;return{configCwd:c,executionCwd:l}}return Re(r,t,n,a),null}function lu(e,t,n){let r=$i(t),o=[...Ii(e,su),...r.kind==="patch"?_i(e):[]].filter(Oi),i=zt(),s=new Set(o.flatMap((a)=>{let l=Fi(wt(a,xt,i),n);return l?[l]:[]}));if(s.size>1)return null;return[...s][0]??n[0]??null}function Fi(e,t){return t.filter((n)=>cu(e,n)).reduce((n,r)=>r.length>n.length?r:n,"")||null}function cu(e,t){let n=ou(t,e);return n===""||!n.startsWith("..")&&!Oi(n)}function Re(e,t,n,r){let o=t&&typeof t==="object"?t.command:void 0;e(qt({command:typeof o==="string"?o:void 0,segment:r,toolName:n}))}function du(e){if(e.workspacePaths===void 0)return[process.cwd()];let t=Array.isArray(e.workspacePaths)?e.workspacePaths.filter((n)=>typeof n==="string"&&n.trim()!==""):[];return fe(t)?t:[]}function uu(e,t){if(!e)return;if(t!=="run_command")return e;return{...e,command:typeof e.CommandLine==="string"&&e.CommandLine!==""?e.CommandLine:void 0}}var kt=[{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"]}}],Kt=kt.slice().sort((e,t)=>e.doctorOrder-t.doctorOrder).map((e)=>e.id),Hi=kt.filter((e)=>("runtime"in e)).slice().sort((e,t)=>e.runtime.order-t.runtime.order).map((e)=>({id:e.id,displayName:"displayName"in e.runtime?e.runtime.displayName:e.displayName,flags:e.runtime.flags,legacyFlags:"legacyFlags"in e.runtime?e.runtime.legacyFlags:[],description:e.runtime.description,legacyTopLevelFlags:e.runtime.legacyTopLevelFlags})),V=kt.slice().sort((e,t)=>e.install.order-t.install.order).map((e)=>({id:e.id,...e.install})).map(({order:e,...t})=>t),K0=Object.fromEntries(kt.map((e)=>[e.id,e.displayName]));function R(e){return kt.find((t)=>t.id===e)?.displayName??e}import{homedir as pu}from"node:os";import{isAbsolute as Mi,join as Lr}from"node:path";function Ui(e){if(e!==void 0&&e!==null&&!Mi(e))return"unknown";try{let t=zt(),n=e?wt(e,xt,t):void 0,r=process.env.HOME||pu(),o=[["codex",process.env.CODEX_HOME||Lr(r,".codex")],["copilot-cli",process.env.COPILOT_HOME||Lr(r,".copilot")],["claude-code",process.env.CLAUDE_CONFIG_DIR||Lr(r,".claude")]],i=n?o.flatMap(([s,a])=>{if(!Mi(a))return[];return ji(n,wt(a,xt,t))?[s]:[]}):[];if(i.length===1)return i[0]??"unknown";if(i.length>1)return"unknown"}catch(t){if(t instanceof Se)return"unknown";return"unknown"}if(process.env.CLAUDECODE==="1"||Boolean(process.env.CLAUDE_CODE_ENTRYPOINT))return"claude-code";return"unknown"}var vr="PreToolUse",Gi="BeforeTool",Bi="pre_tool_call",br="PreToolUse";var fu=new Map([["Bash","posix"],["PowerShell","powershell"]]);function mu(e){return M(e,fu)}async function qi(){await j({agent:"claude-code",getAgent:(e)=>Ui(e.transcript_path),createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:vr,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===vr,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:mu(t)}),getContext:(e,t,n,r)=>te(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}var gu=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);function hu(e){return M(e,gu)}async function Vi(){await j({agent:"copilot-cli",createDenyOutput:(e)=>({permissionDecision:"deny",permissionDecisionReason:e}),isSupported:()=>!0,getToolName:(e)=>e.toolName,getToolInput:(e,t,n)=>{if(typeof e.toolArgs!=="string")return n({reason:"Failed to parse toolArgs JSON."}),{ok:!1};let r=yr(e.toolArgs,n,"Failed to parse toolArgs JSON.");if(r===void 0)return{ok:!1};return{ok:!0,input:r,route:hu(t)}},getContext:(e,t,n,r)=>te(e.cwd,t,n,r),getSessionId:(e)=>typeof e.sessionId==="string"&&e.sessionId.trim()?e.sessionId:void 0})}var yu=new Map([["Shell","auto"]]);function Lu(e){return M(e,yu)}async function zi(){await j({agent:"cursor",createDenyOutput:(e)=>({permission:"deny",user_message:e,agent_message:e}),createAllowOutput:()=>({permission:"allow"}),isSupported:()=>!0,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:Lu(t)}),getContext:vu,getSessionId:(e)=>e.conversation_id})}function vu(e,t,n,r){let o=bu(e);if(!o[0])return O(r,t,n),null;let i=Ae(xu(e.cwd),o);if(!i)return O(r,t,n,typeof e.cwd==="string"?e.cwd:void 0),null;if(t===null||typeof t!=="object"||Array.isArray(t))return{configCwd:i,executionCwd:i};if(!Object.hasOwn(t,"working_directory"))return{configCwd:i,executionCwd:i};let s=t.working_directory;if(typeof s!=="string"||s.trim()==="")return O(r,t,n),null;let a=Ae(s,o);if(!a)return O(r,t,n,s),null;return{configCwd:i,executionCwd:a}}function bu(e){return wu(e).flatMap((t)=>{let n=fe([t]);return n?[n]:[]})}function wu(e){if(e.workspace_roots===void 0)return typeof e.cwd==="string"&&e.cwd.trim()!==""?[e.cwd]:[];if(!Array.isArray(e.workspace_roots))return[];return e.workspace_roots.filter((t)=>typeof t==="string"&&t.trim()!=="")}function xu(e){return typeof e==="string"&&e.trim()!==""?e:"."}var Cu=new Map([["run_shell_command","auto"]]);function ku(e){return M(e,Cu)}async function Ki(){await j({agent:"gemini-cli",createDenyOutput:(e)=>({decision:"deny",reason:e,systemMessage:e}),isSupported:(e)=>e.hook_event_name===Gi,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:ku(t)}),getContext:(e,t,n,r)=>te(e.cwd,t,n,r),getSessionId:(e)=>e.session_id})}import{resolve as Su}from"node:path";var Du=new Map([["terminal","posix"]]);async function Wi(){await j({agent:"hermes-agent",createDenyOutput:(e)=>({action:"block",message:e}),isSupported:(e)=>e.hook_event_name===Bi,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:M(t,Du)}),getContext:Ru,getSessionId:(e)=>e.session_id})}function Ru(e,t,n,r){let o=te(e.cwd,t,n,r);if(!o)return null;if(!t||typeof t!=="object"||Array.isArray(t))return o;if(!Object.hasOwn(t,"workdir"))return o;let i=t.workdir;if(typeof i!=="string"||i.trim()==="")return O(r,t,n),null;let s=fe([Su(o.configCwd,i)]);if(!s)return O(r,t,n,i),null;return{...o,executionCwd:s}}var Ji=new Map([["Bash","posix"]]);function Au(e){return M(e,Ji)}async function Yi(){await j({agent:"kimi-code",createDenyOutput:(e)=>({hookSpecificOutput:{hookEventName:br,permissionDecision:"deny",permissionDecisionReason:e}}),isSupported:(e)=>e.hook_event_name===br,getToolName:(e)=>e.tool_name,getToolInput:(e,t)=>({ok:!0,input:e.tool_input,route:Au(t)}),getContext:(e,t,n,r)=>{let o=te(e.cwd,t,n,r);if(!o)return null;let i=e.tool_input;if(!Ji.has(n)||!i||!Object.hasOwn(i,"cwd"))return o;let s=i.cwd;if(typeof s!=="string"||s.trim()==="")return O(r,t,n),null;let a=Ae(s,[o.configCwd]);if(!a)return O(r,t,n,s),null;return{configCwd:o.configCwd,executionCwd:a}},getSessionId:(e)=>e.session_id})}var Eu={"antigravity-cli":Ni,"claude-code":qi,"copilot-cli":Vi,cursor:zi,"gemini-cli":Ki,"hermes-agent":Wi,"kimi-code":Yi},Ye=Hi.map((e)=>({...e,run:Eu[e.id]}));function Zi(e){let t=T({label:"hook",booleans:Object.fromEntries(Ye.map((r)=>[r.id,[...r.flags,...r.legacyFlags]]))},e);if(t.errors.length>0)return;let n=Ye.filter((r)=>t.flags[r.id]);return n.length===1?n[0]:void 0}function Xi(e){return Ye.find((t)=>t.legacyTopLevelFlags.some((n)=>n===e))}var Pu=Ye.map((e)=>({flags:e.flags.join(", "),description:e.description})),Tu=Ye.flatMap((e)=>e.flags.map((t)=>`cc-safety-net hook ${t}`)),Qi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Pu,{flags:"-h, --help",description:"Show this help"}],examples:Tu};var es={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...V.map((e)=>({flags:e.flag,description:`Install ${R(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...V.map((e)=>`cc-safety-net install ${e.flag}`)]},ts={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...V.map((e)=>({flags:e.flag,description:`Uninstall ${R(e.id)} ${e.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...V.map((e)=>`cc-safety-net uninstall ${e.flag}`)]},ns={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 rs={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 Ze={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 os={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 is={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 Wt=[os,Ci,rs,ki,Ze,es,ns,ts,Qi,Si,is];function Iu(e){return e.aliases??[]}function Jt(e){let t=e.toLowerCase();return Wt.find((n)=>n.name.toLowerCase()===t||Iu(n).some((r)=>r.toLowerCase()===t))}import{readFileSync as _u}from"node:fs";import{basename as Ou}from"node:path";function Yt(e=7,t=ue()){let n=Date.now()-e*24*60*60*1000,r=[],o=new Set,i=0,s,a,l,c;if(t)ke(t);let d={count:0},p=t?ye(t,d):[];for(let u of p)try{let f=_u(u,"utf-8").trim().split(`
|
|
6
|
+
`).filter(Boolean);for(let L of f)try{let v=JSON.parse(L);if(v.decision==="allow")continue;let w=new Date(v.ts).getTime();if(w>=n){if(i++,o.add(v.sessionId??Ou(u,".jsonl")),a===void 0||w<=a)s=v.ts,a=w;if(c===void 0||w>c)l=v.ts,c=w;$u(r,v,w)}}catch{d.count++}}catch{d.count++}let m=r.map((u)=>({timestamp:u.ts,command:u.command,reason:u.reason,relativeTime:Mn(new Date(u.ts))}));return{totalBlocked:i,sessionCount:o.size,recentEntries:m,oldestEntry:s,newestEntry:l,unreadable:d.count}}function $u(e,t,n){let r=e.findIndex((o)=>n>new Date(o.ts).getTime());if(r===-1){if(e.length<3)e.push(t);return}if(e.splice(r,0,t),e.length>3)e.pop()}import{dirname as Nu}from"node:path";function ss(e,t,n,r,o){let i;try{if(x(r)===null)return{path:e,exists:!1,valid:!1,ruleCount:0};i=le(r),i.errors.push(...ce(e,t,{userConfigDir:n},o))}catch(s){if(!(s instanceof N))throw s;i={errors:[s.message],ruleNames:new Set}}return{path:e,exists:!0,valid:i.errors.length===0,ruleCount:i.ruleNames.size,...i.errors.length>0?{errors:i.errors}:{}}}function Fu(e,t){return{source:t,name:e.name,command:e.command,subcommand:e.subcommand,blockArgs:[...e.block_args],reason:e.reason}}function as(e,t){let n=t?.userConfigPath??Q(),r=t?.projectConfigPath??X(e),o=Nu(n),i=Le({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),s=ee({cwd:e,userConfigPath:n,projectConfigPath:r,userConfigDir:o}),a=new Map(i.rulebooks.flatMap((l)=>l.rules.map((c)=>[c,l.source])));return{userConfig:ss(n,Ve({userConfigPath:n}),o,s.userConfigTarget,s.userScope),projectConfig:ss(r,ze(r),o,s.projectConfigTarget,s.projectScope),effectiveRules:i.rules.map((l)=>Fu(l,a.get(l.name)??"project")),shadowedRules:[]}}var Hu=[{flag:S.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:S.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:S.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:S.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:S.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:S.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:S.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:S.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function ls(){return[...Hu.map((e)=>({name:e.flag.name,value:ur(e.flag),isSet:pr(e.flag),legacyName:e.flag.legacyName,legacyValue:e.flag.legacyName?process.env[e.flag.legacyName]:void 0,legacyIsSet:e.flag.legacyName?process.env[e.flag.legacyName]!==void 0:void 0,description:e.description,defaultBehavior:e.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:process.env.CC_SAFETY_NET_HOME,isSet:process.env.CC_SAFETY_NET_HOME!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var cs={error:0,warning:1,info:2},Mu=["policy","config","audit"];function ju(e){return e.map((t)=>{if(t==="ownership")return"is not owned by the current user";if(t==="permissions")return"has unsafe permissions";if(t==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var Uu=[{derive:(e)=>e.hooks.length>0&&e.hooks.every((t)=>!t.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(e)=>e.hooks.filter((t)=>t.inspectionStatus==="failed").map((t)=>{let n=R(t.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${n} inspection failed`,detail:`Doctor could not verify the ${n} integration configuration.`,fixHint:`Correct the reported ${n} configuration error, then run \`cc-safety-net doctor\` again.`,integration:t.platform}})},{derive:(e)=>e.userConfig.exists&&!e.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.userConfig.path}]:[]},{derive:(e)=>e.projectConfig.exists&&!e.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:e.projectConfig.path}]:[]},{derive:(e)=>e.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${e.configState.reason}`,fixHint:"Correct the named source, run `cc-safety-net rule sync` for a rule source, then rerun doctor."}]:[]},{derive:(e)=>{let t=e.environment.find((n)=>n.name==="CC_SAFETY_NET_AUDIT_SCOPE");return dr(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."}]:[]}},...Mu.map((e)=>({derive:(t)=>t.posture.directories.filter((n)=>n.kind===e&&n.status==="unsafe").map((n)=>({checkId:`posture.${e}-directory-unsafe`,severity:"error",title:`${e[0]?.toUpperCase()}${e.slice(1)} directory is unsafe`,detail:`The ${e} directory ${ju(n.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...n.path?{path:n.path}:{}}))})),{derive:(e)=>{let t=[...e.effectiveSafety.weakenedRuleOverrides].sort();return t.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${t.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${t.join(", ")}.`}]:[]}}];function ds(e){return Uu.flatMap((t,n)=>t.derive(e).map((r,o)=>({finding:r,catalogOrder:n,occurrence:o}))).sort((t,n)=>cs[t.finding.severity]-cs[n.finding.severity]||t.catalogOrder-n.catalogOrder||t.occurrence-n.occurrence).map((t)=>t.finding)}function ne(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Gu=(e)=>ne()?`\x1B[32m${e}\x1B[0m`:e,Bu=(e)=>ne()?`\x1B[33m${e}\x1B[0m`:e,qu=(e)=>ne()?`\x1B[34m${e}\x1B[0m`:e,Vu=(e)=>ne()?`\x1B[35m${e}\x1B[0m`:e,zu=(e)=>ne()?`\x1B[36m${e}\x1B[0m`:e,Ku=(e)=>ne()?`\x1B[31m${e}\x1B[0m`:e,Wu=(e)=>ne()?`\x1B[2m${e}\x1B[0m`:e,Ju=(e)=>ne()?`\x1B[1m${e}\x1B[0m`:e,g={green:Gu,yellow:Bu,blue:qu,magenta:Vu,cyan:zu,red:Ku,dim:Wu,bold:Ju},Yu="\x1B[0m",Zu=[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 Xu(e){let t=e;return()=>(t=(t*1664525+1013904223)%4294967296,t/4294967296)}function Qu(e){let t=[...Zu],n=Xu(e);for(let r=t.length-1;r>0;r--){let o=Math.floor(n()*(r+1)),i=t[r];t[r]=t[o],t[o]=i}return t}function ep(e,t=0){if(!ne())return"";let n=Qu(t);return`\x1B[38;5;${n[e%n.length]}m`}function us(e,t,n=0){if(!ne())return`"${e}"`;return`${ep(t,n)}"${e}"${Yu}`}var tp=new RegExp("\x1B\\[[0-9;]*m","g"),wr=(e)=>e.replace(tp,"").length;function Ee(e){let t=(e.headers??e.rows[0]??[]).map((s,a)=>{let l=Math.max(...e.rows.map((c)=>wr(c[a]??"")));return Math.max(wr(s),l)}),n=(s,a)=>s+" ".repeat(Math.max(0,a-wr(s))),r=(s,a)=>a[0]+t.map((l)=>s.repeat(l+2)).join(a[1])+a[2],o=(s)=>`│ ${s.map((a,l)=>n(a,t[l]??0)).join(" │ ")} │`,i=e.headers?[` ${o(e.headers)}`,` ${r("─",["├","┼","┤"])}`]:[];return[` ${r("─",["┌","┬","┐"])}`,...i,...e.rows.map((s)=>` ${o(s)}`),` ${r("─",["└","┴","┘"])}`].join(`
|
|
7
|
+
`)}function ps(e){let t=[];t.push("Hook Integration"),t.push(np(e));let n=[],r=[];for(let o of e){let i=R(o.platform);if(o.errors&&o.errors.length>0)for(let s of o.errors)if(o.configured)n.push({platform:i,message:s});else r.push({platform:i,message:s})}for(let o of n)t.push(` Warning (${o.platform}): ${o.message}`);for(let o of r)t.push(g.red(` Error (${o.platform}): ${o.message}`));return t.join(`
|
|
8
|
+
`)}function np(e){let t=["Platform","Discovery","Configuration","Inspection"],n=e.map((r)=>{let o=R(r.platform);if(r.inspectionStatus==="not-inspected"){let l=g.dim("Not inspected");return[o,l,l,l]}let i=r.detected?g.green("Detected"):r.inspectionStatus==="failed"?g.red("Unknown"):g.dim("Not detected"),s=r.configured?g.green("Configured"):r.detected?g.yellow("Not configured"):r.inspectionStatus==="failed"?g.red("Unknown"):g.dim("Not applicable"),a=r.inspectionStatus==="verified"?g.green("Verified"):r.inspectionStatus==="failed"?g.red("Failed"):g.dim("Not applicable");return[o,i,s,a]});return Ee({headers:t,rows:n})}function fs(e){let n=["Guard Engine Verification",` Synthetic self-test: ${e.failed>0?g.red(`${e.passed}/${e.total} FAIL`):g.green(`${e.passed}/${e.total} passed`)}`],r=e.results.filter((o)=>!o.passed);if(r.length>0){n.push(""),n.push(g.red(" Failures:"));for(let o of r)n.push(g.red(` • ${o.description}`)),n.push(g.red(` expected ${o.expected}, got ${o.actual}`))}return n.join(`
|
|
9
|
+
`)}function rp(e){if(e.length===0)return" (no custom rules)";let t=["Source","Name","Command","Block Args"],n=e.map((r)=>[r.source,r.name,r.subcommand?`${r.command} ${r.subcommand}`:r.command,r.blockArgs.join(", ")]);return Ee({headers:t,rows:n})}function ms(e){let t=[];if(t.push("Configuration"),t.push(op(e.userConfig,e.projectConfig)),t.push(""),e.effectiveRules.length>0)t.push(` Effective rules (${e.effectiveRules.length} total):`),t.push(rp(e.effectiveRules));else t.push(" Effective rules: (none - using built-in rules only)");for(let n of e.shadowedRules)t.push(""),t.push(` Note: Project rule "${n.name}" shadows user rule with same name`);return t.join(`
|
|
10
|
+
`)}function op(e,t){let n=["Scope","Status"],r=(i)=>{if(!i.exists)return g.dim("N/A");if(!i.valid)return g.red(`Invalid (${i.errors?.[0]??"unknown error"})`);return g.green("Configured")},o=[["User",r(e)],["Project",r(t)]];return Ee({headers:n,rows:o})}function gs(e){let t=[];return t.push("Environment"),t.push(ip(e)),t.join(`
|
|
11
|
+
`)}function hs(e){let t=["Effective Safety",` Selected preset: ${e.effectiveSafety.selectedPreset}`,` Effective: ${e.effectiveSafety.level}`],n=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[r,o]of n){let i=e.effectiveSafety.capabilities[r],s=i.enabled?g.green("ON"):g.dim("OFF"),a=i.sources.length>0?` (${i.sources.join(", ")})`:"";t.push(` ${o}: ${s} via ${i.source}${a}`)}t.push(` Stored rule customizations: ${e.effectiveSafety.ruleCounts.stored}`),t.push(` Effective rule customizations: ${e.effectiveSafety.ruleCounts.effective}`);for(let[r,o]of Object.entries(e.effectiveSafety.ruleOverrides))t.push(` ${r}: ${o}`);return t.join(`
|
|
12
|
+
`)}function ys(e){let t=["Findings"];if(e.length===0)return t.push(" No findings from inspected doctor facts."),t.join(`
|
|
13
|
+
`);for(let n of e){let r=`[${n.severity.toUpperCase()}] ${n.checkId}: ${I(n.title)}`,o=n.severity==="error"?g.red:n.severity==="warning"?g.yellow:g.blue;if(t.push(` ${o(r)}`),t.push(` ${I(n.detail)}`),n.path)t.push(` Path: ${I(n.path)}`);if(n.fixHint)t.push(` Fix: ${I(n.fixHint)}`)}return t.join(`
|
|
14
|
+
`)}function ip(e){let t=["Variable","Status","Legacy"],n=e.map((r)=>{let o=r.isSet?g.green("✓"):g.dim("✗"),i=r.legacyName&&r.legacyIsSet?`${r.legacyName} ${g.green("✓")}`:r.legacyName??"";return[r.name,o,i]});return Ee({headers:t,rows:n})}function Ls(e){let t=[];if(e.totalBlocked===0)t.push("Recent Activity"),t.push(" No blocked commands in the last 7 days"),t.push(" Tip: This is normal for new installations");else t.push(`Recent Activity · last 7 days (${e.totalBlocked} blocked / ${e.sessionCount} sessions)`),t.push(sp(e.recentEntries));if(e.unreadable>0)t.push(` Warning: ${e.unreadable} audit log ${e.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return t.join(`
|
|
15
|
+
`)}function sp(e){let t=["Time","Command"],n=e.map((r)=>{let o=I(r.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),i=o.length>40?`${o.slice(0,37)}...`:o;return[r.relativeTime,i]});return Ee({headers:t,rows:n})}function vs(e){let t=[];if(t.push("Update Check"),e.latestVersion===null&&!e.error)return t.push(Zt([["Status",g.dim("Skipped")],["Installed",e.currentVersion]])),t.join(`
|
|
16
|
+
`);if(e.error)return t.push(Zt([["Status",`${g.yellow("⚠")} Error`],["Installed",e.currentVersion],["Error",g.dim(e.error)]])),t.join(`
|
|
17
|
+
`);if(e.updateAvailable)return t.push(Zt([["Status",`${g.yellow("⚠")} Update Available`],["Current",e.currentVersion],["Latest",g.green(e.latestVersion??"")]])),t.push(""),t.push(" Run: bunx cc-safety-net@latest doctor"),t.push(" Or: npx cc-safety-net@latest doctor"),t.join(`
|
|
18
|
+
`);return t.push(Zt([["Status",`${g.green("✓")} Up to date`],["Version",e.currentVersion]])),t.join(`
|
|
19
|
+
`)}function Zt(e){return Ee({rows:e})}function bs(e){let t=[];return t.push("System Info"),t.push(ap(e)),t.join(`
|
|
20
|
+
`)}function ap(e){let t=["Component","Version"],n=(i)=>{if(i===null)return g.dim("not found");return i},o=[{label:"cc-safety-net",value:e.version},...Kt.map((i)=>({label:R(i),value:e.versions[i]??null})),{label:"Node.js",value:e.nodeVersion},{label:"npm",value:e.npmVersion},{label:"Bun",value:e.bunVersion},{label:"Platform",value:e.platform}].map((i)=>[i.label,n(i.value)]);return Ee({headers:t,rows:o})}function ws(e){if(e.findings.length===0)return g.green(`
|
|
21
|
+
No findings from inspected doctor facts.`);let t={error:e.findings.filter((i)=>i.severity==="error").length,warning:e.findings.filter((i)=>i.severity==="warning").length,info:e.findings.filter((i)=>i.severity==="info").length},n=["error","warning","info"].filter((i)=>t[i]>0).map((i)=>`${t[i]} ${i}`),r=e.findings.length===1?"finding":"findings",o=`
|
|
22
|
+
${e.findings.length} ${r}: ${n.join(", ")}.`;if(t.error>0)return g.red(o);if(t.warning>0)return g.yellow(o);return g.blue(o)}import{lstatSync as lp}from"node:fs";import{dirname as xr}from"node:path";function Cr(e,t){try{let n=lp(t);if(n.isSymbolicLink())return{kind:e,path:t,status:"unsafe",issues:["symlink"]};if(!n.isDirectory())return{kind:e,path:t,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:e,path:t,status:"unknown",issues:[]};let r=[...n.uid!==process.getuid()?["ownership"]:[],...(n.mode&18)!==0?["permissions"]:[]];return{kind:e,path:t,status:r.length>0?"unsafe":"safe",issues:r}}catch(n){if(typeof n==="object"&&n!==null&&"code"in n&&n.code==="ENOENT")return{kind:e,path:t,status:"not-applicable",issues:[]};return{kind:e,path:t,status:"unknown",issues:[]}}}function xs(e){let t=ue();return{directories:[Cr("policy",xr(xr(e))),Cr("config",xr(e)),...t?[Cr("audit",t)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as cp}from"node:child_process";import{existsSync as Cs}from"node:fs";import{delimiter as dp,extname as up,join as pp}from"node:path";import{stripVTControlCharacters as ks}from"node:util";var Ds="2.0.9",fp=5000,mp="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function P(){return Ds}function kr(e,t){let n=e[t];if(n)return n;let r=Object.keys(e).find((o)=>o.toLowerCase()===t.toLowerCase()&&!!e[o]);return r?e[r]:n}function gp(e){return(kr(e,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((t)=>t.length>0)}function hp(e,t){let n=up(e)?[e]:[...gp(t).map((r)=>`${e}${r}`),e];if(e.includes("/")||e.includes("\\"))return n.find((r)=>Cs(r))??e;return(kr(t,"PATH")??"").split(dp).flatMap((r)=>n.map((o)=>pp(r,o))).find((r)=>Cs(r))??e}function Ss(e){if(!/[\s"&|<>^]/.test(e))return e;return`"${e.replace(/"/g,'""')}"`}function Pe(e,t){let[n,...r]=e,o=t[mp]==="win32"?"win32":process.platform;if(!n||o!=="win32")return{cmd:n??"",args:r};let i=hp(n,t);if(!/\.(?:bat|cmd)$/i.test(i))return{cmd:i,args:r};return{cmd:kr(t,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Ss(i),...r.map(Ss)].join(" ")]}}var Xe=async(e,t=fp)=>{let n=await yp(e,{timeoutMs:t});if(n.code!==0)return null;return ks(n.stdout).trim()||ks(n.stderr).trim()||null};function yp(e,t){let[n,...r]=e;if(!n)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((o)=>{try{let i=Pe([n,...r],process.env),s=cp(i.cmd,i.args,{stdio:["ignore","pipe","pipe"]}),a=!1,l="",c="";s.stdout.on("data",(m)=>{l+=m.toString()}),s.stderr.on("data",(m)=>{c+=m.toString()});let d=(m)=>{if(a)return;a=!0,clearTimeout(p),o(m)},p=setTimeout(()=>{s.kill(),d({code:null,stdout:l,stderr:c})},t.timeoutMs);s.on("close",(m)=>{d({code:m,stdout:l,stderr:c})}),s.on("error",()=>{d({code:null,stdout:l,stderr:c})})}catch{o({code:null,stdout:"",stderr:""})}})}function Xt(e){if(!e)return null;let t=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(e);if(t)return t[1]??null;let n=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(e);if(n)return n[1]??null;return e.split(`
|
|
23
|
+
`)[0]?.trim()||null}async function St(e=Xe){let[t,n,r,o,i,s]=await Promise.all([Promise.all(V.map(async(a)=>[a.id,Xt(await e([...a.probeCommand]))])),e(["codex","plugin","list"],30000),e(["amp","plugins","list"],30000),e(["node","--version"]),e(["npm","--version"]),e(["bun","--version"])]);return{version:Ds,versions:Object.fromEntries(t),codexPluginListOutput:n,ampPluginListOutput:r,nodeVersion:Xt(o),npmVersion:Xt(i),bunVersion:Xt(s),platform:`${process.platform} ${process.arch}`}}function Sr(e,t){if(t==="dev")return!1;let n=e.split(".").map(Number),r=t.split(".").map(Number),[o=0,i=0,s=0]=n,[a=0,l=0,c=0]=r;if(o!==a)return o>a;if(i!==l)return i>l;return s>c}async function Qe(){let e=P(),t=new AbortController,n=setTimeout(()=>t.abort(),3000);try{let r=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:t.signal});if(!r.ok)return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${r.status}`};let o=await r.json(),i=Sr(o.version,e);return{currentVersion:e,latestVersion:o.version,updateAvailable:i}}catch(r){return{currentVersion:e,latestVersion:null,updateAvailable:!1,error:r instanceof Error?r.message:"Network error"}}finally{clearTimeout(n)}}import*as Os from"node:readline";var Ps=(e)=>`\x1B[${e}B`,Lp=(e)=>`\x1B[${e}A`;var Rs=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function vp(e){return new Promise((t)=>setTimeout(t,e))}function bp(e,t,n){if(!n)return t(e);if(n.aborted)return Promise.resolve();return new Promise((r,o)=>{let i=()=>n.removeEventListener("abort",s),s=()=>{i(),r()};n.addEventListener("abort",s,{once:!0}),t(e).then(()=>{i(),r()},(a)=>{i(),o(a)})})}function Dt(e,t){return e&&e>0?e:t}function Qt(e){return Math.max(0,Math.min(1,e))}function et(e){return Math.max(0,Math.min(255,Math.round(e)))}function Dr(e){return e<=0.0031308?12.92*e:1.055*e**0.4166666666666667-0.055}function wp(e,t,n){let r=n*Math.PI/180,o=t*Math.cos(r),i=t*Math.sin(r),s=(e+0.3963377774*o+0.2158037573*i)**3,a=(e-0.1055613458*o-0.0638541728*i)**3,l=(e-0.0894841775*o-1.291485548*i)**3;return{blue:et(Dr(Qt(-0.0041960863*s-0.7034186147*a+1.707614701*l))*255),green:et(Dr(Qt(-1.2684380046*s+2.6097574011*a-0.3413193965*l))*255),red:et(Dr(Qt(4.0767416621*s-3.3077115913*a+0.2309699292*l))*255)}}function Rr(e,t){let n=(t*e*180/Math.PI%360+360)%360;return wp(0.72,0.15,n)}function Ts(e,t=0.1){let n=Rr(t,e);return`\x1B[38;2;${n.red};${n.green};${n.blue}m`}function xp(e,t){return{blue:et(e.blue+(255-e.blue)*t),green:et(e.green+(255-e.green)*t),red:et(e.red+(255-e.red)*t)}}function Is(e,t,n){let r=Math.imul(e+2654435769,2246822507)^Math.imul(t+3266489909,668265263)^Math.imul(n+374761393,2654435761),o=r^r>>>15,i=Math.imul(o,739982445),s=i^i>>>12,a=Math.imul(s,695872825);return((a^a>>>15)>>>0)/4294967296}function Cp(e,t,n){let r=Math.floor(Is(e,t,n)*Rs.length);return Rs[r]??"░"}function As(e){let t=Qt(e);return t*t*t*(t*(t*6-15)+10)}function kp(e){if(e.length===0)return"";let t=[],n=!1,r="";for(let o of e){let i=`${o.red};${o.green};${o.blue}`;if(o.bold!==n)t.push(o.bold?"\x1B[1m":"\x1B[22m"),n=o.bold;if(i!==r)t.push(`\x1B[38;2;${i}m`),r=i;t.push(o.character)}return`${t.join("")}\x1B[22m\x1B[39m`}function Sp(e,t,n,r,o){return e.map((i,s)=>({...Rr(n,r+t+s/o),bold:!1,character:i}))}function Dp(e,t,n,r,o,i,s,a){let l=Math.max(1,r*0.75),c=Math.min(1,n/l),d=o*As(c),p=Math.max(0,(n-l)/Math.max(1,r-l)),m=(1-As(n/r))*a*2,u=0.35*Math.max(0,1-p*2),h=c>=1,f=Math.min(e.length,Math.ceil(d+2+1));return e.slice(0,f).map((L,v)=>{let w=Rr(i,s+t+v/a+m),y=v+Is(t,v,7919)*2-1;if(y>d+2)return{...w,bold:!1,character:" "};let C=d-y,H=0.8*Math.exp(-(C*C)/12.5),he=Math.min(0.9,H+u),Fn=!h&&y>d-4;return{...xp(w,he),bold:he>0.3,character:Fn?Cp(t,v,n):L}})}function Es(e){return`\x1B[?2026h${e.map((t,n)=>`\x1B8${n>0?Ps(n):""}${kp(t)}`).join("")}\x1B[?2026l`}async function Ar(e,t={}){if(!e)return;let n=t.output??process.stdout,r=t.sleep??vp,o=Dt(t.frequency,0.1),i=t.seed??0,s=Dt(t.speed,40),a=Dt(t.spread,3),l=Dt(t.frameRate,60),c=Math.max(1,Math.floor(Dt(t.duration,12))),d=e.split(`
|
|
24
|
+
`).map((f)=>Array.from(f)),p=Math.max(...d.map((f)=>f.length)),m=1000*c*d.filter((f)=>f.length>0).length/s,u=p>0?Math.max(1,Math.ceil(m/(1000/l))):0,h=u>0?m/u:0;n.write(`\x1B[?25l${d.length>1?`${`
|
|
25
|
+
`.repeat(d.length-1)}${Lp(d.length-1)}`:""}\x1B7`);try{for(let f=1;f<=u;f+=1){if(t.signal?.aborted)break;n.write(Es(d.map((L,v)=>Dp(L,v,f,u,p,o,i,a)))),await bp(h,r,t.signal)}}finally{if(n.write(Es(d.map((f,L)=>Sp(f,L,o,i,a)))),n.write("\x1B8"),d.length>1)n.write(Ps(d.length-1));n.write(`
|
|
26
|
+
\x1B[0m\x1B[?25h`)}}var _s=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
|
|
27
|
+
`);function Rp(e){return Boolean(e.isTTY)}async function Rt(e={}){let t=e.output??process.stdout;if(!Rp(t))return;let n=e.input??process.stdin,r={duration:e.duration,frequency:e.frequency,output:t,seed:e.seed??Math.random()*8192,sleep:e.sleep,speed:e.speed,spread:e.spread};if(!n.isTTY||typeof n.setRawMode!=="function"){await Ar(_s,r);return}let o=new AbortController,i=n.readableFlowing===!0,s=n.isRaw===!0,a=!1,l=(c,d)=>{if(d.ctrl&&d.name==="c")a=!0;if(a||d.name==="return"||d.name==="enter")o.abort()};Os.emitKeypressEvents(n),n.on("keypress",l),n.setRawMode(!0),n.resume();try{await Ar(_s,{...r,signal:o.signal})}finally{if(n.off("keypress",l),n.setRawMode(s),!i)n.pause()}if(!a)return;if(e.onInterrupt){e.onInterrupt();return}process.kill(process.pid,"SIGINT")}var $s="\r\x1B[2K",Ap="\x1B[?25l",Ep="\x1B[39m",Pp="\x1B[?25h",Tp=100,Ip=0.55,_p=80,Ns=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Op(e){return new Promise((t)=>setTimeout(t,e))}async function en(e,t={}){let n=t.output??process.stdout;if(!n.isTTY)return e;let r=t.sleep??Op,o=!1,i=e.then((a)=>(o=!0,a),(a)=>{throw o=!0,a});if(await Promise.race([i.then(()=>!0),r(Tp).then(()=>!1)]))return i;n.write(Ap);try{for(let a=0;!o;a+=1)n.write(`${$s}${Ts(a*Ip)}${Ns[a%Ns.length]}${Ep} ${t.loadingMessage??"Loading…"}`),await Promise.race([i,r(_p)]);return await i}finally{n.write(`${$s}${Pp}`)}}async function At(e,t,n,r={}){let o=t();if(e)await n();if(e&&o.ready)await en(o.ready,r);return o.finish()}import{homedir as tf}from"node:os";import{stripVTControlCharacters as $p}from"node:util";var tn="amp plugins list",Np=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Fs(e){if(!e.ampPluginListOutput)return{platform:"amp",status:"n/a"};let t=$p(e.ampPluginListOutput).split(`
|
|
28
|
+
`).map((n)=>Np.exec(n)?.[1]).find((n)=>n!==void 0);if(!t)return{platform:"amp",status:"n/a"};if(t!=="active")return{platform:"amp",status:"disabled",method:tn,configPath:tn,errors:[`Amp personal plugin cc-safety-net is ${t}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:tn,configPath:tn}}import{existsSync as Fp,readFileSync as Hp}from"node:fs";var Mp=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function jp(e){if(!e||typeof e!=="object"||Array.isArray(e))return[];return Object.values(e).flatMap((t)=>{if(!t||typeof t!=="object"||Array.isArray(t))return[];let n=t,r=n.PreToolUse;if(!Array.isArray(r))return[];return r.flatMap((o)=>{if(!o||typeof o!=="object"||Array.isArray(o))return[];let i=o.hooks;if(!Array.isArray(i))return[];return i.flatMap((s)=>{if(!s||typeof s!=="object"||Array.isArray(s))return[];let a=s.command;if(typeof a!=="string"||!Mp.test(a))return[];return[{command:a,enabled:n.enabled!==!1}]})})})}function Hs(e){let t=Ct(e.homeDir);if(!Fp(t))return{platform:"antigravity-cli",status:"n/a",configPath:t};let n;try{n=jp(JSON.parse(Hp(t,"utf-8")))}catch(r){return{platform:"antigravity-cli",status:"n/a",configPath:t,errors:[`Failed to parse Antigravity hooks config ${t}: ${r instanceof Error?r.message:String(r)}`]}}if(n.some((r)=>r.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:t};if(n.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:t};return{platform:"antigravity-cli",status:"n/a",configPath:t}}import{join as Ms}from"node:path";import{existsSync as Up,lstatSync as Gp,readFileSync as Bp}from"node:fs";function re(e,t=(n)=>n){if(!Up(e))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(t(Bp(e,"utf-8")))}}catch{return{kind:"unreadable"}}}function E(e){try{return Gp(e)}catch{return}}function nn(e,t){let n=E(t);if(!n)return{platform:e,status:"n/a",configPath:t};if(!n.isSymbolicLink()&&n.isDirectory())return;return{platform:e,status:"n/a",configPath:t,errors:[`${t} is a symlink or not a directory; move or remove it before installing`]}}function b(e,t){return typeof e==="object"&&e!==null?e[t]:void 0}var Er="cc-safety-net@cc-marketplace";function js(e){return Ms(e,".claude","plugins","installed_plugins.json")}function Us(e,t){let n=b(b(e,"plugins"),t);return Array.isArray(n)&&n.length>0}function rn(e,t){let n=re(js(e));return n.kind==="ok"&&Us(n.value,t)}function Pr(e){let t=js(e),n=re(t);if(n.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(n.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Us(n.value,Er))return{platform:"claude-code",status:"n/a"};let r=Ms(e,".claude","settings.json"),o=re(r);if(o.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(o.kind==="ok"&&b(b(o.value,"enabledPlugins"),Er)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:r,errors:[`${Er} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:t}}function Gs(e){return Pr(e.homeDir)}function Bs(e){if(!e.codexPluginListOutput)return{platform:"codex",status:"n/a"};let t=e.codexPluginListOutput.split(`
|
|
29
|
+
`).find((n)=>n.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!t)return{platform:"codex",status:"n/a"};if(!t.includes("installed,"))return{platform:"codex",status:"n/a"};if(!t.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as an,readdirSync as qp,readFileSync as Vp}from"node:fs";import{join as F}from"node:path";var oe="cc-safety-net@cc-marketplace",on=["cc-marketplace","cc-safety-net"],qs=["_direct","copilot-safety-net"],Vs=["cc-marketplace","safety-net"],zs="safety-net@cc-marketplace";function sn(e,t){let n=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${n}([^a-z0-9-]|$)`,"m").test(e??"")}function Ks(e){return sn(e,"cc-safety-net@cc-marketplace")}function Ws(e){return sn(e,"cc-marketplace")}function Js(e){return sn(e,"copilot-safety-net")}function Ys(e){return sn(e,"safety-net@cc-marketplace")}function q(e){let t="",n=0,r=!1,o=!1,i=-1;while(n<e.length){let s=e[n],a=e[n+1];if(o){t+=s,o=!1,n++;continue}if(s==='"'&&!r){r=!0,i=-1,t+=s,n++;continue}if(s==='"'&&r){r=!1,t+=s,n++;continue}if(s==="\\"&&r){o=!0,t+=s,n++;continue}if(r){t+=s,n++;continue}if(s==="/"&&a==="/"){while(n<e.length&&e[n]!==`
|
|
30
|
+
`)n++;continue}if(s==="/"&&a==="*"){n+=2;while(n<e.length-1){if(e[n]==="*"&&e[n+1]==="/"){n+=2;break}n++}continue}if(s===","){i=t.length,t+=s,n++;continue}if(s==="}"||s==="]"){if(i!==-1){let l=t.slice(i+1);if(/^\s*$/.test(l))t=t.slice(0,i)+l}i=-1,t+=s,n++;continue}if(!/\s/.test(s))i=-1;t+=s,n++}return t}function Tr(e){if(!e?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(e)}function Xs(e,t){if(!e)return null;let n=e.match(/(\d+)\.(\d+)\.(\d+)/);if(!n)return null;let r=[Number(n[1]),Number(n[2]),Number(n[3])];for(let o=0;o<t.length;o++){let i=r[o]??0,s=t[o]??0;if(i!==s)return i>s}return!0}function zp(e){return Xs(e,[0,0,422])}function Kp(e){return Xs(e,[1,0,8])}function Et(e){return process.env.COPILOT_HOME||F(e,".copilot")}function Ir(e){return(e.hooks?.preToolUse??[]).some((n)=>{if(n.type!=="command")return!1;return Tr(n.command)||Tr(n.bash)||Tr(n.powershell)})}function _r(e,t){try{return JSON.parse(q(Vp(e,"utf-8")))}catch(n){t?.push(`Failed to parse ${e}: ${n instanceof Error?n.message:String(n)}`);return}}function Qs(e,t){try{return qp(e).filter((n)=>n.endsWith(".json")).sort((n,r)=>n.localeCompare(r))}catch(n){return t?.push(`Failed to read ${e}: ${n instanceof Error?n.message:String(n)}`),[]}}function Wp(e,t){if(!an(e))return[];let n=[];for(let r of Qs(e,t)){let o=F(e,r),i=_r(o,t);if(i&&Ir(i))n.push(o)}return n}function tt(e,t){if(!an(e))return;let n=_r(e,t);if(!n)return;return{path:e,config:n}}function Zs(e,t,n,r){if(t){e.push(`GitHub Copilot CLI ${t} does not support ${n}; requires ${r}+`);return}e.push(`GitHub Copilot CLI version unavailable; skipping ${n} because it requires ${r}+`)}function Jp(e){for(let t of e){if(t?.config.disableAllHooks===!0)return t.path;if(t?.config.disableAllHooks===!1)return}return}function Yp(e,t,n,r){let o=Et(e),i=F(t,".github","hooks"),s=F(o,"hooks"),a=F(t,".github","copilot"),l=F(t,".claude"),c=Kp(n),d=c===!0?r:void 0,p=[tt(F(a,"settings.local.json"),d),tt(F(a,"settings.json"),d),tt(F(l,"settings.local.json"),d),tt(F(l,"settings.json"),d)],m=[tt(F(o,"settings.json"),d),tt(F(o,"config.json"),d)];if(c!==!1){let C=Jp([...p,...m]);if(C){if(c===null)r.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${C} as active`);return{activeConfigPaths:[],disabledBy:C}}}let u=Wp(i,r),h=zp(n),f=h===!0?r:void 0,L=an(s)?Qs(s,f):[],v=[];for(let C of L){let H=F(s,C),he=_r(H,f);if(he&&Ir(he))v.push(H)}if(h!==!0&&v.length>0)Zs(r,n,`user hook files in ${s}`,"0.0.422"),v.length=0;let w=[];for(let C of[...p,...m]){if(!C)continue;if(!Ir(C.config))continue;if(c===!0){w.push(C);continue}Zs(r,n,"inline hook definitions in Copilot config files","1.0.8");break}let y=(C)=>C.filter((H)=>!!H&&w.includes(H)).map((H)=>H.path);return{activeConfigPaths:[...y(p),...u,...y(m),...v]}}function ea(e){let t=[],n=Yp(e.homeDir,e.cwd,e.copilotCliVersion,t);if(n.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:n.disabledBy,configPaths:[n.disabledBy],errors:t.length>0?t:void 0};let r=Et(e.homeDir),o=F(r,"installed-plugins",...on),i=an(o),s=F(r,"settings.json"),a=re(s,q);if(i&&a.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(i&&a.kind==="ok"&&b(b(a.value,"enabledPlugins"),oe)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:s,errors:[`${oe} is installed but not enabled in Copilot CLI`]};if(i||n.activeConfigPaths.length>0){let l=i,c=n.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:l?"plugin config":"hook config",configPath:c??(l?o:void 0),configPaths:n.activeConfigPaths.length>0?n.activeConfigPaths:void 0,errors:t.length>0?t:void 0}}return{platform:"copilot-cli",status:"n/a",errors:t.length>0?t:void 0}}import{existsSync as s2,readFileSync as a2}from"node:fs";import{existsSync as ta,mkdirSync as Qp,readFileSync as e2}from"node:fs";import{dirname as t2,join as n2}from"node:path";import{renameSync as Zp,writeFileSync as Xp}from"node:fs";function _(e,t){let n=`${e}.${process.pid}.tmp`;Xp(n,t),Zp(n,e)}var Pt="npx -y cc-safety-net hook --cursor",na=30;function cn(e){return n2(e,".cursor","hooks.json")}function Te(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function Or(){return{command:Pt,timeout:na,failClosed:!0}}function ln(e){return Te(e)&&e.command===Pt}function r2(e){return Object.keys(e).length===3&&e.command===Pt&&e.timeout===na&&e.failClosed===!0}function o2(e){try{return JSON.parse(e2(e,"utf-8"))}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${e}: ${t.message}`);throw t}}function ra(e){let t=o2(e);if(!Te(t))throw Error(`Cursor hooks config ${e} must be a JSON object`);if(t.version!==1)throw Error(`Cursor hooks config ${e} must set "version": 1`);if(t.hooks!==void 0&&!Te(t.hooks))throw Error(`Cursor hooks config ${e} "hooks" must be an object`);let n=Te(t.hooks)?t.hooks.preToolUse:void 0;if(n!==void 0&&!Array.isArray(n))throw Error(`Cursor hooks config ${e} "hooks.preToolUse" must be an array`);return t}function oa(e){let t=Te(e.hooks)?e.hooks.preToolUse:void 0;return Array.isArray(t)?t:[]}function i2(e){if(!e.some(ln))return[...e,Or()];return e.reduce((t,n)=>{if(!ln(n))return t.result.push(n),t;if(!t.inserted)t.result.push(Or()),t.inserted=!0;return t},{result:[],inserted:!1}).result}function ia(e,t,n){let r=Te(t.hooks)?t.hooks:{},o={...t,hooks:{...r,preToolUse:n}};_(e,`${JSON.stringify(o,null,2)}
|
|
31
|
+
`)}function sa(e){let t=cn(e);if(!ta(t))return Qp(t2(t),{recursive:!0}),_(t,`${JSON.stringify({version:1,hooks:{preToolUse:[Or()]}},null,2)}
|
|
32
|
+
`),{path:t,alreadyInstalled:!1};let n=ra(t),r=oa(n),o=r.filter(ln);if(Te(n.hooks)&&Array.isArray(n.hooks.preToolUse)&&o.length===1&&o[0]!==void 0&&r2(o[0]))return{path:t,alreadyInstalled:!0};return ia(t,n,i2(r)),{path:t,alreadyInstalled:!1}}function aa(e){let t=cn(e);if(!ta(t))return{path:t,alreadyInstalled:!1};let n=ra(t),r=oa(n),o=r.filter((i)=>!ln(i));if(o.length===r.length)return{path:t,alreadyInstalled:!1};return ia(t,n,o),{path:t,alreadyInstalled:!0}}function l2(e){if(!e||typeof e!=="object"||Array.isArray(e))return[];let t=e.hooks;if(!t||typeof t!=="object"||Array.isArray(t))return[];let n=t.preToolUse;if(!Array.isArray(n))return[];return n.filter((r)=>!!r&&typeof r==="object"&&!Array.isArray(r)&&r.command===Pt)}function c2(e){let t=[];if(e.length>1)t.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let n=e[0];if(n&&n.failClosed!==!0)t.push('Managed hook is missing "failClosed": true; reinstall to repair');if(n&&n.timeout!==30)t.push('Managed hook "timeout" is not 30; reinstall to repair');return t}function la(e){let t=cn(e.homeDir);if(!s2(t))return{platform:"cursor",status:"n/a",configPath:t};let n;try{n=JSON.parse(a2(t,"utf-8"))}catch(i){return{platform:"cursor",status:"n/a",configPath:t,errors:[`Failed to parse Cursor hooks config ${t}: ${i instanceof Error?i.message:String(i)}`]}}let r=l2(n);if(r.length===0)return{platform:"cursor",status:"n/a",configPath:t};let o=c2(r);return{platform:"cursor",status:"configured",method:"hook config",configPath:t,errors:o.length>0?o:void 0}}import{existsSync as d2}from"node:fs";import{join as $r}from"node:path";var Nr="gemini-safety-net";function Fr(e){let t=$r(e,".gemini","extensions"),n=$r(t,Nr);if(!d2(n))return{platform:"gemini-cli",status:"n/a"};let r=$r(t,"extension-enablement.json"),o=re(r);if(o.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let i=o.kind==="ok"?b(b(o.value,Nr),"overrides"):void 0;if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:r,errors:[`${Nr} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:n}}function ca(e){return Fr(e.homeDir)}import{readFileSync as La}from"node:fs";import{join as va}from"node:path";var z="cc-safety-net",da="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent";function ua(e){return`# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent
|
|
33
|
+
# version: ${e}
|
|
34
|
+
`}function u2(e){return`${ua(e)}name: cc-safety-net
|
|
35
|
+
version: "${e}"
|
|
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 p2(e){return`${ua(e)}"""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
|
|
@@ -175,84 +175,84 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
175
175
|
|
|
176
176
|
def register(ctx):
|
|
177
177
|
ctx.register_hook("pre_tool_call", _pre_tool_call)
|
|
178
|
-
`}function
|
|
179
|
-
`)}function
|
|
180
|
-
`),
|
|
181
|
-
${
|
|
182
|
-
${
|
|
183
|
-
`,t)+1;return/^[ \t]*/.exec(
|
|
184
|
-
`)
|
|
185
|
-
`,
|
|
186
|
-
`,t+2);return
|
|
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
|
|
189
|
-
`)}function
|
|
190
|
-
`,()=>t())})}async function
|
|
191
|
-
`))}function
|
|
192
|
-
`))}function
|
|
193
|
-
`)}var
|
|
194
|
-
`)}function
|
|
195
|
-
`),a
|
|
196
|
-
`).length};return new Promise((
|
|
197
|
-
`);return}
|
|
198
|
-
`)})}),
|
|
178
|
+
`}function Tt(e){return[{name:"__init__.py",content:p2(e)},{name:"plugin.yaml",content:u2(e)}]}import{mkdirSync as f2,readdirSync as m2,readFileSync as g2,rmSync as Hr}from"node:fs";import{join as Ie}from"node:path";var h2="__pycache__";function Mr(e){let t=process.env.HERMES_HOME?.trim();return t?t:Ie(e,".hermes")}function jr(e){return Ie(Mr(e),"plugins",z)}function Ur(e){return e.startsWith(da)}function Gr(e,t){let n=jr(e),r=E(n);if(r&&(r.isSymbolicLink()||!r.isDirectory()))throw Error(`Refusing to ${t} ${n}: not a regular directory. Move or remove it and rerun ${t==="install"?"install":"uninstall"} --hermes-agent.`);return n}function pa(e,t){let n=E(e);if(!n)return;if(n.isSymbolicLink()||!n.isFile())throw Error(`Refusing to ${t} ${e}: not a regular file. Move or remove it.`);let r=g2(e,"utf-8");if(!Ur(r))throw Error(`Refusing to ${t} unmanaged file at ${e}. Move or remove it.`);return r}function fa(e){let t=Gr(e,"install"),n=Tt(P());if(n.map((o)=>pa(Ie(t,o.name),"overwrite")).every((o,i)=>o===n[i]?.content))return{path:t,alreadyInstalled:!0};return f2(t,{recursive:!0}),n.forEach((o)=>{_(Ie(t,o.name),o.content)}),{path:t,alreadyInstalled:!1}}function Br(e){let t=Gr(e,"remove");if(!E(t))return[];return Tt(P()).filter((n)=>pa(Ie(t,n.name),"remove")!==void 0)}function ma(e){let t=Gr(e,"remove");if(!E(t))return{path:t,alreadyInstalled:!1};let n=Br(e);if(n.forEach((r)=>{Hr(Ie(t,r.name))}),Hr(Ie(t,h2),{recursive:!0,force:!0}),m2(t).length===0)Hr(t,{recursive:!0});return{path:t,alreadyInstalled:n.length>0}}var dn="hermes-agent",ga=/^([^\s#][^:]*):/,y2=/^\s+([A-Za-z_][\w-]*):/,ha=/^\s+-\s*(.*)$/;function L2(e){return e.trim().replace(/^(["'])(.*)\1$/,"$2")}function v2(e){let t=e.split(/\r?\n/),n=t.findIndex((i)=>ga.exec(i)?.[1]?.trim()==="plugins");if(n===-1)return[];let r=t.slice(n+1),o=r.findIndex((i)=>ga.test(i));return o===-1?r:r.slice(0,o)}function ya(e,t){let n=v2(e),r=n.findIndex((s)=>y2.exec(s)?.[1]===t);if(r===-1)return[];let o=n.slice(r+1),i=o.findIndex((s)=>!ha.test(s));return(i===-1?o:o.slice(0,i)).map((s)=>L2(ha.exec(s)?.[1]??""))}function b2(e){try{return La(va(Mr(e),"config.yaml"),"utf-8")}catch{return}}function qr(e){let t=b2(e)??"";return ya(t,"enabled").includes(z)&&!ya(t,"disabled").includes(z)}function ba(e){return/^# version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function w2(e,t){let n=E(e);if(!n)return{error:`${t.name} is missing from ${e}; run install --hermes-agent`};if(n.isSymbolicLink()||!n.isFile())return{error:`${e} is a symlink or not a regular file; move or remove it`};try{let r=La(e,"utf-8");if(!Ur(r))return{error:`Unmanaged ${t.name} occupies ${e}; move or remove it`};if(ba(r)===P()&&r!==t.content)return{error:`Modified ${t.name} occupies ${e}; run install --hermes-agent to restore it`};return{content:r}}catch(r){return{error:`Failed to read ${e}: ${r instanceof Error?r.message:String(r)}`}}}function wa(e){let t=jr(e.homeDir),n=nn(dn,t);if(n)return n;let r=Tt(P()).map((a)=>w2(va(t,a.name),a)),o=r.flatMap((a)=>("error"in a)?[a.error]:[]);if(o.length>0)return{platform:dn,status:"n/a",configPath:t,errors:o};let i=r.some((a)=>("content"in a)&&ba(a.content)!==P()),s=i?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!qr(e.homeDir))return{platform:dn,status:"disabled",method:"plugin directory",configPath:t,errors:[`${z} is not enabled in Hermes; run \`hermes plugins enable ${z}\``,...s]};return{platform:dn,status:"configured",method:"plugin directory",configPath:t,errors:i?s:void 0}}import{existsSync as x2,readFileSync as C2}from"node:fs";import{join as xa}from"node:path";var k2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function S2(e){return xa(process.env.KIMI_CODE_HOME||xa(e,".kimi-code"),"config.toml")}function It(e){let t=S2(e.homeDir);if(!x2(t))return{platform:"kimi-code",status:"n/a",configPath:t};try{if(!k2.test(C2(t,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:t}}catch(n){return{platform:"kimi-code",status:"n/a",configPath:t,errors:[`Failed to read ${t}: ${n instanceof Error?n.message:String(n)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:t}}import{readFileSync as Ia}from"node:fs";import{join as Ot}from"node:path";var A="cc-safety-net",K="index.js",nt="openclaw.plugin.json",rt="package.json";var un="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as A2,lstatSync as E2,readdirSync as P2,readFileSync as T2}from"node:fs";import{dirname as Sa,join as ve}from"node:path";import{fileURLToPath as I2}from"node:url";import{spawn as D2}from"node:child_process";function R2(e){return e.join(" ")}function Vr(e,t,n){return[`Failed to run ${R2(e)}${t===null?"":` (exit ${t})`}.`,n.trim()].filter(Boolean).join(`
|
|
179
|
+
`)}function zr(e){let t={stdout:"",stderr:""};return e.stdout.setEncoding("utf-8"),e.stderr.setEncoding("utf-8"),e.stdout.on("data",(n)=>{t.stdout+=n}),e.stderr.on("data",(n)=>{t.stderr+=n}),t}function ie(e,t){return new Promise((n,r)=>{let o=Pe([...e],process.env),i=D2(o.cmd,o.args,{stdio:["ignore","pipe","pipe"]}),s=zr(i),a=()=>[s.stdout,s.stderr].filter(Boolean).join(`
|
|
180
|
+
`),l=t?.timeoutMs??120000,c=setTimeout(()=>{i.kill(),r(Error(Vr(e,null,`Timed out after ${l}ms.
|
|
181
|
+
${a()}`.trim())))},l);i.on("error",(d)=>{clearTimeout(c),r(Error(Vr(e,null,`${d.message}
|
|
182
|
+
${a()}`.trim())))}),i.on("close",(d)=>{if(clearTimeout(c),d!==0){r(Error(Vr(e,d,a())));return}n(t?.stdoutOnly?s.stdout:a())})})}async function Kr(e){for(let t of e)await ie(t)}async function Ca(e){for(let t of e)try{await ie(t)}catch(n){console.warn(n instanceof Error?n.message:String(n))}}var ka=ve("openclaw",A),_2=[K,nt,rt];function Wr(e,t){if(e==="~")return t;if(e.startsWith("~/")||e.startsWith("~\\"))return ve(t,e.slice(2));return e}function Da(e){let t=process.env.OPENCLAW_STATE_DIR?.trim();if(t)return Wr(t,e);let n=process.env.OPENCLAW_CONFIG_PATH?.trim();return n?Sa(Wr(n,e)):ve(e,".openclaw")}function Ra(e){let t=process.env.OPENCLAW_CONFIG_PATH?.trim();return t?Wr(t,e):ve(Da(e),"openclaw.json")}function Jr(e){return ve(Da(e),"extensions",A)}function O2(e){let t=P2(e);if(t.length===0)return!0;if(t.some((o)=>!_2.includes(o)))return!1;let n=ve(e,K),r=E(n);return r!==void 0&&!r.isSymbolicLink()&&r.isFile()&&T2(n,"utf-8").startsWith(un)}function Yr(e){let t=Jr(e),n=E(t);if(!n)return;if(!n.isSymbolicLink()&&n.isDirectory()&&O2(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 Aa(){let e=Sa(I2(import.meta.url));return[ve(e,"..",ka),ve(e,"..","..","..","dist",ka)]}function Zr(e=Aa()){return e.find((t)=>A2(t)&&E2(t).isDirectory())}function $2(e=Aa()){let t=Zr(e);if(!t)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return t}function Ea(e=$2()){return[["openclaw","plugins","install",e,"--force"],["openclaw","plugins","enable",A]]}function N2(e){let t=(()=>{try{return JSON.parse(e)}catch{return}})(),n=b(b(t,"plugin"),"status");return typeof n==="string"?n:void 0}async function Pa(){let e=N2(await ie(["openclaw","plugins","inspect",A,"--runtime","--json"],{stdoutOnly:!0}));if(e==="loaded")return;throw Error(`${e===void 0?`The ${A} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${A} plugin with status "${e}".`} Run \`openclaw plugins inspect ${A} --runtime\` for details.`)}var pn="openclaw",_t=`run \`openclaw plugins enable ${A}\``;function ot(e,t){let n=Ot(e,t),r=E(n);if(!r)return{error:`${t} is missing from ${n}; run install --openclaw`};if(r.isSymbolicLink()||!r.isFile())return{error:`${n} is a symlink or not a regular file; move or remove it`};try{return{content:Ia(n,"utf-8")}}catch(o){return{error:`Failed to read ${n}: ${o instanceof Error?o.message:String(o)}`}}}function _a(e){try{return JSON.parse(q(e))}catch{return}}function F2(e){let t=ot(e,nt);if("error"in t)return t.error;if(b(_a(t.content),"id")===A)return;return`${Ot(e,nt)} is not a valid ${A} manifest; run install --openclaw`}function H2(e){let t=ot(e,rt);if("error"in t)return t.error;let n=b(b(_a(t.content),"openclaw"),"extensions");if(Array.isArray(n)&&n.includes(`./${K}`))return;return`${Ot(e,rt)} does not point OpenClaw at ${K}; run install --openclaw`}function Ta(e){return Array.isArray(e)?e.filter((t)=>typeof t==="string"):[]}function M2(e){let t=Ra(e);if(!E(t))return`${A} is not enabled; ${_t}`;let n=(()=>{try{return JSON.parse(q(Ia(t,"utf-8")))}catch{return}})();if(n===void 0)return`Failed to read ${t}; fix it, then ${_t}`;let r=b(n,"plugins");if(b(r,"enabled")===!1)return`plugins.enabled is false in ${t}; no OpenClaw plugin loads`;let o=b(b(b(r,"entries"),A),"enabled");if(Ta(b(r,"deny")).includes(A)||o===!1)return`${A} is disabled in ${t}; ${_t}`;let i=Ta(b(r,"allow"));if(i.length>0&&!i.includes(A))return`plugins.allow in ${t} does not list ${A}; add it, then ${_t}`;if(i.includes(A)||o===!0)return;return`${A} is not enabled; ${_t}`}function Oa(e){return/^\/\/ version:\s*(.+)$/m.exec(e)?.[1]?.trim()}function j2(e,t,n){if(n===void 0)return[];let r=ot(n,K);if("error"in r||Oa(r.content)!==t)return[];return[K,nt,rt].flatMap((o)=>{let i=ot(e,o),s=ot(n,o);if("error"in i||"error"in s||i.content===s.content)return[];return[`Modified ${o} occupies ${Ot(e,o)}; run install --openclaw to restore it`]})}function $a(e){let t=Jr(e.homeDir),n=nn(pn,t);if(n)return n;let r=ot(t,K),i=["error"in r?r.error:r.content.startsWith(un)?void 0:`Unmanaged ${K} occupies ${Ot(t,K)}; move or remove it`,F2(t),H2(t)].filter((d)=>d!==void 0),s="content"in r?Oa(r.content):void 0,a=i.length>0?i:j2(t,s,Zr());if(a.length>0)return{platform:pn,status:"n/a",configPath:t,errors:a};let l=s===P()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],c=M2(e.homeDir);if(c)return{platform:pn,status:"disabled",method:"plugin directory",configPath:t,errors:[c,...l]};return{platform:pn,status:"configured",method:"plugin directory",configPath:t,errors:l.length>0?l:void 0}}import{existsSync as Z2,readFileSync as X2}from"node:fs";import{join as Q2}from"node:path";import{existsSync as Xr,readFileSync as ja,rmSync as G2}from"node:fs";import{join as me}from"node:path";import{pathToFileURL as B2}from"node:url";function Na(e){return e!==void 0&&/\s/.test(e)}function U2(e,t,n){let r=t+1,o=!1;while(r<e.length){let i=e[r];if(o){o=!1,r++;continue}if(i==="\\"){o=!0,r++;continue}if(i==='"')return r+1;r++}throw Error(n)}function fn(e,t,n){let r=e[t],o=r==="["?"]":"}",i=0,s=t;while(s<e.length){let a=n.skipComment?.(e,s)??s;if(a!==s){s=a;continue}if(e[s]==='"'){s=U2(e,s,n.stringError);continue}if(e[s]===r)i++;if(e[s]===o){if(i--,i===0)return s}s++}throw Error(n.bracketError)}function Fa(e,t){let n=e.lastIndexOf(`
|
|
183
|
+
`,t)+1;return/^[ \t]*/.exec(e.slice(n))?.[0]??""}function mn(e,t){let{start:n,end:r,end:o}=t;while(Na(e[o]))o++;if(e[o]===","){if(r=o+1,e[r]===`
|
|
184
|
+
`)r++;return`${e.slice(0,n)}${e.slice(r)}`}o=t.start-1;while(Na(e[o]))o--;if(e[o]===","){n=o;let i=e.lastIndexOf(`
|
|
185
|
+
`,n-1);if(i!==-1&&/^\s*$/.test(e.slice(i+1,n)))n=i}return`${e.slice(0,n)}${e.slice(r)}`}var gn="cc-safety-net",Ua=`${gn}@latest`,Ga=["opencode.json","opencode.jsonc"],Ha="CCSafetyNetPlugin";function hn(e){return me(process.env.XDG_CONFIG_HOME||me(e,".config"),"opencode")}function q2(e){return me(hn(e),Ga[0])}function V2(e){return Ga.map((t)=>me(hn(e),t))}function Ba(e){return me(process.env.XDG_CACHE_HOME||me(e,".cache"),"opencode","packages",Ua)}function Qr(e){G2(Ba(e),{recursive:!0,force:!0})}async function qa(e){let t=me(Ba(e),"node_modules",gn),n=me(t,"package.json");if(!Xr(n))throw Error(`The OpenCode plugin cache at ${t} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${Ua}\` for details.`);let r=b(JSON.parse(ja(n,"utf-8")),"main");if(typeof r!=="string")throw Error(`The cached OpenCode plugin at ${t} declares no "main" entry.`);let o=me(t,r);if(typeof(await import(B2(o).href))[Ha]==="function")return;throw Error(`The cached OpenCode plugin at ${o} does not export a callable ${Ha}, so OpenCode would load nothing and fail open.`)}function yn(e,t){if(e[t]==="/"&&e[t+1]==="/"){let n=e.indexOf(`
|
|
186
|
+
`,t+2);return n===-1?e.length:n+1}if(e[t]==="/"&&e[t+1]==="*"){let n=e.indexOf("*/",t+2);return n===-1?e.length:n+2}return t}function Ma(e,t){let n=t;while(n<e.length){if(/\s/.test(e[n]??"")){n++;continue}let r=yn(e,n);if(r===n)return n;n=r}return n}function Va(e,t){let n=t+1,r=!1;while(n<e.length){if(r){r=!1,n++;continue}if(e[n]==="\\"){r=!0,n++;continue}if(e[n]==='"')return n+1;n++}throw Error("Unterminated string in OpenCode config")}function za(e,t,n){return JSON.parse(e.slice(t,n))}function z2(e,t){return fn(e,t,{skipComment:yn,stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"})}function K2(e){let t=0,n=0;while(n<e.length){let r=yn(e,n);if(r!==n){n=r;continue}if(e[n]==='"'){let o=Va(e,n);if(t===1&&za(e,n,o)==="plugin"){let i=Ma(e,o),s=Ma(e,i+1);if(e[i]===":"&&e[s]==="[")return{start:s,end:z2(e,s)}}n=o;continue}if(e[n]==="{"||e[n]==="[")t++;if(e[n]==="}"||e[n]==="]")t--;n++}return}function W2(e,t){let n=[],r=t.start+1;while(r<t.end){let o=yn(e,r);if(o!==r){r=o;continue}if(e[r]==='"'){let i=Va(e,r),s=za(e,r,i);if(typeof s==="string"&&s.includes(gn))n.push({start:r,end:i});r=i;continue}r++}return n}function Ka(e,t){try{return JSON.parse(q(e))}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${t}: ${n.message}`);throw n}}function J2(e){if(!e||typeof e!=="object"||Array.isArray(e))return!1;let t=e.plugin;if(!Array.isArray(t))return!1;return t.some((n)=>typeof n==="string"&&n.includes(gn))}function Y2(e,t){let n=K2(e);if(!n)throw Error(`Failed to locate OpenCode plugin array in ${t}`);let r=[...W2(e,n)].reverse().reduce(mn,e);return Ka(r,t),r}function Wa(e){Qr(e);let t=V2(e),n=t.find((o)=>Xr(o)),r=[];for(let o of t){if(!Xr(o))continue;try{let i=ja(o,"utf-8");if(!J2(Ka(i,o)))continue;return _(o,Y2(i,o)),{path:o,alreadyInstalled:!0}}catch(i){r.push(i instanceof Error?i.message:String(i))}}if(r.length>0)throw Error(r.join(`
|
|
187
|
+
`));return{path:n??q2(e),alreadyInstalled:!1}}function Ja(e){let t=[],n=hn(e.homeDir),r=["opencode.json","opencode.jsonc"];for(let o of r){let i=Q2(n,o);if(Z2(i))try{let s=X2(i,"utf-8"),a=q(s);if((JSON.parse(a).plugin??[]).some((p)=>p.includes("cc-safety-net")))return{platform:"opencode",status:"configured",method:"plugin array",configPath:i,errors:t.length>0?t:void 0}}catch(s){t.push(`Failed to parse ${o}: ${s instanceof Error?s.message:String(s)}`)}}return{platform:"opencode",status:"n/a",errors:t.length>0?t:void 0}}import{join as ef}from"node:path";function eo(e){return ef(e,".pi","agent","settings.json")}function to(e){if(typeof e!=="string")return!1;return e==="npm:cc-safety-net"||e.startsWith("npm:cc-safety-net@")}function Ya(e){let t=eo(e.homeDir),n=re(t);if(n.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(n.kind==="missing")return{platform:"pi",status:"n/a"};let r=b(n.value,"packages");if(!Array.isArray(r))return{platform:"pi",status:"n/a"};let o=r.find((a)=>to(typeof a==="string"?a:b(a,"source")));if(o===void 0)return{platform:"pi",status:"n/a"};let i=b(o,"extensions");if(Array.isArray(i)&&i.some((a)=>typeof a==="string"&&a.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:t,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:t}}var nf={amp:Fs,"antigravity-cli":Hs,"claude-code":Gs,codex:Bs,"copilot-cli":ea,cursor:la,"gemini-cli":ca,"hermes-agent":wa,"kimi-code":It,openclaw:$a,opencode:Ja,pi:Ya};function it(e,t){let n={...t,cwd:e,homeDir:t?.homeDir??tf()};return Kt.map((r)=>rf(nf[r](n)))}function rf(e){if(e.status==="not-inspected")return{platform:e.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:e.platform,detected:e.status!=="n/a",configured:e.status==="configured",inspectionStatus:e.status!=="n/a"?"verified":e.errors&&e.errors.length>0?"failed":"not-applicable",method:e.method,configPath:e.configPath,configPaths:e.configPaths,errors:e.errors}}import{tmpdir as of}from"node:os";import{join as sf}from"node:path";var af=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}]),lf=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([])})})}),cf={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 Za(){let e=sf(of(),"cc-safety-net-self-test"),t=af.map((n)=>{let r=Vt(Ke("self-test",{command:n.command},{kind:"command",shell:"auto"},{configCwd:e,executionCwd:e},n.command),{guard:{dependencies:{loadPolicySnapshot:()=>lf,getModes:()=>cf,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),o=n.expectBlocked?"blocked":"allowed",i=r.decision.kind==="deny"?"blocked":"allowed";return{command:n.command,description:n.description,expected:o,actual:i,passed:o===i,reason:r.decision.kind==="deny"?r.decision.reason:void 0,ruleId:r.decision.kind==="deny"?r.decision.ruleId:void 0}});return{passed:t.filter((n)=>n.passed).length,failed:t.filter((n)=>!n.passed).length,total:t.length,results:t}}function no(e){let t=T({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},e);if(ae(t.errors))return null;return{json:t.flags.json,skipUpdateCheck:t.flags.skipUpdateCheck}}async function Xa(e={}){let t=await At(!e.json,()=>{let n=df(e);return{ready:n,finish:()=>n}},()=>Rt(),{loadingMessage:"Checking system status…"});if(e.json)console.log(JSON.stringify(t,null,2));else pf(t);return uf(t.hooks,t.engineSelfTest,{userConfig:t.userConfig,projectConfig:t.projectConfig})?1:0}async function df(e){let t=e.cwd??process.cwd(),n=await St(),r=it(t,{ampPluginListOutput:n.ampPluginListOutput,codexPluginListOutput:n.codexPluginListOutput,copilotCliVersion:n.versions["copilot-cli"]}),o=as(t),i=ls(),s=B({cwd:t}),a=s.policy,l=de(a),c=De(a,l.capabilities),d=Yt(7),p=e.skipUpdateCheck?{currentVersion:P(),latestVersion:null,updateAvailable:!1}:await Qe(),m={hooks:r,engineSelfTest:Za(),userConfig:o.userConfig,projectConfig:o.projectConfig,configState:bt(s),effectiveRules:o.effectiveRules,shadowedRules:o.shadowedRules,environment:i,effectiveSafety:{selectedPreset:a.safety.level??"standard",level:l.effectiveLevel,capabilities:l.capabilities,ruleOverrides:a.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(c).filter(([,u])=>u.source==="rule_override"&&u.override==="off"&&u.inheritedEnabled&&u.changesInherited).map(([u])=>u),ruleCounts:{stored:Object.keys(a.destructiveCommandRuleOverrides).length,effective:Object.values(c).filter((u)=>u.changesInherited).length}},posture:xs(o.userConfig.path),activity:d,update:p,system:n};return{...m,findings:ds(m)}}function uf(e,t,n){return e.length>0&&e.every((r)=>!r.configured)||e.some((r)=>r.inspectionStatus==="failed")||t.failed>0||n.userConfig.exists&&!n.userConfig.valid||n.projectConfig.exists&&!n.projectConfig.valid}function pf(e){console.log(),console.log(ps(e.hooks)),console.log(),console.log(fs(e.engineSelfTest)),console.log(),console.log(ms(e)),console.log(),console.log(gs(e.environment)),console.log(),console.log(hs(e)),console.log(),console.log(ys(e.findings)),console.log(),console.log(Ls(e.activity)),console.log(),console.log(bs(e.system)),console.log(),console.log(vs(e.update)),console.log(ws(e))}import{existsSync as ff}from"node:fs";var mf=/^[A-Za-z0-9_@%+=:,./-]+$/,Qa="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function ro(e){let t=T({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},e);if(ae(t.errors))return console.error(Qa),console.error("Pass -- before a command that starts with dashes."),null;if(t.values.cwd!==void 0&&!ff(t.values.cwd))return console.error(`Error: --cwd path does not exist: ${t.values.cwd}`),null;let n=t.positionals.length===1?t.positionals[0]:t.positionals.map((r)=>mf.test(r)?r:`'${r.replaceAll("'","'\\''")}'`).join(" ");if(!n)return console.error("Error: No command provided"),console.error(Qa),null;return{json:t.flags.json,cwd:t.values.cwd,command:n}}function el(e){if(e)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function tl(e,t){let r=t-18;return[`${e.dtl}${e.dh.repeat(t)}${e.dtr}`,`${e.dv} Command Analysis${" ".repeat(r)}${e.dv}`,`${e.dbl}${e.dh.repeat(t)}${e.dbr}`]}function oo(e){return JSON.stringify(e)}function nl(e,t=0){return`[${e.map((r,o)=>us(r,o,t)).join(",")}]`}function Ln(e,t,n=70){let r=e.split(" "),o=[],i="";for(let s of r)if(i&&i.length+s.length+1>n)o.push(i),i=s;else i=i?`${i} ${s}`:s;if(i)o.push(i);return o.map((s,a)=>a===0?s:`${t}${s}`)}function rl(e,t,n){let r=[];switch(e.type){case"parse":return null;case"env-strip":return r.push(""),r.push(`STEP ${t} ${n.h} Strip environment variables`),r.push(` Removed: ${e.envVars.map((o)=>`${o}=<redacted>`).join(", ")}`),r.push(` Tokens: ${oo(e.output)}`),{lines:r,incrementStep:!0};case"leading-tokens-stripped":return r.push(""),r.push(`STEP ${t} ${n.h} Strip wrappers`),r.push(` Removed: ${e.removed.join(", ")}`),r.push(` Tokens: ${oo(e.output)}`),{lines:r,incrementStep:!0};case"shell-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Detect shell wrapper`),r.push(` Wrapper: ${e.wrapper} -c`),r.push(` Inner: ${e.innerCommand}`),{lines:r,incrementStep:!0};case"interpreter":{if(r.push(""),r.push(`STEP ${t} ${n.h} Detect interpreter`),r.push(` Interpreter: ${e.interpreter}`),r.push(` Code: ${e.codeArg}`),e.paranoidBlocked)r.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:r,incrementStep:!0}}case"busybox":return r.push(""),r.push(`STEP ${t} ${n.h} Busybox wrapper`),r.push(` Subcommand: ${e.subcommand}`),{lines:r,incrementStep:!0};case"transparent-wrapper":return r.push(""),r.push(`STEP ${t} ${n.h} Transparent wrapper`),r.push(` Wrapper: ${e.wrapper}`),r.push(` Tokens: ${oo(e.output)}`),{lines:r,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(r.push(""),r.push(`STEP ${t} ${n.h} Match rules`),r.push(` Rule: ${e.rule}()`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}case"worktree-relaxation":return r.push(""),r.push(`STEP ${t} ${n.h} Worktree relaxation`),r.push(` Mode: ${S.worktree.name}`),r.push(` Git cwd: ${e.gitCwd}`),r.push(" Result: Allowed local discard in linked worktree"),{lines:r,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(e.embeddedCommandFound)return r.push(""),r.push(`STEP ${t} ${n.h} Fallback scan`),r.push(` Found: ${e.embeddedCommandFound}`),{lines:r,incrementStep:!0};return null}case"custom-rules-check":{if(e.rulesChecked){if(r.push(""),r.push(`STEP ${t} ${n.h} Custom rules`),e.matched)r.push(" Result: MATCHED");else r.push(" Result: No match");return{lines:r,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(e.matched)return r.push(""),r.push(`STEP ${t} ${n.h} Dangerous text check`),r.push(` Token: ${e.token}`),r.push(" Result: MATCHED"),{lines:r,incrementStep:!0};return null}case"strict-unparseable":return r.push(""),r.push(`STEP ${t} ${n.h} Strict mode check`),r.push(` Command: ${e.rawCommand}`),r.push(" Result: ✗ UNPARSEABLE"),{lines:r,incrementStep:!0};case"segment-skipped":return null;case"error":return r.push(""),r.push(`ERROR: ${e.message}`),{lines:r,incrementStep:!1};default:return null}}function io(e,t){let n=el(t?.asciiOnly??!1),r=58,o=[],i=1;o.push(...tl(n,58)),o.push("");let s=e.trace.steps.find((u)=>u.type==="error");if(s&&s.type==="error"){o.push("ERROR"),o.push(` ${s.message}`),o.push(""),o.push("RESULT"),o.push(` Status: ${e.result==="blocked"?g.red("BLOCKED"):g.green("ALLOWED")}`),o.push(""),o.push("CONFIG");let u=e.configSource??"none";return o.push(` Path: ${u}`),o.join(`
|
|
188
|
+
`)}let a=e.trace.steps.find((u)=>u.type==="parse");if(a&&a.type==="parse"){o.push("INPUT"),o.push(` ${a.input}`),o.push(""),o.push(`STEP ${i} ${n.h} Split shell commands`),i++;for(let u=0;u<a.segments.length;u++){let h=a.segments[u];if(h){let f=Math.random();o.push(` Segment ${u+1}: ${nl(h,f)}`)}}}let l=e.trace.segments,c=l.length>1;for(let u of l){if(c){o.push("");let v="";if(a&&a.type==="parse"){let Hn=a.segments[u.index];if(Hn)v=Hn.join(" ")}let w=54,y=v,C=` Segment ${u.index+1}: `,H=" ";if(v){if(C.length+v.length+H.length>w){let Vc=w-C.length-H.length;y=`${v.substring(0,Vc-1)}…`}}let he=v?`${C}${y}${H}`:` Segment ${u.index+1} `,Fn=v?`${C}${g.cyan(y)}${H}`:he,Po=58-he.length,To=Math.floor(Po/2),qc=Po-To;o.push(`${n.sh.repeat(To)}${Fn}${n.sh.repeat(qc)}`)}if(u.steps.find((v)=>v.type==="segment-skipped")){o.push(""),o.push(" (skipped — prior segment blocked)");continue}let f=!1,L=!1;for(let v of u.steps){let w=rl(v,i,n);if(w){if(L=!0,v.type==="recurse"){o.push("");let y=" RECURSING ",C=58-y.length-4;o.push(` ${n.tl}${n.h}${y}${n.h.repeat(C)}`),o.push(` ${n.v}`),f=!0;continue}for(let y of w.lines)if(f)o.push(` ${n.v} ${y}`);else o.push(y);if(w.incrementStep)i++}}if(f)o.push(` ${n.v}`),o.push(` ${n.bl}${n.h.repeat(56)}`),f=!1;if(!L)o.push(""),o.push(` ${g.green("✓")} Allowed (no matching rules)`)}if(o.push(""),o.push("RESULT"),e.result==="blocked"){if(o.push(` Status: ${g.red("BLOCKED")}`),e.customRule){if(o.push(` Rule: ${e.customRule.id}`),e.customRule.rulebook)o.push(` Rulebook: ${e.customRule.rulebook.name} ${e.customRule.rulebook.version}`);if(e.customRule.source)o.push(` Source: ${e.customRule.source}`);if(e.customRule.override)o.push(` Override: reason ${e.customRule.override.reason}`)}if(e.reason){let u=Ln(e.reason," ");o.push(` Reason: ${u[0]}`);for(let h=1;h<u.length;h++)o.push(u[h]??"")}}else o.push(` Status: ${g.green("ALLOWED")}`);o.push(""),o.push("CONFIG");let d=e.configSource??"none",p=e.configValid?"":" (invalid)";o.push(` Path: ${d}${p}`),o.push(` Safety preset: ${e.selectedPreset??"standard"}`),o.push(` Effective capabilities: ${e.effectiveLevel}`);let m=Object.entries(e.destructiveCommandRuleOverrides??{});if(o.push(` Rule customizations: ${m.length}`),e.ruleActivation)o.push(` Rule activation: ${e.ruleActivation.id} — ${e.ruleActivation.enabled?"on":"off"} via ${e.ruleActivation.source}`);return o.join(`
|
|
189
|
+
`)}function so(e){return JSON.stringify(e,null,2)}function ol(e){return new Promise((t)=>{process.stdout.write(`${e}
|
|
190
|
+
`,()=>t())})}async function il(e){let t=ro(e);if(!t)return 1;try{let n=We(t.command,{cwd:t.cwd}),r=!!process.env.NO_COLOR||!process.stdout.isTTY;return await ol(t.json?so(n):io(n,{asciiOnly:r})),0}catch(n){if(!(n instanceof lr)&&!(n instanceof Se)&&!(n instanceof pe))throw n;if(t.json)return await ol(JSON.stringify({error:n.message})),1;return console.error(n.message),1}}var sl="2.0.9",W=" ",_e="cc-safety-net";function al(e){return e.argument?`${e.flags} ${e.argument}`:e.flags}function gf(e){return Math.max(...e.map((t)=>al(t).length))}function hf(e){return Math.max(...e.map((t)=>t.usage.length))}function yf(e){return Math.max(...e.map((t)=>`${_e} ${t.usage}`.length))}function Lf(e,t){let n=`${_e} ${e.usage}`;return`${W}${n.padEnd(t+2)}${e.description}`}function ge(e,t){return`${W}${e.padEnd(Math.max(40,e.length+2))}${t}`}function vn(e,t=console.log){let n=[];if(n.push(`${_e} ${e.name}`),n.push(""),n.push(`${W}${e.description}`),n.push(""),n.push("USAGE:"),n.push(`${W}${_e} ${e.usage}`),n.push(""),e.subcommands&&e.subcommands.length>0){n.push("SUBCOMMANDS:");let r=hf(e.subcommands);for(let o of e.subcommands)n.push(`${W}${o.usage.padEnd(r+2)}${o.description}`);n.push("")}if(e.options.length>0){n.push("OPTIONS:");let r=gf(e.options);for(let o of e.options){let i=al(o),s=o.default?`${o.description} (default: ${o.default})`:o.description;n.push(`${W}${i.padEnd(r+2)}${s}`)}n.push("")}if(e.examples&&e.examples.length>0){n.push("EXAMPLES:");for(let r of e.examples)n.push(`${W}${r}`)}t(n.join(`
|
|
191
|
+
`))}function ao(){let e=yf(Wt),t=[];t.push(`${_e} v${sl}`),t.push(""),t.push("Blocks destructive commands and secret access."),t.push(""),t.push("COMMANDS:");for(let n of Wt)t.push(Lf(n,e));t.push(""),t.push("GLOBAL OPTIONS:"),t.push(`${W}-h, --help Show help (use with command for command-specific help)`),t.push(`${W}-V, --version Show version`),t.push(""),t.push("HELP:"),t.push(`${W}${_e} help <command> Show help for a specific command`),t.push(`${W}${_e} <command> --help Show help for a specific command`),t.push(""),t.push("ENVIRONMENT VARIABLES:"),t.push(ge(`${S.level.name}=standard|strict|paranoid`,"Set session safety level")),t.push(ge(`${S.worktree.name}=1`,"Allow local git discards in linked worktrees")),t.push(ge(`${S.debug.name}=1`,"Print diagnostic messages to stderr")),t.push(ge(`${S.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),t.push(ge("CC_SAFETY_NET_HOME","Override rule config home directory")),t.push(""),t.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),t.push(ge(`${S.strict.name}=1`,"Force safety.overrides.fail_closed on")),t.push(ge(`${S.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),t.push(ge(`${S.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),t.push(ge(`${S.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),t.push(""),t.push("Documentation: https://ccsafetynet.com/docs"),console.log(t.join(`
|
|
192
|
+
`))}function ll(){console.log(sl)}function $t(e,t=console.log){let n=Jt(e);if(!n)return!1;if(n.name.toLowerCase()!==e.toLowerCase())return!1;return vn(n,t),!0}import{existsSync as bo,readFileSync as Ql}from"node:fs";import{homedir as um}from"node:os";import{join as Lo}from"node:path";import*as be from"node:readline";function vf(e){return e==="install"?"Install":"Uninstall"}function bf(e){return e==="install"?"Installing":"Uninstalling"}function wf(e){return e==="install"?"into":"from"}function ul(e){return e?.available===!0}function xf(e,t){let n=new Set(t);return e.filter((r)=>n.has(r.target)).map((r)=>r.target)}function cl(e,t,n){if(e.length===0||e.every((r)=>!r.available))return t;return Array.from({length:e.length},(r,o)=>o+1).map((r)=>(t+r*n+e.length)%e.length).find((r)=>ul(e[r]))}function Cf(e,t,n){if(n.ctrl&&n.name==="c")return"interrupt";if(n.name==="escape"||t==="q")return"abort";if(e==="install"&&(t==="u"||t==="U"))return"update";if(n.name==="up"||t==="k")return"up";if(n.name==="down"||t==="j")return"down";if(n.name==="space"||t===" ")return"toggle";if(n.name==="return"||n.name==="enter")return"confirm";return null}function kf(e){return{cursor:e.findIndex((t)=>t.available),selected:[]}}function Sf(e,t,n){if(n==="confirm"||n==="update"||n==="abort"||n==="interrupt")return{state:e,done:n};if(n==="up")return{state:{...e,cursor:cl(t,e.cursor,-1)}};if(n==="down")return{state:{...e,cursor:cl(t,e.cursor,1)}};let r=t[e.cursor];if(!ul(r))return{state:e};let o=e.selected.includes(r.target)?e.selected.filter((i)=>i!==r.target):xf(t,[...e.selected,r.target]);return{state:{...e,selected:o}}}var pl="◉",fl="◯",ml=">",gl=" ";function Df(e,t,n,r={}){let o=r.color!==!1,i=o?g.dim:(l)=>l,s=o?g.green:(l)=>l,a=o?g.bold:(l)=>l;return["",`${vf(e)} CC Safety Net ${wf(e)}:`,"",...t.map((l,c)=>{let d=n.selected.includes(l.target),p=c===n.cursor,m=d?pl:fl,u=p?ml:gl,h=l.available?"":` (${l.unavailableReason??"not installed"})`,f=`${m} ${l.label}${h}`,L=!l.available?i(f):d?s(f):p?a(f):f;return`${u} ${L}`}),"",e==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":t.some((l)=>l.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${e}. q/Esc: close`].join(`
|
|
193
|
+
`)}var dl=["global-hook","plugin"];function Rf(e,t,n={}){let r=n.color!==!1?g.bold:(i)=>i;return["","Install the Kimi Code integration as:","",...[`Global hook — ${t?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((i,s)=>{let a=s===e,l=`${a?pl:fl} ${i}`;return`${a?ml:gl} ${a?r(l):l}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
194
|
+
`)}function hl(e){let{input:t,output:n}=e;be.emitKeypressEvents(t);let r=t.isRaw===!0;t.setRawMode(!0),t.resume();let o=0,i=()=>{if(o===0)return;be.moveCursor(n,0,-o),be.cursorTo(n,0),be.clearScreenDown(n)},s=()=>{i();let a=e.render();n.write(`${a}
|
|
195
|
+
`),o=a.split(`
|
|
196
|
+
`).length};return new Promise((a)=>{let l=(d)=>{t.off("keypress",c),t.setRawMode(r),t.pause(),i(),a(d)};function c(d,p){e.onKey(d,p,{finish:l,draw:s})}t.on("keypress",c),s()})}function yl(e={}){let t=0;return hl({input:e.input??process.stdin,output:e.output??process.stdout,render:()=>Rf(t,e.globalHookInstalled===!0),onKey:(n,r,o)=>{if(r.ctrl&&r.name==="c"){o.finish(null),(e.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(r.name==="escape"||n==="q")return o.finish(null);if(r.name==="return"||r.name==="enter")return o.finish(dl[t]);if(r.name==="up"||r.name==="down"||n==="k"||n==="j")t=(t+1)%dl.length,o.draw()}})}function lo(e=process.stdin,t=process.stdout){return Boolean(e.isTTY&&t.isTTY&&typeof e.setRawMode==="function")}function Ll(e,t,n={}){let r=n.output??process.stdout,o=kf(t);return hl({input:n.input??process.stdin,output:r,render:()=>Df(e,t,o),onKey:(i,s,a)=>{let l=Cf(e,i,s);if(!l)return;let c=Sf(o,t,l);if(o=c.state,c.done==="interrupt"){a.finish(null),(n.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(c.done==="abort")return a.finish(null);if(c.done==="update")return a.finish("update");if(c.done==="confirm"){if(o.selected.length===0){r.write("\x07"),a.draw();return}a.finish([...o.selected]),r.write(`${bf(e)} selected integrations...
|
|
197
|
+
`);return}a.draw()}})}import{existsSync as bl,lstatSync as Ef,mkdirSync as Pf,mkdtempSync as Tf,readdirSync as If,readFileSync as at,rmSync as xn}from"node:fs";import{tmpdir as _f}from"node:os";import{basename as Of,dirname as $f,join as U}from"node:path";import{fileURLToPath as Nf}from"node:url";var co="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",Oe="cc-safety-net",$e="cc-safety-net/index.ts";import{spawn as Af}from"node:child_process";var uo=(e,t)=>{let n=Pe([...e],process.env);return new Promise((r)=>{let o=Af(n.cmd,n.args,{cwd:t,stdio:["ignore","pipe","pipe"]}),i=zr(o),s=!1,a=setTimeout(()=>{s=!0,o.kill()},120000);o.on("error",(l)=>{clearTimeout(a),r({status:null,errorCode:l.code,stdout:i.stdout,stderr:[l.message,i.stderr].filter(Boolean).join(`
|
|
198
|
+
`)})}),o.on("close",(l)=>{clearTimeout(a),r({status:s?null:l,errorCode:s?"ETIMEDOUT":void 0,stdout:i.stdout,stderr:i.stderr})})})};var st="cc-safety-net.ts",vl=U("amp",$e);function Ff(e){return U(e,".config","amp","plugins","cc-safety-net.ts")}function Hf(){let e=$f(Nf(import.meta.url));return[U(e,"..",vl),U(e,"..","..","..","dist",vl)]}function Mf(e=Hf()){let t=e.find((n)=>bl(n)&&Ef(n).isFile());if(!t)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return t}function wl(e){try{return JSON.parse(e)}catch{return}}function Cn(e){return e.subarray(0,Buffer.byteLength(co)).toString("utf-8")===co}async function Nt(e,t,n){let r=await e(t,n);if(r.status===0)return r;throw Error([`Failed to run ${t.join(" ")}${r.status===null?"":` (exit ${r.status})`}.`,[r.stdout,r.stderr].filter(Boolean).join(`
|
|
199
199
|
`).trim()].filter(Boolean).join(`
|
|
200
|
-
`))}async function
|
|
200
|
+
`))}async function xl(e){let t=await e(["amp","plugins","repositories","--json"]);if(t.status===null)throw Error(`${t.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${t.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
|
|
201
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.
|
|
202
202
|
${[t.stdout,t.stderr].filter(Boolean).join(`
|
|
203
|
-
`)}`.trim());let
|
|
204
|
-
`}async function
|
|
205
|
-
`)}function
|
|
203
|
+
`)}`.trim());let n=wl(t.stdout),r=(Array.isArray(n)?n:[]).filter((o)=>b(o,"scope")==="user"&&b(o,"exists")===!0&&b(o,"viewerCanWrite")===!0).map((o)=>b(o,"cloneRef")).find((o)=>typeof o==="string"&&o.length>0);if(!r)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return r}async function Cl(e,t){let n=Tf(U(_f(),"cc-safety-net-amp-"));try{return await Nt(e,["amp","clone","user-plugins",n]),await t(n)}finally{xn(n,{recursive:!0,force:!0})}}function po(e){return`rerun ${e==="overwrite"?"install":"uninstall"} --amp`}function kl(e,t,n){let r=U(e,t),o=E(r);if(!o)return;if(o.isSymbolicLink()||!o.isFile())throw Error(`Refusing to ${n} ${t} in your Amp personal plugins repository: not a regular file. Remove it there and ${po(n)}.`);let i=at(r);if(Cn(i))return i;throw Error(`Refusing to ${n} unmanaged file ${t} in your Amp personal plugins repository. Remove it there and ${po(n)}.`)}function Sl(e,t){let n=U(e,Oe),r=E(n);if(!r)return;if(r.isSymbolicLink()||!r.isDirectory())throw Error(`Refusing to ${t} ${Oe} in your Amp personal plugins repository: not a regular directory. Remove it there and ${po(t)}.`);return kl(e,$e,t)}function jf(e){let t=U(e,st),n=E(t);if(!n||n.isSymbolicLink()||!n.isFile())return;let r=at(t);return Cn(r)?r:void 0}async function Dl(e,t,n,r){if(await Nt(e,n,t),(await Nt(e,["git","status","--porcelain"],t)).stdout.trim()==="")return!1;return await Nt(e,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",r],t),await Nt(e,["git","push","origin","HEAD"],t),!0}function bn(e,t){Uf(e,t),Gf(e,t)}function Rl(e,t){if(t==="keep")return;throw Error(`Local Amp plugin ${e} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function Uf(e,t){let n=Ff(e),r=E(n);if(!r)return;if(!r.isSymbolicLink()&&r.isFile()&&Cn(at(n))){xn(n);return}Rl(n,t)}function Gf(e,t){let n=U(e,".config","amp","plugins",Oe),r=E(n);if(!r)return;if(!r.isSymbolicLink()&&r.isDirectory()&&Bf(n)){xn(n,{recursive:!0});return}Rl(n,t)}function Bf(e){let t=Of($e);if(If(e).join("\x00")!==t)return!1;let n=U(e,t),r=E(n);return!!r&&!r.isSymbolicLink()&&r.isFile()&&Cn(at(n))}function qf(){let e=vt();if(!bl(e))return"";let t=wl(at(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(wn(t))};
|
|
204
|
+
`}async function Al(e,t=Mf(),n=uo){let r=Buffer.concat([at(t),Buffer.from(qf(),"utf-8")]),o=await xl(n);return Cl(n,async(i)=>{let s=`${o}/${Oe}`,a=Sl(i,"overwrite"),l=kl(i,st,"overwrite");if(a?.equals(r)&&!l)return bn(e,"fail"),{path:s,alreadyInstalled:!0};if(Pf(U(i,Oe),{recursive:!0}),_(U(i,$e),r),l)xn(U(i,st));let c=await Dl(n,i,["git","add","--",$e,...l?[st]:[]],`chore: update cc-safety-net plugin to v${P()}`);return bn(e,"fail"),{path:s,alreadyInstalled:!c}})}async function El(e,t=uo){let n=await xl(t);return Cl(t,async(r)=>{let o=Sl(r,"remove"),i=jf(r),s=`${n}/${i&&!o?st:Oe}`;if(!o&&!i)return bn(e,"keep"),{path:s,alreadyInstalled:!1};return await Dl(t,r,["git","rm","--",...o?[$e]:[],...i?[st]:[]],`chore: remove cc-safety-net plugin v${P()}`),bn(e,"keep"),{path:s,alreadyInstalled:!0}})}import{existsSync as Pl,mkdirSync as Vf,readFileSync as zf}from"node:fs";import{dirname as Kf}from"node:path";var fo="npx -y cc-safety-net hook --agy-cli",we="cc-safety-net";function Sn(){return{PreToolUse:[{hooks:[{type:"command",command:fo,timeout:30}]}]}}function Tl(e){try{let t=JSON.parse(zf(e,"utf-8"));if(!t||typeof t!=="object"||Array.isArray(t))throw Error("Antigravity hooks config must be a JSON object");return t}catch(t){if(t instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${e}: ${t.message}`);throw t}}function Il(e){let t=e[we];if(t===void 0)return e[we]=Sn(),e[we];if(!t||typeof t!=="object"||Array.isArray(t))throw Error(`Antigravity hooks config entry "${we}" must be an object`);if(!Array.isArray(t.PreToolUse))t.PreToolUse=[];return t}function _l(e){if(!Array.isArray(e.PreToolUse))return!1;return e.PreToolUse.some((t)=>Array.isArray(t.hooks)&&t.hooks.some((n)=>n.command===fo))}function Wf(e){return Object.values(e).some((t)=>t.enabled!==!1&&_l(t))}function Jf(e){if(e[we]===void 0)return!1;let t=Il(e);if(t.enabled!==!1||!_l(t))return!1;return t.enabled=!0,!0}function Yf(e){if(e[we]===void 0){e[we]=Sn();return}let t=Il(e);t.PreToolUse??=[],t.enabled=!0,t.PreToolUse.push(Sn().PreToolUse?.[0]??{hooks:[]})}function Zf(e){let t=!1;for(let n of Object.values(e)){if(!Array.isArray(n.PreToolUse))continue;n.PreToolUse=n.PreToolUse.flatMap((r)=>{if(!Array.isArray(r.hooks))return[r];let o=r.hooks.filter((i)=>i.command!==fo);if(o.length!==r.hooks.length)t=!0;return o.length===0?[]:[{...r,hooks:o}]})}return t}function kn(e,t){_(e,`${JSON.stringify(t,null,2)}
|
|
205
|
+
`)}function Ol(e){let t=Ct(e);if(Vf(Kf(t),{recursive:!0}),!Pl(t))return kn(t,{[we]:Sn()}),{path:t,alreadyInstalled:!1};let n=Tl(t);if(Wf(n))return{path:t,alreadyInstalled:!0};if(Jf(n))return kn(t,n),{path:t,alreadyInstalled:!1};return Yf(n),kn(t,n),{path:t,alreadyInstalled:!1}}function $l(e){let t=Ct(e);if(!Pl(t))return{path:t,alreadyInstalled:!1};let n=Tl(t);if(!Zf(n))return{path:t,alreadyInstalled:!1};return kn(t,n),{path:t,alreadyInstalled:!0}}import{spawn as Xf}from"node:child_process";var se=V.map((e)=>({target:e.id,flag:e.flag,label:R(e.id),probeCommand:e.probeCommand}));function mo(e){let t=new Set(e);return se.map((n)=>n.target).filter((n)=>t.has(n))}async function Nl(e,t){for(let n of e)await t(n)}var Qf=5000;function go(e){return new Promise((t)=>{let n=Pe([...e],process.env),r=Xf(n.cmd,n.args,{env:process.env,stdio:"ignore"}),o=!1,i=(a)=>{if(o)return;o=!0,clearTimeout(s),t(a)},s=setTimeout(()=>{r.kill(),i(!1)},Qf);r.on("error",()=>i(!1)),r.on("close",(a)=>i(a===0))})}function Fl(e=go,t={}){let n=new Set(t.configuredTargets??[]);return Promise.all(se.map(async(r)=>({target:r.target,flag:r.flag,label:r.label,...Ml(t.action,await e(r.probeCommand),n.has(r.target))})))}function Hl(e,t){let n=new Set(t.configuredTargets??[]);return e.map((r)=>({...r,...Ml(t.action,r.available,n.has(r.target))}))}function Ml(e,t,n){if(e==="uninstall")return n?{available:!0}:{available:!1,unavailableReason:"not installed"};if(e==="install"&&n)return{available:!1,unavailableReason:"already installed"};if(!t)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as jl,readdirSync as em,rmSync as tm}from"node:fs";import{join as lt}from"node:path";function Dn(e,t=process.platform){let n=lt(process.env.npm_config_cache||(t==="win32"?lt(process.env.LOCALAPPDATA||lt(e,"AppData","Local"),"npm-cache"):lt(e,".npm")),"_npx");if(!jl(n))return;em(n).filter((r)=>jl(lt(n,r,"node_modules","cc-safety-net"))).forEach((r)=>{tm(lt(n,r),{recursive:!0,force:!0})})}import{existsSync as Gl,mkdirSync as nm,readFileSync as Bl}from"node:fs";import{dirname as rm,join as Ul}from"node:path";var Ft="npx -y cc-safety-net hook --kimi-code",ho=`[[hooks]]
|
|
206
206
|
event = "PreToolUse"
|
|
207
|
-
command = "${
|
|
208
|
-
`).reduce((r
|
|
209
|
-
`)}function
|
|
210
|
-
`,t+1);return
|
|
211
|
-
`,
|
|
212
|
-
${
|
|
213
|
-
`;return`${
|
|
214
|
-
|
|
215
|
-
${
|
|
216
|
-
`}function
|
|
217
|
-
`),{path:t,alreadyInstalled:!1};let
|
|
218
|
-
`;return
|
|
219
|
-
`)},opencode:{beforeInstall:
|
|
220
|
-
`),`Enabled ${
|
|
221
|
-
`),`Enabled npm:cc-safety-net extensions in ${t}`}function
|
|
222
|
-
`)}async function
|
|
223
|
-
Removing the plugin files anyway; ${
|
|
224
|
-
`)}var
|
|
225
|
-
`),uninstall:()=>
|
|
226
|
-
`),uninstall:()=>
|
|
227
|
-
`);function
|
|
207
|
+
command = "${Ft}"`,yo=`{ event = "PreToolUse", command = "${Ft}" }`;function ql(e){return Ul(process.env.KIMI_CODE_HOME??Ul(e,".kimi-code"),"config.toml")}function om(e){return e.split(`
|
|
208
|
+
`).reduce((n,r)=>{if(/^\s*\[/.test(r))return n.activeTable=!0,n.lines.push(r),n;if(!n.activeTable&&/^\s*hooks\s*=\s*\[\s*]\s*(?:#.*)?$/.test(r))return n;return n.lines.push(r),n},{activeTable:!1,lines:[]}).lines.join(`
|
|
209
|
+
`)}function im(e,t){if(e[t]!=="#")return t;let n=e.indexOf(`
|
|
210
|
+
`,t+1);return n===-1?e.length:n+1}function sm(e,t){return fn(e,t,{skipComment:im,stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"})}function Vl(e){let t=!1,n=0;while(n<e.length){let r=e.indexOf(`
|
|
211
|
+
`,n),o=r===-1?e.length:r,i=e.slice(n,o);if(/^\s*\[/.test(i))t=!0;if(!t){let s=/^(\s*)hooks\s*=\s*\[/.exec(i);if(s){let a=n+s[0].lastIndexOf("[");return{start:a,end:sm(e,a)}}}n=r===-1?e.length:r+1}return}function am(e,t){let n=e.slice(0,t.end).trimEnd(),r=Fa(e,t.end),o=r===""?" ":`${r} `,i=!n.endsWith("[")&&!n.endsWith(",");return`${n}${i?",":""}
|
|
212
|
+
${o}${yo}${e.slice(t.end)}`}function lm(e){let t=Vl(e);if(t&&e.slice(t.start+1,t.end).trim())return am(e,t);let n=om(e).trimEnd();if(n==="")return`${ho}
|
|
213
|
+
`;return`${n}
|
|
214
|
+
|
|
215
|
+
${ho}
|
|
216
|
+
`}function cm(e){return e.split(/(?=^\s*\[)/m).filter((n)=>!/^\s*\[\[hooks]]\s*$/m.test(n)||!n.includes(Ft)).join("").trimEnd()}function dm(e,t){let n=e.indexOf(yo,t.start);if(n===-1||n>t.end)return e;return mn(e,{start:n,end:n+yo.length})}function zl(e){let t=ql(e);if(nm(rm(t),{recursive:!0}),!Gl(t))return _(t,`${ho}
|
|
217
|
+
`),{path:t,alreadyInstalled:!1};let n=Bl(t,"utf-8");if(n.includes(Ft))return{path:t,alreadyInstalled:!0};return _(t,lm(n)),{path:t,alreadyInstalled:!1}}function Kl(e){let t=ql(e);if(!Gl(t))return{path:t,alreadyInstalled:!1};let n=Bl(t,"utf-8");if(!n.includes(Ft))return{path:t,alreadyInstalled:!1};let r=Vl(n),o=r?dm(n,r):`${cm(n)}
|
|
218
|
+
`;return _(t,o),{path:t,alreadyInstalled:!0}}var vo="safety-net@cc-marketplace",Wl=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),Jl=new Set(["antigravity-cli","cursor","hermes-agent","kimi-code"]);function wo(e){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(e??"")}function ec(e){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(e??"")}function pm(e){return/^Marketplace `cc-marketplace`\s*$/m.test(e??"")}var tc={"claude-code":{installCommands:(e)=>{let t=rn(e,"cc-safety-net@cc-marketplace");return{commands:[...t?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...Pr(e).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:rn(e,vo)?[["claude","plugin","uninstall",vo]]:[],update:t}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(e,t)=>{let n=t??await ie(["codex","plugin","list"]),r=ec(n);return{commands:[r||pm(n)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:wo(n)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:r}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:"Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."},"copilot-cli":{installCommands:async()=>{let e=await ie(["copilot","plugin","list"]),t=[...Js(e)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...Ys(e)?[["copilot","plugin","uninstall",zs]]:[]];if(Ks(e))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",oe]],cleanupCommands:t,update:!0};return{commands:[Ws(await ie(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",oe]],cleanupCommands:t}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(e)=>{let t=Fr(e);if(t.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(t.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:Yr,installCommands:()=>({commands:Ea()}),uninstallCommands:[["openclaw","plugins","uninstall",A,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
|
|
219
|
+
`)},opencode:{beforeInstall:Qr,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 En(){return process.env.HOME??um()}function nc(e,t=(n)=>n){try{let n=JSON.parse(t(Ql(e,"utf-8")));if(!n||typeof n!=="object"||Array.isArray(n))throw Error(`Settings file ${e} must be a JSON object`);return n}catch(n){if(n instanceof SyntaxError)throw Error(`Failed to parse ${e}: ${n.message}`);throw n}}function fm(e){let t=Lo(Et(e),"settings.json");if(!bo(t))return;let n=nc(t,q),r=n.enabledPlugins;if(!r||typeof r!=="object"||Array.isArray(r))return;if(r[oe]!==!1)return;let o=Ql(t,"utf-8"),i=o.replace(new RegExp(`("${oe}"\\s*:\\s*)false`),"$1true");return r[oe]=!0,_(t,i!==o?i:`${JSON.stringify(n,null,2)}
|
|
220
|
+
`),`Enabled ${oe} plugin in ${t}`}function mm(e){let t=eo(e);if(!bo(t))return;let n=nc(t);if(!Array.isArray(n.packages))return;let r=n.packages.find((o)=>!!o&&typeof o==="object"&&!Array.isArray(o)&&to(o.source)&&("extensions"in o));if(!r)return;return delete r.extensions,_(t,`${JSON.stringify(n,null,2)}
|
|
221
|
+
`),`Enabled npm:cc-safety-net extensions in ${t}`}function Yl(e,t){let n=T({label:t,booleans:Object.fromEntries(se.map((i)=>[i.target,[i.flag]]))},e),r=n.errors[0];if(r)throw Error(r);let o=se.filter((i)=>n.flags[i.target]).map((i)=>i.target);if(o.length!==1)throw Error(`Choose exactly one ${t} target: ${se.map((i)=>i.flag).join(", ")}`);return o[0]}async function rc(e=En(),t=Xe){let[n,r,o]=await Promise.all([t(["amp","plugins","list"],30000),t(["codex","plugin","list"],30000),t(["copilot","--binary-version"])]);return{codexPluginListOutput:r,hooks:it(process.cwd(),{homeDir:e,ampPluginListOutput:n,codexPluginListOutput:r,copilotCliVersion:o})}}async function gm(e,t=Xe){let n=await rc(En(),t);return n.hooks.filter((r)=>e==="install"?r.configured:r.detected||r.inspectionStatus==="not-inspected").filter((r)=>r.platform!=="codex"||!wo(n.codexPluginListOutput)||ec(n.codexPluginListOutput)).map((r)=>r.platform)}function hm(e,t,n){if(t.length>0)return{finish:async()=>[Yl(t,e)]};if(!n.selectTargets&&!lo(n.input,n.output))return{finish:async()=>[Yl(t,e)]};let r=n.detectConfiguredTargets??(()=>gm(e,n.fetchVersion)),o=Promise.all([Fl(n.probeTargets),r()]);return{ready:o,finish:async()=>{let[i,s]=await o,a=Hl(i,{action:e,configuredTargets:s}),l=n.selectTargets?await n.selectTargets(e,Xl(e,a)):await Ll(e,Xl(e,a),{input:n.input,output:n.output});if(l==="update")return l;if(!l||l.length===0)return null;return mo(l)}}}async function Ne(e,t,n=!1,r){let o=tc[e];o.beforeInstall?.(t);let i=typeof o.installCommands==="function"?await o.installCommands(t,r):{commands:o.installCommands};return await Kr(i.commands),await Ca(i.cleanupCommands??[]),[`${i.update||n?"Updated":"Installed"} ${R(e)} integration`,o.postInstallMessage].filter(Boolean).join(`
|
|
222
|
+
`)}async function ct(e){let t=tc[e];if(!t.uninstallCommands)throw Error(`${R(e)} uninstall is not supported`);return await Kr(t.uninstallCommands),`Uninstalled ${R(e)} integration`}function ym(e){let t=Wa(e);return t.alreadyInstalled?`Uninstalled OpenCode plugin from ${t.path}`:`OpenCode plugin not installed in ${t.path}`}var Lm={"antigravity-cli":{install:Ol,uninstall:$l},cursor:{install:sa,uninstall:aa},"kimi-code":{install:zl,uninstall:Kl}};function dt(e,t,n,r=!1){if(e==="install"&&!r)Dn(n);let o=Lm[t][e](n),i=R(t),s=e!=="install"?"Uninstalled":r?"Updated":"Installed";return e==="install"&&o.alreadyInstalled?r?`${i} hook up to date in ${o.path}`:`${i} hook already installed in ${o.path}`:e==="uninstall"&&!o.alreadyInstalled?`${i} hook not installed in ${o.path}`:`${s} ${i} hook ${e==="install"?"in":"from"} ${o.path}`}var vm={amp:{install:Al,uninstall:El,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:fa,uninstall:ma,afterInstall:async(e)=>{let t=qr(e);return await ie(["hermes","plugins","enable",z,"--no-allow-tool-override"]),!t},beforeUninstall:async(e)=>{Br(e);try{await ie(["hermes","plugins","disable",z])}catch(t){console.warn(`${t instanceof Error?t.message:String(t)}
|
|
223
|
+
Removing the plugin files anyway; ${z} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Rn(e,t,n,r=!1){let o=vm[t];if(e==="uninstall")await o.beforeUninstall?.(n);let i=e==="install"?await o.install(n):await o.uninstall(n),s=e==="install"&&await o.afterInstall?.(n),a=R(t),l=!s&&(e==="install"&&i.alreadyInstalled||e==="uninstall"&&!i.alreadyInstalled);return[l?e==="install"?`${a} plugin ${r?"up to date":"already installed"} at ${i.path}`:`${a} plugin not installed at ${i.path}`:`${e!=="install"?"Uninstalled":r?"Updated":"Installed"} ${a} plugin ${e==="install"?"at":"from"} ${i.path}`,l?void 0:o.restartNote].filter(Boolean).join(`
|
|
224
|
+
`)}var bm={amp:{install:(e,t)=>Rn("install","amp",e,t),uninstall:(e)=>Rn("uninstall","amp",e)},"antigravity-cli":{install:(e,t)=>dt("install","antigravity-cli",e,t),uninstall:(e)=>dt("uninstall","antigravity-cli",e)},"claude-code":{install:(e,t)=>Ne("claude-code",e,t),uninstall:()=>ct("claude-code")},codex:{install:(e,t,n)=>Ne("codex",e,t,n),uninstall:()=>ct("codex")},"copilot-cli":{install:async(e,t)=>[await Ne("copilot-cli",e,t),fm(e)].filter(Boolean).join(`
|
|
225
|
+
`),uninstall:()=>ct("copilot-cli")},cursor:{install:(e,t)=>dt("install","cursor",e,t),uninstall:(e)=>dt("uninstall","cursor",e)},"gemini-cli":{install:(e,t)=>Ne("gemini-cli",e,t),uninstall:()=>ct("gemini-cli")},"hermes-agent":{install:(e,t)=>{if(!t)Dn(e);return Rn("install","hermes-agent",e,t)},uninstall:(e)=>Rn("uninstall","hermes-agent",e)},"kimi-code":{install:(e,t)=>dt("install","kimi-code",e,t),uninstall:(e)=>dt("uninstall","kimi-code",e)},openclaw:{install:async(e,t)=>{let n=await Ne("openclaw",e,t);return await Pa(),n},uninstall:(e)=>(Yr(e),ct("openclaw"))},opencode:{install:async(e,t)=>{let n=await Ne("opencode",e,t);return await qa(e),n},uninstall:(e)=>ym(e)},pi:{install:async(e,t)=>[await Ne("pi",e,t),mm(e)].filter(Boolean).join(`
|
|
226
|
+
`),uninstall:()=>ct("pi")}},Zl=["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 wm(e){if(It({homeDir:e,cwd:process.cwd()}).status!=="configured")return Zl;return[Zl,"",g.red(["CAUTION: the global Kimi Code hook is installed and will run alongside the plugin.","After the plugin is active, remove it with: cc-safety-net uninstall --kimi-code"].join(`
|
|
228
228
|
`))].join(`
|
|
229
|
-
`)}function
|
|
230
|
-
`)}),s.some((
|
|
231
|
-
`),0;if(
|
|
232
|
-
`);return}if(
|
|
233
|
-
`);return}}let
|
|
234
|
-
`)}),0}catch(
|
|
235
|
-
Check file permissions for the target config file and parent directory.`;if(
|
|
236
|
-
Check that the target config path and parent directory exist.`;if(
|
|
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
|
|
239
|
-
Added $schema to ${y.scope.toLowerCase()} config.`);
|
|
240
|
-
${
|
|
241
|
-
Config validation failed.`),1;return console.log(
|
|
229
|
+
`)}function Xl(e,t){return t.map((n)=>e==="install"&&n.target==="kimi-code"&&n.unavailableReason==="already installed"?{...n,available:!0,unavailableReason:void 0,label:`${n.label} (global hook installed)`}:n)}function xm(e,t){if(e.selectKimiInstallMethod)return e.selectKimiInstallMethod();if(!lo(e.input,e.output))return Promise.resolve("global-hook");return yl({input:e.input,output:e.output,globalHookInstalled:It({homeDir:t,cwd:process.cwd()}).status==="configured"})}async function oc(e,t,n,r=!1,o){return bm[t][e](n,r,o)}function Cm(e){let t=T({label:"update"},e).errors[0];if(t)throw Error(t)}async function km(e,t=Xe){let n=await rc(e,t),r=Lo(Et(e),"installed-plugins");return{targets:mo([...n.hooks.filter((i)=>i.platform!=="copilot-cli"&&i.detected).map((i)=>i.platform),...[on,Vs,qs].flatMap((i)=>bo(Lo(r,...i))?["copilot-cli"]:[]),...rn(e,vo)?["claude-code"]:[],...wo(n.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:n.codexPluginListOutput}}async function Sm(e){let t=En(),n=e.output??process.stdout,r=km(t,e.fetchVersion??Xe).then(async(a)=>{let l=new Set(a.targets);return{targets:a.targets,codexPluginListOutput:a.codexPluginListOutput,available:new Map(await Promise.all(se.filter((c)=>l.has(c.target)&&Wl.has(c.target)).map(async(c)=>[c.target,await go(c.probeCommand)])))}}),o=await At(e.showBanner??!0,()=>({ready:r,finish:()=>r}),()=>Rt({input:e.input??process.stdin,output:n}),{loadingMessage:"Checking installed integrations…",output:n});if(o.targets.length===0)return n.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),0;let i=o.targets.some((a)=>Jl.has(a))?await Promise.resolve().then(()=>(Dn(t),null)).catch((a)=>An(a)):null,s=await en(Promise.all(o.targets.map((a)=>{if(Wl.has(a)&&!o.available.get(a))return Promise.resolve({message:`${R(a)} not found; skipped`,failed:!1});if(i!==null&&Jl.has(a))return Promise.resolve({message:i,failed:!0});return oc("install",a,t,!0,o.codexPluginListOutput).then((l)=>({message:l,failed:!1}),(l)=>({message:An(l),failed:!0}))})),{loadingMessage:`Updating ${o.targets.length} integration${o.targets.length===1?"":"s"}…`,output:n});return s.forEach((a)=>{a.failed?console.error(a.message):n.write(`${a.message}
|
|
230
|
+
`)}),s.some((a)=>a.failed)?1:0}function xo(e,t={}){return Promise.resolve().then(()=>Cm(e)).then(()=>Sm(t)).catch((n)=>(console.error(An(n)),1))}async function Ht(e,t,n={}){try{let r=await At(!0,()=>hm(e,t,n),()=>Rt({input:n.input??process.stdin,output:n.output??process.stdout}),{loadingMessage:e==="install"?"Checking available integrations…":"Checking installed integrations…",output:n.output??process.stdout});if(!r)return(n.output??process.stdout).write(`Cancelled: nothing was ${e}ed.
|
|
231
|
+
`),0;if(r==="update")return(n.runUpdate??(()=>xo([],{fetchVersion:n.fetchVersion,input:n.input,output:n.output,showBanner:!1})))();let o=En(),i=n.output??process.stdout;return await Nl(r,async(s)=>{if(s==="kimi-code"&&e==="install"){let l=await xm(n,o);if(l===null){i.write(`Cancelled: Kimi Code integration was not installed.
|
|
232
|
+
`);return}if(l==="plugin"){i.write(`${wm(o)}
|
|
233
|
+
`);return}}let a=await en(oc(e,s,o),{loadingMessage:`${e==="install"?"Installing":"Uninstalling"} ${R(s)} integration…`,output:i});i.write(`${a}
|
|
234
|
+
`)}),0}catch(r){return console.error(An(r)),1}}function An(e){let t=e instanceof Error?e.message:String(e),n=typeof e==="object"&&e!==null&&"code"in e?e.code:null;if(n==="EACCES"||n==="EPERM")return`${t}
|
|
235
|
+
Check file permissions for the target config file and parent directory.`;if(n==="ENOENT")return`${t}
|
|
236
|
+
Check that the target config path and parent directory exist.`;if(n==="ENOTDIR")return`${t}
|
|
237
|
+
Check that every parent path component is a directory.`;return t}import{join as cg}from"node:path";var ic="# 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 Mt(e,t){if(!e.ok){Em(e);return}Pm(e),console.log(t),console.log("Rule config synced."),console.log(""),Dm(e.entries)}function Dm(e){if(e.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${e.length}):`);for(let t of e)console.log(` - ${t.name} ${t.version} (${Rm(t.ruleCount??0)})`),console.log(` Source: ${rr(t)}`)}function Rm(e){return`${e} ${e===1?"rule":"rules"}`}function ac(e,t){Fe("Active sources",e.rulebooks,(n)=>[`[${n.source}] ${n.name} ${n.version}`,` Source: ${t[n.source].get(n.spec)??n.spec}`]),Fe("Active rules",e.rules,(n)=>[`[${Am(e,n.name)}] ${n.name}`,` Command: ${n.subcommand?`${n.command} ${n.subcommand}`:n.command}`,` Block args: ${n.block_args.join(", ")}`,` Reason: ${n.reason}`]),Fe("Disabled rules",sc(e,"off"),(n)=>[n.key]),Fe("Reason overrides",sc(e,"reason"),(n)=>[n.key,` Reason: ${n.value.reason}`]),Fe("Transparent wrappers",e.transparent_wrappers,(n)=>[n]),Fe("Issues",e.errors,(n)=>[n]),Fe("Warnings",e.warnings,(n)=>[n])}function Fe(e,t,n){if(t.length===0){console.log(`${e}: (none)`);return}console.log(`${e} (${t.length}):`);for(let r of t){let[o,...i]=n(r);console.log(` - ${o}`);for(let s of i)console.log(` ${s}`)}}function Am(e,t){return e.rulebooks.find((n)=>n.rules.includes(t))?.source??"project"}function sc(e,t){return Object.entries({...e.userConfig?.overrides??{},...e.projectConfig?.overrides??{}}).filter((n)=>{if(t==="off")return n[1]==="off";return!!n[1]&&typeof n[1]==="object"}).map(([n,r])=>({key:n,value:r}))}function Em(e){for(let t of e.errors)console.error(t)}function Pm(e){if(!e.warnings||e.warnings.length===0)return;for(let t of e.warnings)console.warn(t)}import{dirname as lc,join as Pn}from"node:path";var Tm=".safety-net.json",Im="~/.cc-safety-net/config.json";async function uc(e){return[await cc({legacyPath:dc({cwd:e.cwd}),configPath:X(e.cwd),defaultRulebookName:"project-rules",migratedFrom:Tm,cleanup:e.cleanup,syncOptions:{cwd:e.cwd}}),await cc({legacyPath:gt(),configPath:Q(),defaultRulebookName:"user-rules",migratedFrom:Im,cleanup:e.cleanup,syncOptions:{cwd:e.cwd,global:!0}})].every((n)=>n)?0:1}async function cc(e){let t=J(e.syncOptions),n=k(t.filesystemScope,e.legacyPath),r=x(n);if(r===null)return console.log(`No legacy config found at ${e.legacyPath}`),!0;let o=Om(r);if(!o.ok){for(let m of o.errors)console.error(m);return!1}let i=Y(t.configTarget);if(i.errors.length>0){for(let m of i.errors)console.error(m);return!1}let s=i.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},a=$m(lc(e.configPath),s.rules,e.defaultRulebookName,e.migratedFrom,t.filesystemScope),l=Pn(lc(e.configPath),a,"rulebook.json"),c=k(t.filesystemScope,l),d=[Co(t.configTarget),Co(c),Co(t.lockTarget)],p=await _m(e,t.configTarget,c,a,o.config.rules,s.rules.includes(a)?s.rules:[...s.rules,a],s.overrides??{},s.transparent_wrappers??[]);if(!p.ok){Hm(d);for(let m of p.errors)console.error(m);return!1}if(!e.cleanup)return console.log(`Migrated legacy config at ${e.legacyPath}. Legacy file is no longer used.`),!0;if(!Fm(t.configTarget,c,a,e.migratedFrom,o.config.rules))return console.error(`Migration cleanup verification failed for ${e.legacyPath}`),!1;return ft(n),console.log(`Deleted legacy config at ${e.legacyPath}`),!0}async function _m(e,t,n,r,o,i,s,a){try{return Z(t,{version:1,rules:i,overrides:s,transparent_wrappers:a}),Z(n,Nm(r,e.migratedFrom,o)),await qe(e.syncOptions)}catch(l){return{ok:!1,errors:[l instanceof Error?l.message:String(l)]}}}function Om(e){try{let t=JSON.parse(e),n=qn(t);if(n.errors.length>0)return{ok:!1,errors:n.errors};return{ok:!0,config:{version:1,rules:t.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function $m(e,t,n,r,o){let i=t.find((s)=>Mm(k(o,Pn(e,s,"rulebook.json")))===r);if(i)return i;if(x(k(o,Pn(e,n,"rulebook.json")))===null)return n;for(let s=2;;s++){let a=`${n}-${s}`;if(x(k(o,Pn(e,a,"rulebook.json")))===null)return a}}function Nm(e,t,n){return{rulebook_version:1,name:e,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:t,allowed_commands:[...new Set(n.map((r)=>r.command))],rules:n,tests:n.map((r)=>({command:[r.command,r.subcommand,r.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:r.name}))}}function Fm(e,t,n,r,o){if(!Y(e).config?.rules.includes(n))return!1;try{let s=x(t);if(s===null)return!1;let a=JSON.parse(s);return a.migrated_from===r&&JSON.stringify(a.rules)===JSON.stringify(o)}catch{return!1}}function Co(e){return{target:e,content:x(e)}}function Hm(e){for(let t of e){if(t.content===null){ft(t.target);continue}xe(t.target,t.content)}}function Mm(e){let t=x(e);if(t===null)return null;try{let n=JSON.parse(t);return typeof n.migrated_from==="string"?n.migrated_from:null}catch{return null}}import{mkdir as jm,readFile as Um,writeFile as Gm}from"node:fs/promises";import{dirname as Bm,join as qm}from"node:path";var Vm=86400000,zm=604800000;async function fc(e=Date.now()){if(process.env.CC_SAFETY_NET_NO_UPDATE_CHECK)return null;let t=sr();if(!t)return null;let n=qm(t,".cc-safety-net","update-check.json"),r=await Km(n,e);if(!r.lastCheck||e-r.lastCheck>Vm){let s=await Qe();if(r.lastCheck=e,s.latestVersion)r.latestVersion=s.latestVersion;if(!await pc(n,r))return null;if(s.error)return null}let o=r.latestVersion,i=P();if(!o||!Sr(o,i))return null;if(r.notifiedVersion===o&&r.notifiedAt!==void 0&&e-r.notifiedAt<zm)return null;if(r.notifiedVersion=o,r.notifiedAt=e,!await pc(n,r))return null;return`UPDATE_AVAILABLE: cc-safety-net v${o} is available (running v${i}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function Km(e,t){let n=await Um(e,"utf8").then((i)=>JSON.parse(i)).catch(()=>{return});if(!n||typeof n!=="object"||Array.isArray(n))return{};let r=n,o=(i)=>typeof i==="number"&&Number.isFinite(i)&&i<=t?i:void 0;return{lastCheck:o(r.lastCheck),latestVersion:typeof r.latestVersion==="string"?r.latestVersion:void 0,notifiedVersion:typeof r.notifiedVersion==="string"?r.notifiedVersion:void 0,notifiedAt:o(r.notifiedAt)}}async function pc(e,t){return jm(Bm(e),{recursive:!0,mode:448}).then(()=>Gm(e,JSON.stringify(t),{mode:384})).then(()=>!0).catch(()=>!1)}import{dirname as Wm,join as Jm,resolve as ko}from"node:path";var gc="CC Safety Net Config",Ym="═".repeat(gc.length),Zm="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Xm=new Set(["rule.json","rule.lock","cache"]);function hc(e={}){try{return Qm(e)}catch(t){if(t instanceof N)return console.error(t.message),1;throw t}}function Qm(e){let t=e.cwd??process.cwd(),n=e.userConfigPath??Q(),r=e.projectConfigPath??X(t),o=e.legacyUserConfigPath??gt(),i=e.legacyProjectConfigPath??Ko(t),s=ko(t,nr),a=Wm(n),l=ee({cwd:t,userConfigPath:n,projectConfigPath:r}),c=ee({cwd:t}),d=k(l.userScope,n),p=k(l.projectScope,r),m=e.legacyUserConfigPath?pt(e.legacyUserConfigPath,"user policy"):k(c.userScope,o),u=e.legacyProjectConfigPath?pt(e.legacyProjectConfigPath,"project policy"):k(c.projectScope,i),h=!1,f=!1,L=[],v=[],w=eg(k(c.projectScope,s));if(ng(),x(d)!==null){let y=le(d);if(y.errors.push(...ce(n,Ve({userConfigDir:a}),{userConfigDir:a},l.userScope)),L.push({scope:"User",path:n,result:y,schema:"rules",sourceDisplayMap:Ce(n,l.userScope),target:d}),y.errors.length>0)h=!0}if(x(m)!==null)if(f=!0,x(d)!==null)v.push(Tn("user","cleanup"));else{let y=Vn(m);if(L.push({scope:"User",path:o,result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:m}),v.push(Tn("user",y.errors.length>0?"fix-or-delete":"migrate")),y.errors.length>0)h=!0}if(x(p)!==null){let y=le(p);if(y.errors.push(...ce(r,ze(r),{userConfigDir:a},l.projectScope)),L.push({scope:"Project",path:ko(r),result:y,schema:"rules",sourceDisplayMap:Ce(r,l.projectScope),target:p}),y.errors.length>0)h=!0;if(x(u)!==null)f=!0,v.push(Tn("project","cleanup"))}else if(x(u)!==null){f=!0,h=!0;let y=Vn(u);L.push({scope:"Project",path:ko(i),result:y,schema:"legacy",sourceDisplayMap:new Map,inactive:!0,target:u}),v.push(Tn("project",y.errors.length>0?"fix-or-delete":"migrate"))}if(w?.result.errors.length)h=!0;if(L.length===0&&!w)return console.log(`
|
|
238
|
+
No config files found. Using built-in rules only.`),0;for(let y of L)if(y.inactive)og(y.scope,y.path,y.result,y.sourceDisplayMap);else if(y.result.errors.length>0)ig(y.scope,y.path,y.result.errors);else{if(y.schema==="rules"&&lg(y.target))console.log(`
|
|
239
|
+
Added $schema to ${y.scope.toLowerCase()} config.`);rg(y.scope,y.path,y.result,y.schema,y.sourceDisplayMap)}for(let y of v)console.error(`
|
|
240
|
+
${g.red(y)}`);if(w)if(w.result.errors.length>0)ag(w.path,w.result.errors);else sg(w.path,w.result);if(h)return console.error(`
|
|
241
|
+
Config validation failed.`),1;return console.log(f?`
|
|
242
242
|
Configs valid with warnings.`:`
|
|
243
|
-
All configs valid.`),0}function
|
|
244
|
-
✓ ${
|
|
245
|
-
✗ Legacy ${
|
|
246
|
-
✓ GitHub source rules: ${
|
|
247
|
-
✗ ${
|
|
248
|
-
`))}import{spawn as
|
|
249
|
-
return POSIX path of (choose folder with prompt "${
|
|
243
|
+
All configs valid.`),0}function Tn(e,t){let n=`legacy ${e} config`;if(t==="cleanup")return`Warning: Legacy ${e} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(t==="migrate")return`Warning: Legacy ${e} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${e} config is no longer supported. Fix or delete the ${n}, then run \`npx -y cc-safety-net rule migrate\`.`}function eg(e){if(Be(e)===null)return null;let t=tg(e);if(t.ruleNames.size===0&&t.errors.length===0)return null;return{path:e.path,result:t}}function tg(e){let t=[],n=new Set,r=(Be(e)??[]).filter((o)=>!Xm.has(o.name)).sort((o,i)=>o.name.localeCompare(i.name));if(r.length===0)return{errors:t,ruleNames:n};for(let o of r){if(!mt.test(o.name)){t.push(`rulebook directory names must match ${mt}: ${o.name}`);continue}if(o.kind!=="directory"){t.push(`${o.name} must be a rulebook directory`);continue}let i=k(e.scope,Jm(e.path,o.name,"rulebook.json")),s=x(i);if(s===null){t.push(`${o.name}/rulebook.json is required`);continue}try{let a;try{a=JSON.parse(s)}catch{t.push(`${o.name}/rulebook.json: invalid JSON`);continue}let l=mc(a);if(l.name!==o.name){t.push(`rulebook name "${l.name}" must match folder "${o.name}"`);continue}n.add(o.name)}catch(a){t.push(a instanceof Error?`${o.name}/rulebook.json: ${a.message}`:`${o.name}/rulebook.json: ${String(a)}`)}}return{errors:t,ruleNames:n}}function ng(){console.log(gc),console.log(Ym)}function rg(e,t,n,r,o){if(console.log(`
|
|
244
|
+
✓ ${e} config: ${t}`),console.log(` Schema: ${r==="rules"?"rulebook sources":"legacy inline rules"}`),n.ruleNames.size>0){console.log(` ${r==="rules"?"Sources":"Rules"}:`);let i=1;for(let s of n.ruleNames)console.log(` ${i}. ${o.get(s)??s}`),i++}else console.log(` ${r==="rules"?"Sources":"Rules"}: (none)`)}function og(e,t,n,r){if(console.error(`
|
|
245
|
+
✗ Legacy ${e.toLowerCase()} config: ${t}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),n.errors.length>0){console.error(" Errors:");let o=1;for(let i of n.errors)for(let s of i.split("; "))console.error(` ${o}. ${s}`),o++;return}if(n.ruleNames.size>0){console.error(" Rules:");let o=1;for(let i of n.ruleNames)console.error(` ${o}. ${r.get(i)??i}`),o++;return}console.error(" Rules: (none)")}function ig(e,t,n){yc(`${e} config`,t,n)}function sg(e,t){console.log(`
|
|
246
|
+
✓ GitHub source rules: ${e}`),console.log(" Rulebooks:");let n=1;for(let r of t.ruleNames)console.log(` ${n}. ${r}`),n++}function ag(e,t){yc("GitHub source rules",e,t)}function yc(e,t,n){console.error(`
|
|
247
|
+
✗ ${e}: ${t}`),console.error(" Errors:");let r=1;for(let o of n)for(let i of o.split("; "))console.error(` ${r}. ${i}`),r++}function lg(e){try{let t=x(e);if(t===null)return!1;let n=JSON.parse(t);if(n.$schema)return!1;return xe(e,JSON.stringify({$schema:Zm,...n},null,2)),!0}catch(t){if(t instanceof N)throw t;return!1}}var Lc=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),dg=new Set(["add","remove","list"]);async function bc(e){try{return await ug(e)}catch(t){if(t instanceof N)return console.error(t.message),1;throw t}}async function ug(e){let t=fg(e),n=t.help?pg(t.positionals):null;if(n)return vn(n),0;if(t.errors.length>0){for(let s of t.errors)console.error(s);return 1}let r=t.positionals[0];if(!r)return vn(Ze,console.error),1;let o=t.positionals[1],i={global:t.global,check:t.check};if(r==="init"){let s=J(i),a=s.configDir;hg(s.configTarget),vc(k(s.filesystemScope,Bt({...i,cacheConfigDir:a})));let l=cg(a,"example-rules","rulebook.json"),c=k(s.filesystemScope,l);if(t.example&&x(c)===null)ir(c,"example-rules");let d=await qe(i);return Mt(d,"Rule config initialized."),d.ok?0:1}if(r==="add"){if(!o)return console.error("rule add requires a source"),1;let s=await Qn(o,i);return Mt(s,`Added rulebook source: ${o}`),s.ok?0:1}if(r==="remove"){if(!o)return console.error("rule remove requires a source"),1;let s=await tr(o,{...i,deleteSource:t.deleteSource});return Mt(s,`Removed rulebook source: ${o}`),s.ok?0:1}if(r==="update"||r==="sync"){let s=await qe({...i,only:r==="update"?o:void 0});return Mt(s,t.check?"Rule config checked.":"Rule config synced."),s.ok?0:1}if(r==="list"){let s=Le(),a=ee({});return ac(s,{user:Ce(s.userConfigPath,a.userScope),project:Ce(s.projectConfigPath,a.projectScope)}),s.errors.length>0?1:0}if(r==="wrapper")return yg(t);if(r==="migrate")return uc({cleanup:t.cleanup,cwd:process.cwd()});if(r==="doc"){console.log(ic);let s=await fc();if(s)console.error(s);return 0}if(r==="verify")return hc();return 1}function pg(e){if(e.length===0)return Ze;let t=Ze.subcommands.filter((r)=>r.usage.split(" ")[0]===e[0]);if(t.length===0)return null;if(e.length===1&&t.length>1)return{name:`rule ${e[0]}`,description:`Subcommands of rule ${e[0]}`,usage:`rule ${e[0]} <subcommand>`,subcommands:t,options:[]};let n=e.length===1?t[0]:t.find((r)=>r.usage.split(" ")[1]===e[1]);if(!n)return null;return{name:`rule ${e[0]}`,description:n.description,usage:`rule ${n.usage}`,options:[]}}function fg(e){let t=T({label:"rule",booleans:{global:["-g","--global"],check:["--check"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},positionals:"list"},e),n={...t.flags,help:t.help,positionals:t.positionals,errors:t.errors};return mg(n),n}function mg(e){let[t]=e.positionals;if(t&&!Lc.has(t))e.errors.push(`Unknown rule subcommand: ${t}`);if(e.deleteSource&&t!=="remove")if(t&&Lc.has(t))e.errors.push(`Unknown option for rule ${t}: --delete-source`);else e.errors.push("--delete-source is only valid with 'rule remove'");if(e.cleanup&&t!=="migrate")e.errors.push(In(t,"--cleanup"));if(e.example&&t!=="init")e.errors.push(In(t,"--example"));if(t==="migrate"){if(e.global)e.errors.push(In(t,"--global"));if(e.check)e.errors.push(In(t,"--check"));if(e.positionals.length>1)e.errors.push(`Unexpected rule migrate argument: ${e.positionals[1]}`)}else if(t==="wrapper")gg(e);else if(e.positionals.length>2)e.errors.push(`Unexpected rule argument: ${e.positionals[2]}`);if(t==="list"&&e.global)e.errors.push("Unknown option for rule list: --global")}function In(e,t){return e?`Unknown option for rule ${e}: ${t}`:`Unknown option for rule: ${t}`}function gg(e){let t=e.positionals[1],n=e.positionals[2];if(!t){e.errors.push("rule wrapper requires add, remove, or list");return}if(!dg.has(t)){e.errors.push(`Unknown rule wrapper action: ${t}`);return}if(t==="list"){if(n)e.errors.push(`Unexpected rule wrapper argument: ${n}`);return}if(!n){e.errors.push(`rule wrapper ${t} requires a command`);return}if(e.positionals.length>3)e.errors.push(`Unexpected rule wrapper argument: ${e.positionals[3]}`)}function hg(e){if(x(e)===null){or(e);return}let t=Y(e);if(!t.config)return;Z(e,{version:1,rules:t.config.rules,overrides:t.config.overrides??{},transparent_wrappers:t.config.transparent_wrappers??[]})}async function yg(e){let t=e.positionals[1],n=e.positionals[2],r=J({global:e.global}).configTarget;if(t==="list"){let a=Y(r);if(a.errors.length>0){for(let l of a.errors)console.error(l);return 1}return Lg(a.config?.transparent_wrappers??[]),0}if(!n||!ar.test(n))return console.error("transparent wrapper must match command pattern"),1;if(cr(n))return console.error(`reserved command "${n}" cannot be a wrapper`),1;let o=Y(r);if(o.errors.length>0){for(let a of o.errors)console.error(a);return 1}let i=o.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},s=t==="add"?[...new Set([...i.transparent_wrappers??[],n])]:(i.transparent_wrappers??[]).filter((a)=>a!==n);return Z(r,{version:1,rules:i.rules,overrides:i.overrides??{},transparent_wrappers:s}),console.log(t==="add"?`Added transparent wrapper: ${n}`:`Removed transparent wrapper: ${n}`),0}function Lg(e){if(e.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${e.length}):`);for(let t of e)console.log(` - ${t}`)}import{homedir as wc}from"node:os";import{existsSync as vg,readFileSync as bg}from"node:fs";import{homedir as wg}from"node:os";import{join as xg}from"node:path";async function Cg(e){if(e.isTTY)return null;return(await hr(e).catch(()=>null))?.trim()||null}function kg(){if(process.env.CLAUDE_SETTINGS_PATH)return process.env.CLAUDE_SETTINGS_PATH;return xg(wg(),".claude","settings.json")}function So(){let e=kg();if(!vg(e))return!1;try{let t=bg(e,"utf-8"),n=JSON.parse(t);if(!n.enabledPlugins)return!1;let r="cc-safety-net@cc-marketplace";if(!(r in n.enabledPlugins))return!1;return n.enabledPlugins[r]===!0}catch(t){if(Lt(S.debug))console.error(`CC Safety Net debug: failed to read Claude settings: ${e}: ${t instanceof Error?t.message:String(t)}`);return!1}}async function Do(e=process.stdin){let t=So(),n;if(!t)n="\uD83D\uDEE1️ CC Safety Net ❌";else{let o=B({cwd:process.cwd()}),i=o.policy,s=de(i),a=Object.values(De(i,s.capabilities)).some((c)=>c.changesInherited);n=`\uD83D\uDEE1️ CC Safety Net ${{standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[a?"custom":s.effectiveLevel]}${s.worktreeMode?"\uD83C\uDF33":""}${o.state==="degraded"?"⚠️":""}`}let r=await Cg(e);if(r&&!r.startsWith("{"))console.log(`${r} | ${n}`);else console.log(n)}function xc(){let e=B({cwd:process.cwd()}),t=e.policy,n=de(t),r=!!process.env.NO_COLOR||!process.stdout.isTTY,o=Math.min(process.stdout.columns||80,100),i=r?"ok":"✔",s=r?"OFF":"✘",a=(u,h)=>{let f=` ${u.padEnd(13)}${h}`;return(f.length>o?`${f.slice(0,o-1)}…`:f).replaceAll(s,g.red(s))},l=Object.values(De(t,n.capabilities)).some((u)=>u.changesInherited),c=vt(),d={ready:g.green,degraded:g.yellow}[e.state],p=[...So()?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...e.diagnostics],m=r?"-":"·";console.log([`${r?"":"\uD83D\uDEE1️ "}CC Safety Net — ${d(e.state)}`,"",a("Protection",`destructive ${t.destructiveCommandProtectionEnabled?i:s} secrets ${t.secretProtection.enabled?i:s}`),a("Level",l?`${n.effectiveLevel} (customised)`:n.effectiveLevel),a("Rules",t.rules.length===0?"none active":`${t.rules.length} active`),a("Policy",c.startsWith(wc())?`~${c.slice(wc().length)}`:c),...n.worktreeMode?[a("Worktree","relaxations active")]:[],"",...p.length===0?[" Everything configured is active."]:[" Not active",...p.flatMap((u)=>Ln(u," ",o-6).map((h,f)=>f===0?` ${m} ${h}`:h)),""," Full report: cc-safety-net doctor"]].join(`
|
|
248
|
+
`))}import{spawn as Uc}from"node:child_process";import{randomBytes as $g}from"node:crypto";import{createServer as Ng}from"node:http";import{Writable as Fg}from"node:stream";import{homedir as Sg}from"node:os";var _n=500;function Dg(e){let t=e.filter((o)=>o.decision!=="allow"),n=e.filter((o)=>o.decision==="allow"),r=Math.min(t.length,Math.max(_n-n.length,Math.ceil(_n/2)));return[...t.slice(0,r),...n.slice(0,_n-r)]}function Cc(e,t=ue()){if(t)ke(t);let n=(f)=>new Date(f.getFullYear(),f.getMonth(),f.getDate()).getTime(),r=n(new Date),o=new Date(r);o.setDate(o.getDate()-(e-1));let i=o.getTime(),s=[],a={count:0};for(let f of t?ye(t,a):[])for(let L of ut(f,a)){if(!L||typeof L.ts!=="string"||typeof L.command!=="string")continue;let v=new Date(L.ts).getTime();if(!Number.isFinite(v))continue;if(v>=i)s.push(L)}s.sort((f,L)=>new Date(L.ts).getTime()-new Date(f.ts).getTime());let l=Array.from({length:e},()=>0),c=Array.from({length:e},()=>0),d={},p={},m={},u=0,h=0;for(let f of s){let L=f.agent||"unknown";d[L]=(d[L]??0)+1;let v=Math.round((r-n(new Date(f.ts)))/86400000),w=e-1-v,y=v>=0&&v<e;if(y)c[w]=(c[w]??0)+1;if(f.decision!=="allow"){if(u++,f.ruleId)p[f.ruleId]=(p[f.ruleId]??0)+1;let C=He(f.segment||f.command);if(C)m[C]=(m[C]??0)+1;if(f.failureStage)h++;if(y)l[w]=(l[w]??0)+1}}return{days:e,logsDir:t,homeDir:Sg(),totalInWindow:s.length,truncated:s.length>_n,unreadable:a.count,counts:{blocked:u,allowed:s.length-u,agents:d,blockedByDay:l,analyzedByDay:c,rules:p,commands:m,errors:h},entries:Dg(s).sort((f,L)=>new Date(L.ts).getTime()-new Date(f.ts).getTime())}}import{spawn as Rg}from"node:child_process";import{existsSync as kc,statSync as Ag}from"node:fs";import{delimiter as Eg,join as Pg}from"node:path";var Tg=120000,On="Choose the project folder",Ig=`try
|
|
249
|
+
return POSIX path of (choose folder with prompt "${On}")
|
|
250
250
|
on error number -128
|
|
251
251
|
return ""
|
|
252
|
-
end try`,
|
|
252
|
+
end try`,_g=`Add-Type -AssemblyName System.Windows.Forms
|
|
253
253
|
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
254
|
-
$dialog.Description = '${
|
|
255
|
-
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,
|
|
254
|
+
$dialog.Description = '${On}'
|
|
255
|
+
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Sc=[{binary:"zenity",args:["--file-selection","--directory",`--title=${On}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",On]}],Dc=(e,t)=>(t.PATH??"").split(Eg).some((n)=>n.length>0&&kc(Pg(n,e)));function Rc(e,t){if(e==="darwin"||e==="win32")return!0;if(e!=="linux")return!1;if(!t.DISPLAY&&!t.WAYLAND_DISPLAY)return!1;return Sc.some((n)=>Dc(n.binary,t))}function Og(e,t){if(e==="darwin")return{cmd:"osascript",args:["-e",Ig]};if(e==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",_g]};let n=Sc.find((r)=>Dc(r.binary,t));return n?{cmd:n.binary,args:n.args}:null}function Ac(e=process.platform,t=process.env){let n=Og(e,t);if(!n)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((r)=>{let o=Rg(n.cmd,n.args,{env:t,stdio:["ignore","pipe","pipe"]}),i="",s=!1,a=(c)=>{if(s)return;s=!0,clearTimeout(l),r(c)},l=setTimeout(()=>{o.kill(),a({error:"The folder dialog timed out"})},Tg);o.stdout.on("data",(c)=>{i+=c.toString()}),o.on("error",()=>a({error:`Could not open the folder dialog (${n.cmd})`})),o.on("close",()=>{let c=i.trim().replace(/\/+$/,"");if(!c)return a({cancelled:!0});if(!kc(c)||!Ag(c).isDirectory())return a({error:"That selection is not a folder on disk"});a({path:c})})})}var Ec=`<!doctype html>
|
|
256
256
|
<html lang="en">
|
|
257
257
|
<head>
|
|
258
258
|
<meta charset="utf-8">
|
|
@@ -3361,7 +3361,6 @@ var requestJson = async (path, init) => {
|
|
|
3361
3361
|
var errorText = (result) => result.error ?? (Array.isArray(result.data?.errors) && result.data.errors.length ? result.data.errors.join(\`
|
|
3362
3362
|
\`) : null) ?? result.data?.error ?? \`Request failed (status \${result.status}).\`;
|
|
3363
3363
|
var isWriteSuccess = (result) => result.ok && !(Array.isArray(result.data?.errors) && result.data.errors.length > 0);
|
|
3364
|
-
var isPolicyState = (value) => !!value && typeof value === "object" && !!value.policy && typeof value.policy === "object" && !!value.policy.safety && !!value.policy.workflow && !!value.policy.secret_protection && Array.isArray(value.destructiveCommandRules) && Array.isArray(value.secretPatterns) && (value.preview === null || value.preview && typeof value.preview === "object") && Array.isArray(value.errors);
|
|
3365
3364
|
var qs = (id) => document.getElementById(id);
|
|
3366
3365
|
var setDetailStatus = (text, kind = "") => {
|
|
3367
3366
|
qs("status").textContent = text;
|
|
@@ -3484,7 +3483,6 @@ var applyView = () => {
|
|
|
3484
3483
|
if (view === "rules" && rulesData && pendingRuleFocus)
|
|
3485
3484
|
renderRules();
|
|
3486
3485
|
};
|
|
3487
|
-
var isActivityFeed = (value) => !!value && typeof value === "object" && Array.isArray(value.entries) && !!value.counts && typeof value.counts === "object";
|
|
3488
3486
|
var agentLabels = integrationDisplayNames;
|
|
3489
3487
|
var tierCountHtml = (segments) => {
|
|
3490
3488
|
const parts = segments.filter(([count]) => count > 0).map(([count, label, tone]) => tone ? \`<span class="count-\${tone}">\${count} \${label}</span>\` : \`\${count} \${label}\`);
|
|
@@ -3590,9 +3588,10 @@ var renderTopList = (containerId, counts, className, dataAttr) => {
|
|
|
3590
3588
|
const top = Object.entries(counts).sort((a, b) => b[1] - a[1]).slice(0, 5);
|
|
3591
3589
|
qs(containerId).innerHTML = top.length === 0 ? '<p class="empty">No blocked commands in this window.</p>' : top.map(([key, count]) => \`<button type="button" class="\${className}" \${dataAttr}="\${escapeHtml(key)}"><code class="rule-id">\${escapeHtml(key)}</code><span class="chip-count">\${count.toLocaleString("en-US")}</span></button>\`).join("");
|
|
3592
3590
|
};
|
|
3593
|
-
var
|
|
3591
|
+
var renderTopLists = () => {
|
|
3594
3592
|
if (!overview)
|
|
3595
3593
|
return;
|
|
3594
|
+
renderTopList("top-commands", overview.counts.commands, "top-command", "data-command");
|
|
3596
3595
|
renderTopList("top-rules", overview.counts.rules, "top-rule", "data-rule-id");
|
|
3597
3596
|
};
|
|
3598
3597
|
var findSuspects = (entries) => {
|
|
@@ -3620,15 +3619,6 @@ var jumpToActivityRule = (ruleId) => {
|
|
|
3620
3619
|
}
|
|
3621
3620
|
location.hash = "activity";
|
|
3622
3621
|
};
|
|
3623
|
-
var renderTopCommands = () => {
|
|
3624
|
-
if (!overview)
|
|
3625
|
-
return;
|
|
3626
|
-
renderTopList("top-commands", overview.counts.commands, "top-command", "data-command");
|
|
3627
|
-
};
|
|
3628
|
-
var renderTopLists = () => {
|
|
3629
|
-
renderTopCommands();
|
|
3630
|
-
renderTopRules();
|
|
3631
|
-
};
|
|
3632
3622
|
var renderGuardErrors = () => {
|
|
3633
3623
|
if (!overview)
|
|
3634
3624
|
return;
|
|
@@ -3694,7 +3684,7 @@ var renderActivityFeed = () => {
|
|
|
3694
3684
|
};
|
|
3695
3685
|
var loadOverview = async () => {
|
|
3696
3686
|
const result = await requestJson(\`/api/activity?days=\${overviewDays()}\`);
|
|
3697
|
-
if (!result.ok || !
|
|
3687
|
+
if (!result.ok || !result.data) {
|
|
3698
3688
|
const message = \`<p class="empty">Could not load activity: \${escapeHtml(errorText(result))}</p>\`;
|
|
3699
3689
|
qs("overview-window").textContent = "";
|
|
3700
3690
|
qs("overview-tiles").innerHTML = "";
|
|
@@ -3702,7 +3692,8 @@ var loadOverview = async () => {
|
|
|
3702
3692
|
qs("guard-errors").hidden = true;
|
|
3703
3693
|
return;
|
|
3704
3694
|
}
|
|
3705
|
-
|
|
3695
|
+
const feed = result.data;
|
|
3696
|
+
overview = feed;
|
|
3706
3697
|
qs("logs-path").textContent = overview.logsDir ?? "Not available";
|
|
3707
3698
|
renderOverviewActivity();
|
|
3708
3699
|
renderTopLists();
|
|
@@ -3710,13 +3701,14 @@ var loadOverview = async () => {
|
|
|
3710
3701
|
};
|
|
3711
3702
|
var loadActivity = async () => {
|
|
3712
3703
|
const result = await requestJson(\`/api/activity?days=\${activityFilters.days}\`);
|
|
3713
|
-
if (!result.ok || !
|
|
3704
|
+
if (!result.ok || !result.data) {
|
|
3714
3705
|
const message = \`<p class="empty">Could not load activity: \${escapeHtml(errorText(result))}</p>\`;
|
|
3715
3706
|
qs("activity-feed").innerHTML = message;
|
|
3716
3707
|
qs("activity-count").textContent = "";
|
|
3717
3708
|
return;
|
|
3718
3709
|
}
|
|
3719
|
-
|
|
3710
|
+
const feed = result.data;
|
|
3711
|
+
activity = feed;
|
|
3720
3712
|
suspects = findSuspects(activity.entries);
|
|
3721
3713
|
if (activityFilters.agent !== "all" && !(activityFilters.agent in activity.counts.agents)) {
|
|
3722
3714
|
activityFilters.agent = "all";
|
|
@@ -3730,20 +3722,20 @@ var loadActivity = async () => {
|
|
|
3730
3722
|
renderActivityControls();
|
|
3731
3723
|
renderActivityFeed();
|
|
3732
3724
|
};
|
|
3733
|
-
var
|
|
3734
|
-
const button = qs(
|
|
3725
|
+
var runRefresh = async (buttonId, reload) => {
|
|
3726
|
+
const button = qs(buttonId);
|
|
3735
3727
|
if (button.disabled)
|
|
3736
3728
|
return;
|
|
3737
3729
|
button.disabled = true;
|
|
3738
3730
|
button.classList.add("spinning");
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
button.disabled = false;
|
|
3731
|
+
try {
|
|
3732
|
+
await Promise.all([reload(), new Promise((resolve) => setTimeout(resolve, 600))]);
|
|
3733
|
+
} finally {
|
|
3734
|
+
button.classList.remove("spinning");
|
|
3735
|
+
button.disabled = false;
|
|
3736
|
+
}
|
|
3746
3737
|
};
|
|
3738
|
+
var refreshActivity = () => runRefresh("activity-refresh", () => Promise.all([loadOverview(), loadActivity()]));
|
|
3747
3739
|
var renderIntegrations = () => {
|
|
3748
3740
|
const loaded = integrations;
|
|
3749
3741
|
if (!loaded)
|
|
@@ -3800,17 +3792,10 @@ var loadIntegrations = async () => {
|
|
|
3800
3792
|
qs("integrations-platform").textContent = result.data.system.platform;
|
|
3801
3793
|
qs("integrations-system").hidden = false;
|
|
3802
3794
|
};
|
|
3803
|
-
var refreshIntegrations =
|
|
3804
|
-
const button = qs("integrations-refresh");
|
|
3805
|
-
if (button.disabled)
|
|
3806
|
-
return;
|
|
3807
|
-
button.disabled = true;
|
|
3808
|
-
button.classList.add("spinning");
|
|
3795
|
+
var refreshIntegrations = () => runRefresh("integrations-refresh", () => {
|
|
3809
3796
|
integrationsRequested = true;
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
button.disabled = false;
|
|
3813
|
-
};
|
|
3797
|
+
return loadIntegrations();
|
|
3798
|
+
});
|
|
3814
3799
|
var renderRules = () => {
|
|
3815
3800
|
const loaded = rulesData;
|
|
3816
3801
|
if (!loaded)
|
|
@@ -3862,17 +3847,10 @@ var loadRules = async () => {
|
|
|
3862
3847
|
rulesData = result.data;
|
|
3863
3848
|
renderRules();
|
|
3864
3849
|
};
|
|
3865
|
-
var refreshRules =
|
|
3866
|
-
const button = qs("rules-refresh");
|
|
3867
|
-
if (button.disabled)
|
|
3868
|
-
return;
|
|
3869
|
-
button.disabled = true;
|
|
3870
|
-
button.classList.add("spinning");
|
|
3850
|
+
var refreshRules = () => runRefresh("rules-refresh", () => {
|
|
3871
3851
|
rulesRequested = true;
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
button.disabled = false;
|
|
3875
|
-
};
|
|
3852
|
+
return loadRules();
|
|
3853
|
+
});
|
|
3876
3854
|
var jumpToRulesRule = (ruleId) => {
|
|
3877
3855
|
pendingRuleFocus = ruleId.replace(/^custom\\./, "");
|
|
3878
3856
|
location.hash = "rules";
|
|
@@ -4278,6 +4256,14 @@ var createPathList = (prefix, config) => {
|
|
|
4278
4256
|
};
|
|
4279
4257
|
return { render, add, remove };
|
|
4280
4258
|
};
|
|
4259
|
+
var validatePathAdditions = async (patch) => {
|
|
4260
|
+
const candidate = collectFormPolicy();
|
|
4261
|
+
patch(candidate);
|
|
4262
|
+
const result = await requestPolicyPreview(candidate);
|
|
4263
|
+
if (result.ok && result.data?.preview)
|
|
4264
|
+
return null;
|
|
4265
|
+
return errorText(result);
|
|
4266
|
+
};
|
|
4281
4267
|
var pathLists = {
|
|
4282
4268
|
"deny-paths": createPathList("deny-paths", {
|
|
4283
4269
|
getPaths: () => draftPolicy.secret_protection.deny_paths,
|
|
@@ -4286,17 +4272,9 @@ var pathLists = {
|
|
|
4286
4272
|
},
|
|
4287
4273
|
isDisabled: () => !draftPolicy.secret_protection.enabled,
|
|
4288
4274
|
itemLabel: "deny path",
|
|
4289
|
-
validateAdditions:
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
...candidate.secret_protection,
|
|
4293
|
-
deny_paths: paths
|
|
4294
|
-
};
|
|
4295
|
-
const result = await requestPolicyPreview(candidate);
|
|
4296
|
-
if (result.ok && result.data?.preview)
|
|
4297
|
-
return null;
|
|
4298
|
-
return errorText(result);
|
|
4299
|
-
}
|
|
4275
|
+
validateAdditions: (paths) => validatePathAdditions((candidate) => {
|
|
4276
|
+
candidate.secret_protection = { ...candidate.secret_protection, deny_paths: paths };
|
|
4277
|
+
})
|
|
4300
4278
|
}),
|
|
4301
4279
|
"secret-allow-paths": createPathList("secret-allow-paths", {
|
|
4302
4280
|
getPaths: () => draftPolicy.secret_protection.allow_paths,
|
|
@@ -4305,17 +4283,9 @@ var pathLists = {
|
|
|
4305
4283
|
},
|
|
4306
4284
|
isDisabled: () => !draftPolicy.secret_protection.enabled,
|
|
4307
4285
|
itemLabel: "allow path",
|
|
4308
|
-
validateAdditions:
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
...candidate.secret_protection,
|
|
4312
|
-
allow_paths: paths
|
|
4313
|
-
};
|
|
4314
|
-
const result = await requestPolicyPreview(candidate);
|
|
4315
|
-
if (result.ok && result.data?.preview)
|
|
4316
|
-
return null;
|
|
4317
|
-
return errorText(result);
|
|
4318
|
-
}
|
|
4286
|
+
validateAdditions: (paths) => validatePathAdditions((candidate) => {
|
|
4287
|
+
candidate.secret_protection = { ...candidate.secret_protection, allow_paths: paths };
|
|
4288
|
+
})
|
|
4319
4289
|
}),
|
|
4320
4290
|
"allow-paths": createPathList("allow-paths", {
|
|
4321
4291
|
getPaths: () => draftPolicy.destructive_command_protection.allow_paths,
|
|
@@ -4324,17 +4294,12 @@ var pathLists = {
|
|
|
4324
4294
|
},
|
|
4325
4295
|
isDisabled: () => !draftPolicy.destructive_command_protection.enabled,
|
|
4326
4296
|
itemLabel: "allow path",
|
|
4327
|
-
validateAdditions:
|
|
4328
|
-
const candidate = collectFormPolicy();
|
|
4297
|
+
validateAdditions: (paths) => validatePathAdditions((candidate) => {
|
|
4329
4298
|
candidate.destructive_command_protection = {
|
|
4330
4299
|
...candidate.destructive_command_protection,
|
|
4331
4300
|
allow_paths: paths
|
|
4332
4301
|
};
|
|
4333
|
-
|
|
4334
|
-
if (result.ok && result.data?.preview)
|
|
4335
|
-
return null;
|
|
4336
|
-
return errorText(result);
|
|
4337
|
-
}
|
|
4302
|
+
})
|
|
4338
4303
|
})
|
|
4339
4304
|
};
|
|
4340
4305
|
var pathListFor = (name) => name === "deny-paths" || name === "allow-paths" || name === "secret-allow-paths" ? pathLists[name] : null;
|
|
@@ -4713,7 +4678,7 @@ var restoreDraft = () => {
|
|
|
4713
4678
|
};
|
|
4714
4679
|
async function load() {
|
|
4715
4680
|
const result = await requestJson("/api/policy");
|
|
4716
|
-
if (!
|
|
4681
|
+
if (!result.ok || !result.data) {
|
|
4717
4682
|
setAppStatus("Load failed", "error");
|
|
4718
4683
|
setDetailStatus(\`Error: Could not load policy: \${errorText(result)}\`, "error");
|
|
4719
4684
|
return false;
|
|
@@ -4773,6 +4738,22 @@ document.addEventListener("paste", (event) => {
|
|
|
4773
4738
|
list.add(\`\${input.value}
|
|
4774
4739
|
\${text}\`);
|
|
4775
4740
|
});
|
|
4741
|
+
var writePolicy = async (path, body, failureStatus) => {
|
|
4742
|
+
const result = await requestJson(path, { method: "POST", body });
|
|
4743
|
+
if (isWriteSuccess(result))
|
|
4744
|
+
return result;
|
|
4745
|
+
setAppStatus(failureStatus, "error");
|
|
4746
|
+
setDetailStatus(\`Error: \${errorText(result)}\`, "error");
|
|
4747
|
+
return null;
|
|
4748
|
+
};
|
|
4749
|
+
var reloadAfterWrite = async () => {
|
|
4750
|
+
sessionStorage.removeItem("cc-safety-net-draft");
|
|
4751
|
+
if (!await load())
|
|
4752
|
+
return false;
|
|
4753
|
+
dirty = false;
|
|
4754
|
+
setDetailStatus("");
|
|
4755
|
+
return true;
|
|
4756
|
+
};
|
|
4776
4757
|
var saveRetentionDays = async (days) => {
|
|
4777
4758
|
const saved = state;
|
|
4778
4759
|
if (!saved)
|
|
@@ -4805,14 +4786,8 @@ var saveRetentionDays = async (days) => {
|
|
|
4805
4786
|
await runExclusive("Saving...", async () => {
|
|
4806
4787
|
const policy = clonePolicy(saved.policy);
|
|
4807
4788
|
policy.audit.retention_days = days;
|
|
4808
|
-
|
|
4809
|
-
method: "POST",
|
|
4810
|
-
body: JSON.stringify(policy)
|
|
4811
|
-
});
|
|
4812
|
-
if (!isWriteSuccess(result)) {
|
|
4789
|
+
if (!await writePolicy("/api/policy", JSON.stringify(policy), "Save failed")) {
|
|
4813
4790
|
qs("retention-days").value = String(current);
|
|
4814
|
-
setAppStatus("Save failed", "error");
|
|
4815
|
-
setDetailStatus(\`Error: \${errorText(result)}\`, "error");
|
|
4816
4791
|
return;
|
|
4817
4792
|
}
|
|
4818
4793
|
if (!await load())
|
|
@@ -5228,22 +5203,11 @@ qs("save").onclick = () => {
|
|
|
5228
5203
|
}
|
|
5229
5204
|
const policy = collectFormPolicy();
|
|
5230
5205
|
runExclusive("Saving...", async () => {
|
|
5231
|
-
const result = await
|
|
5232
|
-
|
|
5233
|
-
body: JSON.stringify(policy)
|
|
5234
|
-
});
|
|
5235
|
-
if (!isWriteSuccess(result)) {
|
|
5236
|
-
setAppStatus("Save failed", "error");
|
|
5237
|
-
setDetailStatus(\`Error: \${errorText(result)}\`, "error");
|
|
5206
|
+
const result = await writePolicy("/api/policy", JSON.stringify(policy), "Save failed");
|
|
5207
|
+
if (!result)
|
|
5238
5208
|
return;
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
sessionStorage.removeItem("cc-safety-net-draft");
|
|
5242
|
-
if (await load()) {
|
|
5243
|
-
dirty = false;
|
|
5244
|
-
setAppStatus(\`Saved \${savedPath}.\`, "ok");
|
|
5245
|
-
setDetailStatus("");
|
|
5246
|
-
}
|
|
5209
|
+
if (await reloadAfterWrite())
|
|
5210
|
+
setAppStatus(\`Saved \${result.data.path}.\`, "ok");
|
|
5247
5211
|
});
|
|
5248
5212
|
};
|
|
5249
5213
|
qs("repair").onclick = async () => {
|
|
@@ -5267,19 +5231,11 @@ qs("repair").onclick = async () => {
|
|
|
5267
5231
|
return;
|
|
5268
5232
|
}
|
|
5269
5233
|
runExclusive("Repairing...", async () => {
|
|
5270
|
-
const result = await
|
|
5271
|
-
if (!
|
|
5272
|
-
setAppStatus("Repair failed", "error");
|
|
5273
|
-
setDetailStatus(\`Error: \${errorText(result)}\`, "error");
|
|
5234
|
+
const result = await writePolicy("/api/repair", "{}", "Repair failed");
|
|
5235
|
+
if (!result)
|
|
5274
5236
|
return;
|
|
5275
|
-
|
|
5276
|
-
|
|
5277
|
-
sessionStorage.removeItem("cc-safety-net-draft");
|
|
5278
|
-
if (await load()) {
|
|
5279
|
-
dirty = false;
|
|
5280
|
-
setAppStatus(\`Repaired \${repairedPath}.\`, "ok");
|
|
5281
|
-
setDetailStatus("");
|
|
5282
|
-
}
|
|
5237
|
+
if (await reloadAfterWrite())
|
|
5238
|
+
setAppStatus(\`Repaired \${result.data.path}.\`, "ok");
|
|
5283
5239
|
});
|
|
5284
5240
|
};
|
|
5285
5241
|
qs("reset").onclick = async () => {
|
|
@@ -5297,19 +5253,11 @@ qs("reset").onclick = async () => {
|
|
|
5297
5253
|
return;
|
|
5298
5254
|
}
|
|
5299
5255
|
runExclusive("Resetting...", async () => {
|
|
5300
|
-
const result = await
|
|
5301
|
-
if (!
|
|
5302
|
-
setAppStatus("Reset failed", "error");
|
|
5303
|
-
setDetailStatus(\`Error: \${errorText(result)}\`, "error");
|
|
5256
|
+
const result = await writePolicy("/api/reset", "{}", "Reset failed");
|
|
5257
|
+
if (!result)
|
|
5304
5258
|
return;
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
sessionStorage.removeItem("cc-safety-net-draft");
|
|
5308
|
-
if (await load()) {
|
|
5309
|
-
dirty = false;
|
|
5310
|
-
setAppStatus(\`Reset \${resetPath} to defaults.\`, "ok");
|
|
5311
|
-
setDetailStatus("");
|
|
5312
|
-
}
|
|
5259
|
+
if (await reloadAfterWrite())
|
|
5260
|
+
setAppStatus(\`Reset \${result.data.path} to defaults.\`, "ok");
|
|
5313
5261
|
});
|
|
5314
5262
|
};
|
|
5315
5263
|
setRawCopyCopied(false);
|
|
@@ -5361,5 +5309,5 @@ load().then((loaded) => {
|
|
|
5361
5309
|
</script>
|
|
5362
5310
|
</body>
|
|
5363
5311
|
</html>
|
|
5364
|
-
`;var
|
|
5365
|
-
`)}}finally{console.log=s,console.error=
|
|
5312
|
+
`;var Pc='<script id="ccsn-data" type="application/json">';function Tc(e){return Ec.replace(Pc,()=>Pc+JSON.stringify({token:e}).replaceAll("<","\\u003c"))}var Nn="kenryu42/cc-safety-net",Hg=`https://github.com/${Nn}`,Eo=1e4,Mg=7;async function Gc(e,t={}){let n=T({label:"gui",booleans:{noOpen:["--no-open"]}},e),r=t.log??console.log,o=t.error??console.error;if(n.errors.length>0){for(let s of n.errors)o(s);return o("Usage: cc-safety-net gui [--no-open]"),1}let i=await jg(t);if(r(`CC Safety Net policy GUI: ${i.url}`),!n.flags.noOpen)try{await(t.openBrowser??Wg)(i.url)}catch(s){o(`Failed to open browser: ${s instanceof Error?s.message:String(s)}`),o(`Open this URL manually: ${i.url}`)}if(t.keepAlive===!1)return await i.close(),0;return await Kg(i),0}async function jg(e={}){let t=$g(24).toString("base64url"),n=Ng((i,s)=>{Ug(i,s,t,e)});await new Promise((i,s)=>{n.once("error",s),n.listen(0,"127.0.0.1",()=>{n.off("error",s),i()})});let o=`http://127.0.0.1:${n.address().port}`;return{origin:o,token:t,url:`${o}/?token=${encodeURIComponent(t)}`,close:()=>zg(n)}}async function Ug(e,t,n,r){let o=new URL(e.url??"/","http://127.0.0.1");if(e.method==="GET"&&o.pathname==="/favicon.ico"){t.writeHead(204,{"cache-control":"no-store"}),t.end();return}if(!qg(e,o,n)){D(t,403,{error:"Forbidden"});return}if(e.method==="GET"&&o.pathname==="/"){Vg(t,Tc(n));return}if(e.method==="GET"&&o.pathname==="/api/policy"){let i=$c(r);D(t,200,{...i,configState:bt(B(r)),destructiveCommandRules:ht,secretPatterns:_c,version:P(),preview:i.errors.length>0?null:Fc(i.policy)});return}if(e.method==="POST"&&o.pathname==="/api/policy/preview"){let i=await $n(e);if(!i.ok){D(t,400,{errors:[i.error]});return}let s=Nc(i.value);D(t,s.errors.length>0?400:200,s);return}if(e.method==="POST"&&o.pathname==="/api/policy/explain"){let i=await $n(e);if(!i.ok){D(t,400,{errors:[i.error]});return}let s=i.value;if(s===null||typeof s.command!=="string"){D(t,400,{errors:["command must be a string"]});return}let a=fr(s.policy);if(a.length>0){D(t,400,{errors:a});return}D(t,200,Gg(s.command,s.policy,r));return}if(e.method==="POST"&&o.pathname==="/api/policy"){let i=await $n(e);if(!i.ok){D(t,400,{errors:[i.error]});return}let s=Ro(i.value,r);D(t,s.errors.length>0?400:200,s);return}if(e.method==="POST"&&o.pathname==="/api/reset"){D(t,200,Ro(Oc,r));return}if(e.method==="POST"&&o.pathname==="/api/repair"){D(t,200,Hc(r));return}if(e.method==="GET"&&o.pathname==="/api/activity"){let i=Je(r),s=Bg(o.searchParams.get("days"),i);if(s===null){D(t,400,{error:`days must be an integer between 1 and ${i}`});return}D(t,200,Cc(s,r.activityLogsDir));return}if(e.method==="POST"&&o.pathname==="/api/rules/choose-directory"){D(t,200,await Ac());return}if(e.method==="GET"&&o.pathname==="/api/rules"){let i=Le(r),s=new Map(i.rules.map((a)=>[a.name,a]));D(t,200,{projectPath:r.cwd??process.cwd(),canPickDirectory:Rc(process.platform,process.env),rulebooks:i.rulebooks.map((a)=>({source:a.source,spec:a.spec,name:a.name,version:a.version,rules:a.rules.flatMap((l)=>{let c=s.get(l);if(!c)return[];return[{name:c.name,command:c.command,subcommand:c.subcommand,block_args:c.block_args,reason:c.reason}]})})),errors:i.errors,warnings:i.warnings});return}if(e.method==="GET"&&o.pathname==="/api/star/context"){D(t,200,await(r.fetchStarContext??(()=>Qg({logsDir:r.activityLogsDir})))());return}if(e.method==="POST"&&o.pathname==="/api/star"){let i=await(r.starRepo??Jg)();D(t,200,i.ok?{ok:!0}:{ok:!1,fallbackUrl:Hg});return}if(e.method==="GET"&&o.pathname==="/api/integrations"){D(t,200,await(r.fetchIntegrations??Yg)());return}if(e.method==="GET"&&o.pathname==="/api/health"){D(t,200,await(r.fetchHealth??Zg)());return}if(e.method==="POST"&&(o.pathname==="/api/install"||o.pathname==="/api/uninstall")){let i=await $n(e);if(!i.ok){D(t,400,{errors:[i.error]});return}let s=i.value?.target;if(typeof s!=="string"||!se.some((l)=>l.target===s)){D(t,400,{error:"unknown target"});return}let a=o.pathname==="/api/install"?"install":"uninstall";D(t,200,await(r.runIntegration??Xg)(a,s));return}D(t,404,{error:"Not found"})}function Gg(e,t,n){let r=wn(t),o=B(n),i=yt({rules:o.policy.rules,transparentWrappers:o.policy.transparentWrappers,safety:jc(r.safety),worktreeMode:r.workflow.worktree_mode,destructiveCommandProtectionEnabled:r.destructive_command_protection.enabled,destructiveCommandRuleOverrides:r.destructive_command_protection.overrides,destructiveCommandAllowPaths:r.destructive_command_protection.allow_paths,secretProtection:{enabled:r.secret_protection.enabled,disabledRules:Mc(r.secret_protection.overrides),denyPaths:r.secret_protection.deny_paths,allowPaths:r.secret_protection.allow_paths}});return We(e,{policySnapshot:i,cwd:n.cwd,userConfigDir:n.userConfigDir})}function Bg(e,t){if(e===null)return Math.min(Mg,t);let n=Number(e);if(!Number.isInteger(n)||n<1||n>t)return null;return n}function qg(e,t,n){if(t.searchParams.get("token")!==n)return!1;if(e.method!=="POST")return!0;return e.headers["x-cc-safety-net-token"]===n}async function $n(e){let t=[];for await(let n of e)t.push(n);try{return{ok:!0,value:JSON.parse(Buffer.concat(t).toString("utf-8")||"{}")}}catch(n){return{ok:!1,error:`Invalid JSON: ${n instanceof Error?n.message:String(n)}`}}}function Vg(e,t){e.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),e.end(t)}function D(e,t,n){e.writeHead(t,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),e.end(JSON.stringify(n))}function zg(e){return new Promise((t,n)=>{e.close((r)=>r?n(r):t())})}function Kg(e){return new Promise((t)=>{let n=()=>{process.off("SIGINT",r),process.off("SIGTERM",r)},r=()=>{n(),e.close().then(t)};process.once("SIGINT",r),process.once("SIGTERM",r)})}function Wg(e){let t=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",n=process.platform==="win32"?["/c","start","",e]:[e];return new Promise((r,o)=>{let i=Uc(t,n,{detached:!0,stdio:"ignore"}),s=(l)=>{i.off("spawn",a),o(l)},a=()=>{i.off("error",s),i.unref(),r()};i.once("error",s),i.once("spawn",a)})}async function Jg(e="gh",t=Eo){return{ok:await Ao(e,["api","-X","PUT",`/user/starred/${Nn}`],t)===0}}async function Yg(e={}){let t=await St(e.fetcher),n=Bc(t,e.homeDir);return{targets:V.map((r)=>{let o=n.find((i)=>i.platform===r.id);return{target:r.id,label:R(r.id),version:t.versions[r.id]??null,status:o?.configured?"active":o?.detected?"disabled":o?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:t.version,nodeVersion:t.nodeVersion,platform:t.platform}}}function Bc(e,t){return it(process.cwd(),{homeDir:t,ampPluginListOutput:e.ampPluginListOutput,codexPluginListOutput:e.codexPluginListOutput,copilotCliVersion:e.versions["copilot-cli"]})}async function Zg(e={}){let[t,n]=await Promise.all([St(e.fetcher),(e.checkUpdates??Qe)()]);return{hooks:Bc(t,e.homeDir).filter((r)=>r.detected).map((r)=>({platform:r.platform,label:R(r.platform),configured:r.configured})),update:{currentVersion:n.currentVersion,latestVersion:n.latestVersion??null,updateAvailable:n.updateAvailable}}}var Ic=Promise.resolve();function Xg(e,t,n={}){let r=async()=>{let i=[],s=console.log,a=console.error;console.log=(...l)=>i.push(l.map(String).join(" ")),console.error=console.log;try{return{ok:await Ht(e,[],{selectTargets:async()=>[t],output:new Fg({write(c,d,p){i.push(String(c).replace(/\n$/,"")),p()}}),...n})===0,output:i.join(`
|
|
5313
|
+
`)}}finally{console.log=s,console.error=a}},o=Ic.then(r);return Ic=o.then(()=>{return},()=>{return}),o}async function Qg(e={}){let[t,n,r]=await Promise.all([e1(e.command),t1(e.fetchRepo),Promise.resolve(Yt(Je(),e.logsDir).totalBlocked)]);return{starred:t,starCount:n,blockedTotal:r}}async function e1(e="gh",t=Eo){if(await Ao(e,["auth","status"],t)!==0)return null;let n=await Ao(e,["api",`/user/starred/${Nn}`],t);if(n===0)return!0;if(n===null)return null;return!1}function Ao(e,t,n){return new Promise((r)=>{let o=Uc(e,t,{stdio:"ignore",windowsHide:!0}),i=!1,s,a=(l)=>{if(i)return;if(i=!0,s)clearTimeout(s);r(l)};o.once("error",()=>a(null)),o.once("close",a),s=setTimeout(()=>{o.kill(),a(null)},n)})}async function t1(e=fetch){try{let t=await e(`https://api.github.com/repos/${Nn}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Eo)});if(!t.ok)return null;let n=await t.json();return typeof n.stargazers_count==="number"?n.stargazers_count:null}catch{return null}}function n1(e){if(e[0]!=="help")return!1;let t=e[1];if(!t)ao(),process.exit(0);if($t(t))process.exit(0);console.error(`Unknown command: ${t}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var r1={hook:async(e)=>{let t=Zi(e);if(t){await t.run();return}console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),$t("hook",console.error),process.exit(1)},install:async(e)=>{process.exit(await Ht("install",e))},update:async(e)=>{process.exit(await xo(e))},uninstall:async(e)=>{process.exit(await Ht("uninstall",e))},rule:async(e)=>{process.exit(await bc(e))},status:async(e)=>{if(ae(T({label:"status"},e).errors))process.exit(1);xc()},statusline:async(e)=>{let t=T({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},e);if(t.errors.length===0&&t.flags.claudeCode){await Do();return}if(ae(t.errors),!t.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");$t("statusline",console.error),process.exit(1)},doctor:async(e)=>{let t=no(e);if(!t)process.exit(1);let n=await Xa({json:t.json,skipUpdateCheck:t.skipUpdateCheck});process.exit(n)},logs:async(e)=>{process.exit(await bi(e))},gui:async(e)=>{process.exit(await Gc(e))},explain:async(e)=>{process.exit(await il(e))}};async function o1(){let e=process.argv.slice(2),t=T({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},e);if(n1(e))return;let n=e[0],r=n?Jt(n):void 0;if(t.help&&r&&r.name!=="rule")$t(r.name),process.exit(0);if(!n||t.help&&!r)ao(),process.exit(0);if(t.flags.version)ll(),process.exit(0);if(r){await r1[r.name](e.slice(1));return}let o=Xi(n);if(o){await o.run();return}if(n==="--statusline"){await Do();return}console.error(n.startsWith("-")?`Unknown option: ${n}`:`Unknown command: ${n}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}o1().catch((e)=>{console.error("CC Safety Net error:",e),process.exit(1)});
|