cc-safety-net 2.4.9 → 2.4.10

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/cli.js CHANGED
@@ -1,10 +1,10 @@
1
- import{a,s,ke,Ue,k,Ze,Ge,c,o,He,R,L,ve,Qe,f,We,d,r,v,i,re,n,g,le,N,tt,nt,l,ue,de,rt,A,q,oe,S,ot,F,b,Se,M,u,K,Be,ze,I,w,T,pe,fe,Le,it,m,e,Te,we,Ve,qe,ie,Ce,se,_e,J,j,Pe,me,U,Ke,G,Y,Z,ae,Je,Ye,C,H,Ae,Oe,De,E,Ne,Ee,Fe,h,t,X,ge,y,x,_,st,Me,$e,p,W}from"./chunks/index-fvtsm6ez.js";import{ee,B,je,O,D}from"./chunks/index-g2gqgqzy.js";var Ud=["-h","--help"];function xt(P,V){let z=Object.entries(P.booleans??{}),Q=Object.entries(P.values??{}),te=Object.entries(P.lists??{}),ne=Object.fromEntries(z.map(([Xe])=>[Xe,!1])),ce={},he=Object.fromEntries(te.map(([Xe])=>[Xe,[]])),ye=[],be=[],xe=!1,Ie=-1;for(let[Xe,et]of V.entries()){if(Xe<=Ie)continue;if(et==="--"){ye.push(...V.slice(Xe+1));break}if(Ud.includes(et)){xe=!0;continue}let Re=z.find(([,lt])=>lt.includes(et));if(Re){ne[Re[0]]=!0;continue}let at=Q.find(([,lt])=>lt.includes(et));if(at){let lt=V[Xe+1];if(lt===void 0||lt.startsWith("-")){be.push(`${et} requires a value`);continue}ce[at[0]]=lt,Ie=Xe+1;continue}let ct=te.find(([,lt])=>lt.includes(et));if(ct){let lt=V.slice(Xe+1),pt=lt.findIndex((gt)=>gt.startsWith("-")),mt=lt.slice(0,pt===-1?lt.length:pt);if(mt.length===0){be.push(`${et} requires at least one value`);continue}he[ct[0]]=[...he[ct[0]]??[],...mt],Ie=Xe+mt.length;continue}if(et.startsWith("-")){be.push(`Unknown option for ${P.label}: ${et}`);continue}if(P.positionals==="tail"){ye.push(...V.slice(Xe));break}ye.push(et)}if(P.positionals!=="list"&&P.positionals!=="tail")be.push(...ye.map((Xe)=>`Unexpected argument for ${P.label}: ${Xe}`));return{flags:ne,values:ce,lists:he,positionals:ye,help:xe,errors:be}}function Ht(P){for(let V of P)console.error(V);return P.length>0}import{readdirSync as Wd,statSync as Ni,unlinkSync as Kd}from"node:fs";import{basename as Mi,dirname as Yd,isAbsolute as Zd,join as Xd,relative as Qd,resolve as eu,sep as tu}from"node:path";var Oi=(P)=>{let V=Date.now()-new Date(P).getTime();if(!Number.isFinite(V))return"";let z=Math.floor(V/60000),Q=Math.floor(z/60),te=Math.floor(Q/24);if(te>0)return`${te}d ago`;if(Q>0)return`${Q}h ago`;if(z>0)return`${z}m ago`;return"just now"},Qr=(P)=>{let V=(P??"").trim().split(/\s+/).filter((te)=>te&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(te)),z=V[0]?.split("/").pop();if(!z)return null;let Q=V[1];return Q&&/^[a-z][a-z0-9-]*$/.test(Q)?`${z} ${Q}`:z};function Fi(P){let V=(te)=>`${te.sessionId}
1
+ import{a,s,ke,Ue,k,Ze,Ge,c,o,He,R,L,ve,Qe,f,We,d,r,v,i,re,n,g,le,N,tt,nt,l,ue,de,rt,A,q,oe,S,ot,F,b,Se,M,u,K,Be,ze,I,w,T,pe,fe,Le,it,m,e,Te,we,Ve,qe,ie,Ce,se,_e,J,j,Pe,me,U,Ke,G,Y,Z,ae,Je,Ye,C,H,Ae,Oe,De,E,Ne,Ee,Fe,h,t,X,ge,y,x,_,st,Me,$e,p,W}from"./chunks/index-fvtsm6ez.js";import{ee,B,je,O,D}from"./chunks/index-8z99qpz1.js";var Ud=["-h","--help"];function xt(P,V){let z=Object.entries(P.booleans??{}),Q=Object.entries(P.values??{}),te=Object.entries(P.lists??{}),ne=Object.fromEntries(z.map(([Xe])=>[Xe,!1])),ce={},he=Object.fromEntries(te.map(([Xe])=>[Xe,[]])),ye=[],be=[],xe=!1,Ie=-1;for(let[Xe,et]of V.entries()){if(Xe<=Ie)continue;if(et==="--"){ye.push(...V.slice(Xe+1));break}if(Ud.includes(et)){xe=!0;continue}let Re=z.find(([,lt])=>lt.includes(et));if(Re){ne[Re[0]]=!0;continue}let at=Q.find(([,lt])=>lt.includes(et));if(at){let lt=V[Xe+1];if(lt===void 0||lt.startsWith("-")){be.push(`${et} requires a value`);continue}ce[at[0]]=lt,Ie=Xe+1;continue}let ct=te.find(([,lt])=>lt.includes(et));if(ct){let lt=V.slice(Xe+1),pt=lt.findIndex((gt)=>gt.startsWith("-")),mt=lt.slice(0,pt===-1?lt.length:pt);if(mt.length===0){be.push(`${et} requires at least one value`);continue}he[ct[0]]=[...he[ct[0]]??[],...mt],Ie=Xe+mt.length;continue}if(et.startsWith("-")){be.push(`Unknown option for ${P.label}: ${et}`);continue}if(P.positionals==="tail"){ye.push(...V.slice(Xe));break}ye.push(et)}if(P.positionals!=="list"&&P.positionals!=="tail")be.push(...ye.map((Xe)=>`Unexpected argument for ${P.label}: ${Xe}`));return{flags:ne,values:ce,lists:he,positionals:ye,help:xe,errors:be}}function Ht(P){for(let V of P)console.error(V);return P.length>0}import{readdirSync as Wd,statSync as Ni,unlinkSync as Kd}from"node:fs";import{basename as Mi,dirname as Yd,isAbsolute as Zd,join as Xd,relative as Qd,resolve as eu,sep as tu}from"node:path";var Oi=(P)=>{let V=Date.now()-new Date(P).getTime();if(!Number.isFinite(V))return"";let z=Math.floor(V/60000),Q=Math.floor(z/60),te=Math.floor(Q/24);if(te>0)return`${te}d ago`;if(Q>0)return`${Q}h ago`;if(z>0)return`${z}m ago`;return"just now"},Qr=(P)=>{let V=(P??"").trim().split(/\s+/).filter((te)=>te&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(te)),z=V[0]?.split("/").pop();if(!z)return null;let Q=V[1];return Q&&/^[a-z][a-z0-9-]*$/.test(Q)?`${z} ${Q}`:z};function Fi(P){let V=(te)=>`${te.sessionId}
2
2
  ${Qr(te.segment||te.command)}`,z=P.filter((te)=>te.decision!=="allow"),Q=z.filter((te)=>te.sessionId).reduce((te,ne)=>te.set(V(ne),(te.get(V(ne))??0)+1),new Map);return new Set(z.filter((te)=>te.failureStage||(Q.get(V(te))??0)>=2))}import{existsSync as Gd,readdirSync as Bd,readFileSync as qd}from"node:fs";import{join as Vd}from"node:path";function Yt(P,V){try{return Bd(P,{withFileTypes:!0,encoding:"utf8"}).flatMap((z)=>{let Q=Vd(P,z.name);if(z.isDirectory())return Yt(Q,V);if(z.name.endsWith(".jsonl"))return[Q];return[]})}catch{if(V&&Gd(P))V.count++;return[]}}var zd=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Jd(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let V=P;if(typeof V.ts!=="string"||typeof V.command!=="string")return!1;return zd.every((z)=>V[z]===void 0||typeof V[z]==="string")}function pn(P,V){try{return qd(P,"utf-8").split(`
3
3
  `).filter(Boolean).flatMap((z)=>{try{let Q=JSON.parse(z);if(!Jd(Q)){if(V)V.count++;return[]}return[Q]}catch{if(V)V.count++;return[]}})}catch{if(V)V.count++;return[]}}function Ct(P){return Array.from(P,(V)=>{let z=V.charCodeAt(0);if(z<=31||z>=127&&z<=159)return`\\x${z.toString(16).padStart(2,"0")}`;return V}).join("")}function nu(P,V){let z=ee(P),Q=xt({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"]}},V);if(Ht(Q.errors))return null;if(Q.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(Q.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let te=Q.values.limit===void 0?20:ji(Q.values.limit);if(te===null)return console.error("--limit must be a positive number"),null;let ne=Q.values.since===void 0?Math.min(30,z):ji(Q.values.since);if(ne===null||ne>z)return console.error(`--since must be a positive number of days no greater than ${z}`),null;let ce={limit:te,limitExplicit:Q.values.limit!==void 0,since:ne,sinceExplicit:Q.values.since!==void 0,all:Q.flags.all,json:Q.flags.json,suspect:Q.flags.suspect,pruneLegacy:Q.flags.pruneLegacy,dryRun:Q.flags.dryRun,id:Q.values.id,agent:Q.values.agent,rule:Q.values.rule,session:Q.values.session,project:Q.values.project===void 0?void 0:eu(Q.values.project)};if(ce.id&&(ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.sinceExplicit||ce.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(ce.pruneLegacy&&(ce.id!==void 0||ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.all||ce.sinceExplicit||ce.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(ce.dryRun&&!ce.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return ce}async function Hi(P,V,z={}){let Q=nu(P,V);if(!Q)return 1;let te=z.logsDir??O(P);if(Q.pruneLegacy)return ru(te,Q.json,Q.dryRun);if(!te)return console.log(Q.json?"[]":Q.id?`No retained audit log entry found for id ${Ct(Q.id)}.`:"No audit log entries found."),0;B(P,te);let ne={count:0},ce=Yt(te,ne).flatMap((Ie)=>pn(Ie,ne).map((Xe)=>({entry:Xe,file:Ie})));if(ne.count>0)console.error(`warning: ${ne.count} audit log ${ne.count===1?"source":"sources"} could not be read; these results are incomplete`);if(Q.id)return au(ce,Q,z.timeZone);let he=Date.now()-Q.since*24*60*60*1000,ye=ce.filter((Ie)=>lu(Ie,Q,te,he)),be=Q.suspect?Fi(ye.map((Ie)=>Ie.entry)):null,xe=(be?ye.filter((Ie)=>be.has(Ie.entry)):ye).sort((Ie,Xe)=>Date.parse(Xe.entry.ts)-Date.parse(Ie.entry.ts)).slice(0,Q.limit);if(Q.json)return console.log(JSON.stringify(xe.map((Ie)=>Ie.entry),null,2)),0;if(xe.length===0)return console.log("No audit log entries found."),0;for(let Ie of xe)console.log(uu(Ie.entry,z.timeZone));return 0}function ru(P,V,z){let Q=P?iu(P).map((he)=>Xd(P,he)):[];if(z)return ou(Q,V);let te=[],ne=0,ce=0;for(let he of Q){let ye=Ni(he,{throwIfNoEntry:!1})?.size??0,be=su(he);if(be){te.push(`${Mi(he)}: ${be}`);continue}ne++,ce+=ye}if(V)return console.log(JSON.stringify({removedFiles:ne,removedBytes:ce,failedFiles:te.length})),te.length===0?0:1;console.log(ne===0&&te.length===0?"No legacy audit log files found.":`Removed ${ne} legacy audit log ${ne===1?"file":"files"} (${Ui(ce)}).`);for(let he of te)console.error(`Could not remove ${Ct(he)}`);if(console.log("Nested v2 audit logs were not changed."),ne>0)console.log("This deletion cannot be undone.");return te.length===0?0:1}function ou(P,V){let z=P.reduce((Q,te)=>Q+(Ni(te,{throwIfNoEntry:!1})?.size??0),0);if(V)return console.log(JSON.stringify({dryRun:!0,files:P.length,bytes:z})),0;if(console.log(P.length===0?"No legacy audit log files found.":`Would remove ${P.length} legacy audit log ${P.length===1?"file":"files"} (${Ui(z)}).`),console.log("Nested v2 audit logs are not included."),P.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function iu(P){try{return Wd(P,{withFileTypes:!0}).filter((V)=>V.isFile()&&V.name.endsWith(".jsonl")).map((V)=>V.name)}catch{return[]}}function su(P){try{return Kd(P),null}catch(V){return V instanceof Error?V.message:String(V)}}function Ui(P){let V=["B","KiB","MiB","GiB"],z=Math.min(Math.floor(Math.log2(Math.max(P,1))/10),V.length-1);return`${Math.round(P/1024**z*10)/10} ${V[z]}`}function au(P,V,z){let Q=P.filter((ne)=>ne.entry.id===V.id);if(Q.length>1)return console.error(`Multiple audit log entries found for id ${Ct(V.id??"")}.`),1;if(V.json)return console.log(JSON.stringify(Q.map((ne)=>ne.entry),null,2)),0;let te=Q[0];if(!te)return console.log(`No retained audit log entry found for id ${Ct(V.id??"")}.`),0;return console.log(pu(te.entry,z)),0}function lu(P,V,z,Q){if(!V.all&&P.entry.decision==="allow")return!1;if(Date.parse(P.entry.ts)<Q)return!1;if(V.agent!==void 0&&P.entry.agent!==V.agent)return!1;if(V.rule!==void 0&&P.entry.ruleId!==V.rule)return!1;if(V.session!==void 0&&!cu(P,z,V.session))return!1;if(V.project!==void 0&&!du(P.entry.cwd,V.project))return!1;return!0}function cu(P,V,z){if(P.entry.sessionId===z)return!0;return Yd(P.file)===V&&Mi(P.file,".jsonl")===z}function du(P,V){if(!P)return!1;let z=Qd(V,P);return z!==".."&&!z.startsWith(`..${tu}`)&&!Zd(z)}function uu(P,V){let z=Ct(P.id??"-"),Q=Ct(P.decision??"deny"),te=P.cwd?` [${Ct(P.cwd)}]`:"",ne=P.segment||P.command,ce=ne===P.command?"":"↳ ",he=ne.length>50?`${ne.slice(0,50)}…`:ne;return`${z.padEnd(16)} ${Ct(Gi(P.ts,V))} ${Q.padEnd(5)} ${Ct(P.agent??"-").padEnd(15)} ${Ct(P.ruleId??"-").padEnd(20)} ${ce}${Ct(he)}${te}`}function pu(P,V){let z=(te)=>Ct(te===void 0||te===null||te===""?"-":te),Q=P.shape?`${P.agent??"-"} (shape: ${P.shape})`:P.agent??"-";return[`id: ${z(P.id)}`,`ts: ${z(Gi(P.ts,V))}`,`decision: ${z(P.decision)}`,`agent: ${z(Q)}`,`level: ${z(P.level)}`,`tool: ${z(P.toolName)}`,`rule: ${z(P.ruleId)}`,`intent: ${z(P.intent)}`,`stage: ${z(P.failureStage)}`,`error: ${z(P.errorCode)}`,`session: ${z(P.sessionId)}`,`cwd: ${z(P.cwd)}`,`version: ${z(P.v)}`,`truncated: ${z(P.truncated===!0?"yes":void 0)}`,`reason: ${z(P.reason)}`,`command: ${z(P.command)}`,`segment: ${z(P.segment)}`].join(`
4
- `)}function Gi(P,V){let z=new Date(P);if(Number.isNaN(z.getTime()))return P;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:V}).format(z)}function ji(P){let V=Number(P);return Number.isFinite(V)&&V>0?V:null}var Bi={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 qi={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 Vi={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"]};var Yn=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Zn=Yn.slice().sort((P,V)=>P.doctorOrder-V.doctorOrder).map((P)=>P.id),Sn=Yn.filter((P)=>("runtime"in P)).slice().sort((P,V)=>P.runtime.order-V.runtime.order).map((P)=>({id:P.id,displayName:"displayName"in P.runtime?P.runtime.displayName:P.displayName,flags:P.runtime.flags,legacyFlags:"legacyFlags"in P.runtime?P.runtime.legacyFlags:[],description:P.runtime.description,legacyTopLevelFlags:P.runtime.legacyTopLevelFlags})),$t=Yn.slice().sort((P,V)=>P.install.order-V.install.order).map((P)=>({id:P.id,...P.install})).map(({order:P,...V})=>V),fu=Object.fromEntries(Yn.map((P)=>[P.id,P.displayName]));function bt(P){return fu[P]}var mu=Sn.map((P)=>({flags:P.flags.join(", "),description:P.description})),gu=Sn.flatMap((P)=>P.flags.map((V)=>`cc-safety-net hook ${V}`)),zi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...mu,{flags:"-h, --help",description:"Show this help"}],examples:gu};var Ji={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Install ${bt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...$t.map((P)=>`cc-safety-net install ${P.flag}`)]},Wi={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Uninstall ${bt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...$t.map((P)=>`cc-safety-net uninstall ${P.flag}`)]},Ki={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 Yi={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var Xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],fn={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var Zi={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 Xi={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 Qn=[Zi,Bi,Yi,qi,fn,Xn,Ji,Ki,Wi,zi,Vi,Xi];function hu(P){return P.aliases??[]}function er(P){let V=P.toLowerCase();return Qn.find((z)=>z.name.toLowerCase()===V||hu(z).some((Q)=>Q.toLowerCase()===V))}import{basename as yu}from"node:path";function tr(P,V=7,z=O(P)){let Q=Date.now()-V*24*60*60*1000,te=[],ne=new Set,ce=0,he,ye,be,xe;if(z)B(P,z);let Ie={count:0},Xe=z?Yt(z,Ie):[];for(let Re of Xe)for(let at of pn(Re,Ie)){if(at.decision==="allow")continue;let ct=new Date(at.ts).getTime();if(ct>=Q){if(ce++,ne.add(at.sessionId??yu(Re,".jsonl")),ye===void 0||ct<=ye)he=at.ts,ye=ct;if(xe===void 0||ct>xe)be=at.ts,xe=ct;vu(te,at,ct)}}let et=te.map((Re)=>({timestamp:Re.ts,command:Re.command,reason:Re.reason,relativeTime:Oi(new Date(Re.ts))}));return{totalBlocked:ce,sessionCount:ne.size,recentEntries:et,oldestEntry:he,newestEntry:be,unreadable:Ie.count}}function vu(P,V,z){let Q=P.findIndex((te)=>z>new Date(te.ts).getTime());if(Q===-1){if(P.length<3)P.push(V);return}if(P.splice(Q,0,V),P.length>3)P.pop()}import{dirname as Au}from"node:path";import{dirname as bu,join as Lu,resolve as wu}from"node:path";var ku="config.json";function Rt(P,V,z,Q){g(xu(P),`${JSON.stringify(V,null,2)}
5
- `,z,Q)}function xu(P){return typeof P==="string"?re(P):P}function ro(P){return{errors:ie(Su(P),": "," "),ruleNames:new Set(_e(P).map((V)=>V.toLowerCase()))}}var Cu="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",Qi="must match pattern (letters, numbers, hyphens, underscores)";function Su(P){if(!es(P))return[e([],"Config must be an object")];return[...P.version===1?[]:[e(["version"],"must be 1")],...Ru(P.rules)]}function Ru(P){if(P===void 0)return[];if(!Array.isArray(P))return[e(["rules"],"must be an array")];return[...P.flatMap((V,z)=>es(V)?Pu(V,["rules",z]):[e(["rules",z],"must be an object")]),...Te(P)]}function Pu(P,V){return[...no(P.name,[...V,"name"],"required string",l,Cu),...no(P.command,[...V,"command"],"required string",w,Qi),...P.subcommand===void 0?[]:no(P.subcommand,[...V,"subcommand"],"must be a string if provided",w,Qi),...Eu(P.block_args,[...V,"block_args"]),...Du(P.reason,[...V,"reason"]),...P.intent===void 0||Ce(P.intent)?[]:[e([...V,"intent"],we)]]}function no(P,V,z,Q,te){if(typeof P!=="string")return[e(V,z)];return Q.test(P)?[]:[e(V,te)]}function Eu(P,V){if(!Array.isArray(P))return[e(V,"required array")];if(P.length===0)return[e(V,"must have at least one element")];return P.flatMap((z,Q)=>{if(typeof z!=="string")return[e([...V,Q],"must be a string")];return z===""?[e([...V,Q],"must not be empty")]:[]})}function Du(P,V){if(typeof P!=="string")return[e(V,"required string")];if(P==="")return[e(V,"must not be empty")];return P.length>T?[e(V,`must be at most ${T} characters`)]:[]}function es(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function oo(P){let V=ts(P);if(!V.ok)return V.result;return ro(V.parsed)}function ts(P){let V=[],z=new Set;try{let Q=typeof P==="string"?re(P):P,te=n(Q);if(te===null)return V.push(`File not found: ${Q.path}`),{ok:!1,result:{errors:V,ruleNames:z}};if(!te.trim())return V.push("Config file is empty"),{ok:!1,result:{errors:V,ruleNames:z}};return{ok:!0,parsed:JSON.parse(te)}}catch(Q){if(Q instanceof r)return V.push(Q.message),{ok:!1,result:{errors:V,ruleNames:z}};let te=Q instanceof Error?Q.message:String(Q);return V.push(Q instanceof SyntaxError?"Invalid JSON":te),{ok:!1,result:{errors:V,ruleNames:z}}}}function ns(P){return wu(P,".safety-net.json")}function Jt(P){let V=ts(P);if(!V.ok)return V.result;let z=Ve(V.parsed);return{errors:z.errors,ruleNames:z.sources}}function nr(P,V={}){return Lu(bu(Se(P,V)),ku)}function rs(P,V,z){let Q;try{if(n(V)===null)return{path:P,exists:!1,valid:!1,ruleCount:0};Q=Jt(V),Q.errors.push(...j(P,z))}catch(te){if(!(te instanceof r))throw te;Q={errors:[te.message],ruleNames:new Set}}return{path:P,exists:!0,valid:Q.errors.length===0,ruleCount:Q.ruleNames.size,...Q.errors.length>0?{errors:Q.errors}:{}}}function _u(P,V){return{source:V,name:P.name,command:P.command,subcommand:P.subcommand,blockArgs:[...P.block_args],reason:P.reason}}function os(P,V){let z=M(P),Q=F(V),te=Au(z),ne=J(P,{cwd:V,userConfigPath:z,projectConfigPath:Q,userConfigDir:te}),ce=K(P,{cwd:V,userConfigPath:z,projectConfigPath:Q,userConfigDir:te}),he=new Map(ne.rulebooks.flatMap((ye)=>ye.rules.map((be)=>[be,ye.source])));return{userConfig:rs(z,ce.userConfigTarget,ce.userScope),projectConfig:rs(Q,ce.projectConfigTarget,ce.projectScope),effectiveRules:ne.rules.map((ye)=>_u(ye,he.get(ye.name)??"project"))}}var Tu=[{flag:o.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:o.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:o.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:o.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:o.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:o.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:o.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:o.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function is(P){return[...Tu.map((V)=>({name:V.flag.name,value:ve(V.flag,P.env),isSet:Qe(V.flag,P.env),legacyName:V.flag.legacyName,legacyValue:V.flag.legacyName?P.env.get(V.flag.legacyName):void 0,legacyIsSet:V.flag.legacyName?P.env.get(V.flag.legacyName)!==void 0:void 0,description:V.description,defaultBehavior:V.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:P.env.get("CC_SAFETY_NET_HOME"),isSet:P.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ss={error:0,warning:1,info:2},$u=["policy","config","audit"];function Iu(P){return P.map((V)=>{if(V==="ownership")return"is not owned by the current user";if(V==="permissions")return"has unsafe permissions";if(V==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var Ou=[{derive:(P)=>P.hooks.length>0&&P.hooks.every((V)=>!V.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:(P)=>P.hooks.filter((V)=>V.inspectionStatus==="failed").map((V)=>{let z=bt(V.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${z} inspection failed`,detail:`Doctor could not verify the ${z} integration configuration.`,fixHint:`Correct the reported ${z} configuration error, then run \`cc-safety-net doctor\` again.`,integration:V.platform}})},{derive:(P)=>P.userConfig.exists&&!P.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:P.userConfig.path}]:[]},{derive:(P)=>P.projectConfig.exists&&!P.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:P.projectConfig.path}]:[]},{derive:(P)=>P.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${P.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(P)=>P.v2Leftovers&&P.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${P.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(P)=>{let V=P.environment.find((z)=>z.name==="CC_SAFETY_NET_AUDIT_SCOPE");return He(V?.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."}]:[]}},...$u.map((P)=>({derive:(V)=>V.posture.directories.filter((z)=>z.kind===P&&z.status==="unsafe").map((z)=>({checkId:`posture.${P}-directory-unsafe`,severity:"error",title:`${P[0]?.toUpperCase()}${P.slice(1)} directory is unsafe`,detail:`The ${P} directory ${Iu(z.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...z.path?{path:z.path}:{}}))})),{derive:(P)=>{let V=[...P.effectiveSafety.weakenedRuleOverrides].sort();return V.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: ${V.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${V.join(", ")}.`}]:[]}}];function as(P){return Ou.flatMap((V,z)=>V.derive(P).map((Q,te)=>({finding:Q,catalogOrder:z,occurrence:te}))).sort((V,z)=>ss[V.finding.severity]-ss[z.finding.severity]||V.catalogOrder-z.catalogOrder||V.occurrence-z.occurrence).map((V)=>V.finding)}function Ut(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Fu=(P)=>Ut()?`\x1B[32m${P}\x1B[0m`:P,ju=(P)=>Ut()?`\x1B[33m${P}\x1B[0m`:P,Nu=(P)=>Ut()?`\x1B[34m${P}\x1B[0m`:P,Mu=(P)=>Ut()?`\x1B[36m${P}\x1B[0m`:P,Hu=(P)=>Ut()?`\x1B[31m${P}\x1B[0m`:P,Uu=(P)=>Ut()?`\x1B[2m${P}\x1B[0m`:P,Gu=(P)=>Ut()?`\x1B[1m${P}\x1B[0m`:P,dt={green:Fu,yellow:ju,blue:Nu,cyan:Mu,red:Hu,dim:Uu,bold:Gu},Bu="\x1B[0m",qu=[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 Vu(P){let V=P;return()=>(V=(V*1664525+1013904223)%4294967296,V/4294967296)}function zu(P){let V=[...qu],z=Vu(P);for(let Q=V.length-1;Q>0;Q--){let te=Math.floor(z()*(Q+1)),ne=V[Q];V[Q]=V[te],V[te]=ne}return V}function Ju(P,V=0){if(!Ut())return"";let z=zu(V);return`\x1B[38;5;${z[P%z.length]}m`}function ls(P,V,z=0){if(!Ut())return`"${P}"`;return`${Ju(V,z)}"${P}"${Bu}`}function rr(P){return P==="default"?"built-in default":`${P} policy`}var Wu=new RegExp("\x1B\\[[0-9;]*m","g"),io=(P)=>P.replace(Wu,"").length;function Zt(P){let V=(P.headers??P.rows[0]??[]).map((ce,he)=>{let ye=Math.max(...P.rows.map((be)=>io(be[he]??"")));return Math.max(io(ce),ye)}),z=(ce,he)=>ce+" ".repeat(Math.max(0,he-io(ce))),Q=(ce,he)=>he[0]+V.map((ye)=>ce.repeat(ye+2)).join(he[1])+he[2],te=(ce)=>`│ ${ce.map((he,ye)=>z(he,V[ye]??0)).join(" │ ")} │`,ne=P.headers?[` ${te(P.headers)}`,` ${Q("─",["├","┼","┤"])}`]:[];return[` ${Q("─",["┌","┬","┐"])}`,...ne,...P.rows.map((ce)=>` ${te(ce)}`),` ${Q("─",["└","┴","┘"])}`].join(`
6
- `)}function cs(P){let V=[];V.push("Hook Integration"),V.push(Ku(P));let z=[],Q=[];for(let te of P){let ne=bt(te.platform);if(te.errors&&te.errors.length>0)for(let ce of te.errors)if(te.configured)z.push({platform:ne,message:ce});else Q.push({platform:ne,message:ce})}for(let te of z)V.push(` Warning (${te.platform}): ${te.message}`);for(let te of Q)V.push(dt.red(` Error (${te.platform}): ${te.message}`));return V.join(`
7
- `)}function Ku(P){let V=["Platform","Discovery","Configuration","Inspection"],z=P.map((Q)=>{let te=bt(Q.platform);if(Q.inspectionStatus==="not-inspected"){let ye=dt.dim("Not inspected");return[te,ye,ye,ye]}let ne=Q.detected?dt.green("Detected"):Q.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not detected"),ce=Q.configured?dt.green("Configured"):Q.detected?dt.yellow("Not configured"):Q.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not applicable"),he=Q.inspectionStatus==="verified"?dt.green("Verified"):Q.inspectionStatus==="failed"?dt.red("Failed"):dt.dim("Not applicable");return[te,ne,ce,he]});return Zt({headers:V,rows:z})}function ds(P){let z=["Guard Engine Verification",` Synthetic self-test: ${P.failed>0?dt.red(`${P.passed}/${P.total} FAIL`):dt.green(`${P.passed}/${P.total} passed`)}`],Q=P.results.filter((te)=>!te.passed);if(Q.length>0){z.push(""),z.push(dt.red(" Failures:"));for(let te of Q)z.push(dt.red(` • ${te.description}`)),z.push(dt.red(` expected ${te.expected}, got ${te.actual}`))}return z.join(`
4
+ `)}function Gi(P,V){let z=new Date(P);if(Number.isNaN(z.getTime()))return P;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:V}).format(z)}function ji(P){let V=Number(P);return Number.isFinite(V)&&V>0?V:null}var Bi={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 qi={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 Vi={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"]};var Yn=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Zn=Yn.slice().sort((P,V)=>P.doctorOrder-V.doctorOrder).map((P)=>P.id),Sn=Yn.filter((P)=>("runtime"in P)).slice().sort((P,V)=>P.runtime.order-V.runtime.order).map((P)=>({id:P.id,displayName:"displayName"in P.runtime?P.runtime.displayName:P.displayName,flags:P.runtime.flags,legacyFlags:"legacyFlags"in P.runtime?P.runtime.legacyFlags:[],description:P.runtime.description,legacyTopLevelFlags:P.runtime.legacyTopLevelFlags})),$t=Yn.slice().sort((P,V)=>P.install.order-V.install.order).map((P)=>({id:P.id,...P.install})).map(({order:P,...V})=>V),fu=Object.fromEntries(Yn.map((P)=>[P.id,P.displayName]));function vt(P){return fu[P]}var mu=Sn.map((P)=>({flags:P.flags.join(", "),description:P.description})),gu=Sn.flatMap((P)=>P.flags.map((V)=>`cc-safety-net hook ${V}`)),zi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...mu,{flags:"-h, --help",description:"Show this help"}],examples:gu};var Ji={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Install ${vt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...$t.map((P)=>`cc-safety-net install ${P.flag}`)]},Wi={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Uninstall ${vt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...$t.map((P)=>`cc-safety-net uninstall ${P.flag}`)]},Ki={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 Yi={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var Xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],fn={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var Zi={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 Xi={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 Qn=[Zi,Bi,Yi,qi,fn,Xn,Ji,Ki,Wi,zi,Vi,Xi];function hu(P){return P.aliases??[]}function er(P){let V=P.toLowerCase();return Qn.find((z)=>z.name.toLowerCase()===V||hu(z).some((Q)=>Q.toLowerCase()===V))}import{basename as yu}from"node:path";function tr(P,V=7,z=O(P)){let Q=Date.now()-V*24*60*60*1000,te=[],ne=new Set,ce=0,he,ye,be,xe;if(z)B(P,z);let Ie={count:0},Xe=z?Yt(z,Ie):[];for(let Re of Xe)for(let at of pn(Re,Ie)){if(at.decision==="allow")continue;let ct=new Date(at.ts).getTime();if(ct>=Q){if(ce++,ne.add(at.sessionId??yu(Re,".jsonl")),ye===void 0||ct<=ye)he=at.ts,ye=ct;if(xe===void 0||ct>xe)be=at.ts,xe=ct;vu(te,at,ct)}}let et=te.map((Re)=>({timestamp:Re.ts,command:Re.command,reason:Re.reason,relativeTime:Oi(new Date(Re.ts))}));return{totalBlocked:ce,sessionCount:ne.size,recentEntries:et,oldestEntry:he,newestEntry:be,unreadable:Ie.count}}function vu(P,V,z){let Q=P.findIndex((te)=>z>new Date(te.ts).getTime());if(Q===-1){if(P.length<3)P.push(V);return}if(P.splice(Q,0,V),P.length>3)P.pop()}import{dirname as Au}from"node:path";import{dirname as bu,join as Lu,resolve as wu}from"node:path";var ku="config.json";function Rt(P,V,z,Q){g(xu(P),`${JSON.stringify(V,null,2)}
5
+ `,z,Q)}function xu(P){return typeof P==="string"?re(P):P}function ro(P){return{errors:ie(Su(P),": "," "),ruleNames:new Set(_e(P).map((V)=>V.toLowerCase()))}}var Cu="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",Qi="must match pattern (letters, numbers, hyphens, underscores)";function Su(P){if(!es(P))return[e([],"Config must be an object")];return[...P.version===1?[]:[e(["version"],"must be 1")],...Ru(P.rules)]}function Ru(P){if(P===void 0)return[];if(!Array.isArray(P))return[e(["rules"],"must be an array")];return[...P.flatMap((V,z)=>es(V)?Pu(V,["rules",z]):[e(["rules",z],"must be an object")]),...Te(P)]}function Pu(P,V){return[...no(P.name,[...V,"name"],"required string",l,Cu),...no(P.command,[...V,"command"],"required string",w,Qi),...P.subcommand===void 0?[]:no(P.subcommand,[...V,"subcommand"],"must be a string if provided",w,Qi),...Eu(P.block_args,[...V,"block_args"]),...Du(P.reason,[...V,"reason"]),...P.intent===void 0||Ce(P.intent)?[]:[e([...V,"intent"],we)]]}function no(P,V,z,Q,te){if(typeof P!=="string")return[e(V,z)];return Q.test(P)?[]:[e(V,te)]}function Eu(P,V){if(!Array.isArray(P))return[e(V,"required array")];if(P.length===0)return[e(V,"must have at least one element")];return P.flatMap((z,Q)=>{if(typeof z!=="string")return[e([...V,Q],"must be a string")];return z===""?[e([...V,Q],"must not be empty")]:[]})}function Du(P,V){if(typeof P!=="string")return[e(V,"required string")];if(P==="")return[e(V,"must not be empty")];return P.length>T?[e(V,`must be at most ${T} characters`)]:[]}function es(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function oo(P){let V=ts(P);if(!V.ok)return V.result;return ro(V.parsed)}function ts(P){let V=[],z=new Set;try{let Q=typeof P==="string"?re(P):P,te=n(Q);if(te===null)return V.push(`File not found: ${Q.path}`),{ok:!1,result:{errors:V,ruleNames:z}};if(!te.trim())return V.push("Config file is empty"),{ok:!1,result:{errors:V,ruleNames:z}};return{ok:!0,parsed:JSON.parse(te)}}catch(Q){if(Q instanceof r)return V.push(Q.message),{ok:!1,result:{errors:V,ruleNames:z}};let te=Q instanceof Error?Q.message:String(Q);return V.push(Q instanceof SyntaxError?"Invalid JSON":te),{ok:!1,result:{errors:V,ruleNames:z}}}}function ns(P){return wu(P,".safety-net.json")}function Jt(P){let V=ts(P);if(!V.ok)return V.result;let z=Ve(V.parsed);return{errors:z.errors,ruleNames:z.sources}}function nr(P,V={}){return Lu(bu(Se(P,V)),ku)}function rs(P,V,z){let Q;try{if(n(V)===null)return{path:P,exists:!1,valid:!1,ruleCount:0};Q=Jt(V),Q.errors.push(...j(P,z))}catch(te){if(!(te instanceof r))throw te;Q={errors:[te.message],ruleNames:new Set}}return{path:P,exists:!0,valid:Q.errors.length===0,ruleCount:Q.ruleNames.size,...Q.errors.length>0?{errors:Q.errors}:{}}}function _u(P,V){return{source:V,name:P.name,command:P.command,subcommand:P.subcommand,blockArgs:[...P.block_args],reason:P.reason}}function os(P,V){let z=M(P),Q=F(V),te=Au(z),ne=J(P,{cwd:V,userConfigPath:z,projectConfigPath:Q,userConfigDir:te}),ce=K(P,{cwd:V,userConfigPath:z,projectConfigPath:Q,userConfigDir:te}),he=new Map(ne.rulebooks.flatMap((ye)=>ye.rules.map((be)=>[be,ye.source])));return{userConfig:rs(z,ce.userConfigTarget,ce.userScope),projectConfig:rs(Q,ce.projectConfigTarget,ce.projectScope),effectiveRules:ne.rules.map((ye)=>_u(ye,he.get(ye.name)??"project"))}}var Tu=[{flag:o.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:o.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:o.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:o.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:o.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:o.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:o.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:o.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function is(P){return[...Tu.map((V)=>({name:V.flag.name,value:ve(V.flag,P.env),isSet:Qe(V.flag,P.env),legacyName:V.flag.legacyName,legacyValue:V.flag.legacyName?P.env.get(V.flag.legacyName):void 0,legacyIsSet:V.flag.legacyName?P.env.get(V.flag.legacyName)!==void 0:void 0,description:V.description,defaultBehavior:V.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:P.env.get("CC_SAFETY_NET_HOME"),isSet:P.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ss={error:0,warning:1,info:2},$u=["policy","config","audit"];function Iu(P){return P.map((V)=>{if(V==="ownership")return"is not owned by the current user";if(V==="permissions")return"has unsafe permissions";if(V==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var Ou=[{derive:(P)=>P.hooks.length>0&&P.hooks.every((V)=>!V.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:(P)=>P.hooks.filter((V)=>V.inspectionStatus==="failed").map((V)=>{let z=vt(V.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${z} inspection failed`,detail:`Doctor could not verify the ${z} integration configuration.`,fixHint:`Correct the reported ${z} configuration error, then run \`cc-safety-net doctor\` again.`,integration:V.platform}})},{derive:(P)=>P.userConfig.exists&&!P.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:P.userConfig.path}]:[]},{derive:(P)=>P.projectConfig.exists&&!P.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:P.projectConfig.path}]:[]},{derive:(P)=>P.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${P.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(P)=>P.v2Leftovers&&P.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${P.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(P)=>{let V=P.environment.find((z)=>z.name==="CC_SAFETY_NET_AUDIT_SCOPE");return He(V?.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."}]:[]}},...$u.map((P)=>({derive:(V)=>V.posture.directories.filter((z)=>z.kind===P&&z.status==="unsafe").map((z)=>({checkId:`posture.${P}-directory-unsafe`,severity:"error",title:`${P[0]?.toUpperCase()}${P.slice(1)} directory is unsafe`,detail:`The ${P} directory ${Iu(z.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...z.path?{path:z.path}:{}}))})),{derive:(P)=>{let V=[...P.effectiveSafety.weakenedRuleOverrides].sort();return V.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: ${V.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${V.join(", ")}.`}]:[]}}];function as(P){return Ou.flatMap((V,z)=>V.derive(P).map((Q,te)=>({finding:Q,catalogOrder:z,occurrence:te}))).sort((V,z)=>ss[V.finding.severity]-ss[z.finding.severity]||V.catalogOrder-z.catalogOrder||V.occurrence-z.occurrence).map((V)=>V.finding)}function Ut(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Fu=(P)=>Ut()?`\x1B[32m${P}\x1B[0m`:P,ju=(P)=>Ut()?`\x1B[33m${P}\x1B[0m`:P,Nu=(P)=>Ut()?`\x1B[34m${P}\x1B[0m`:P,Mu=(P)=>Ut()?`\x1B[36m${P}\x1B[0m`:P,Hu=(P)=>Ut()?`\x1B[31m${P}\x1B[0m`:P,Uu=(P)=>Ut()?`\x1B[2m${P}\x1B[0m`:P,Gu=(P)=>Ut()?`\x1B[1m${P}\x1B[0m`:P,dt={green:Fu,yellow:ju,blue:Nu,cyan:Mu,red:Hu,dim:Uu,bold:Gu},Bu="\x1B[0m",qu=[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 Vu(P){let V=P;return()=>(V=(V*1664525+1013904223)%4294967296,V/4294967296)}function zu(P){let V=[...qu],z=Vu(P);for(let Q=V.length-1;Q>0;Q--){let te=Math.floor(z()*(Q+1)),ne=V[Q];V[Q]=V[te],V[te]=ne}return V}function Ju(P,V=0){if(!Ut())return"";let z=zu(V);return`\x1B[38;5;${z[P%z.length]}m`}function ls(P,V,z=0){if(!Ut())return`"${P}"`;return`${Ju(V,z)}"${P}"${Bu}`}function rr(P){return P==="default"?"built-in default":`${P} policy`}var Wu=new RegExp("\x1B\\[[0-9;]*m","g"),io=(P)=>P.replace(Wu,"").length;function Zt(P){let V=(P.headers??P.rows[0]??[]).map((ce,he)=>{let ye=Math.max(...P.rows.map((be)=>io(be[he]??"")));return Math.max(io(ce),ye)}),z=(ce,he)=>ce+" ".repeat(Math.max(0,he-io(ce))),Q=(ce,he)=>he[0]+V.map((ye)=>ce.repeat(ye+2)).join(he[1])+he[2],te=(ce)=>`│ ${ce.map((he,ye)=>z(he,V[ye]??0)).join(" │ ")} │`,ne=P.headers?[` ${te(P.headers)}`,` ${Q("─",["├","┼","┤"])}`]:[];return[` ${Q("─",["┌","┬","┐"])}`,...ne,...P.rows.map((ce)=>` ${te(ce)}`),` ${Q("─",["└","┴","┘"])}`].join(`
6
+ `)}function cs(P){let V=[];V.push("Hook Integration"),V.push(Ku(P));let z=[],Q=[];for(let te of P){let ne=vt(te.platform);if(te.errors&&te.errors.length>0)for(let ce of te.errors)if(te.configured)z.push({platform:ne,message:ce});else Q.push({platform:ne,message:ce})}for(let te of z)V.push(` Warning (${te.platform}): ${te.message}`);for(let te of Q)V.push(dt.red(` Error (${te.platform}): ${te.message}`));return V.join(`
7
+ `)}function Ku(P){let V=["Platform","Discovery","Configuration","Inspection"],z=P.map((Q)=>{let te=vt(Q.platform);if(Q.inspectionStatus==="not-inspected"){let ye=dt.dim("Not inspected");return[te,ye,ye,ye]}let ne=Q.detected?dt.green("Detected"):Q.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not detected"),ce=Q.configured?dt.green("Configured"):Q.detected?dt.yellow("Not configured"):Q.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not applicable"),he=Q.inspectionStatus==="verified"?dt.green("Verified"):Q.inspectionStatus==="failed"?dt.red("Failed"):dt.dim("Not applicable");return[te,ne,ce,he]});return Zt({headers:V,rows:z})}function ds(P){let z=["Guard Engine Verification",` Synthetic self-test: ${P.failed>0?dt.red(`${P.passed}/${P.total} FAIL`):dt.green(`${P.passed}/${P.total} passed`)}`],Q=P.results.filter((te)=>!te.passed);if(Q.length>0){z.push(""),z.push(dt.red(" Failures:"));for(let te of Q)z.push(dt.red(` • ${te.description}`)),z.push(dt.red(` expected ${te.expected}, got ${te.actual}`))}return z.join(`
8
8
  `)}function Yu(P){if(P.length===0)return" (no custom rules)";let V=["Source","Name","Command","Block Args"],z=P.map((Q)=>[Q.source,Q.name,Q.subcommand?`${Q.command} ${Q.subcommand}`:Q.command,Q.blockArgs.join(", ")]);return Zt({headers:V,rows:z})}function us(P){let V=[];if(V.push("Configuration"),V.push(Zu(P.userConfig,P.projectConfig)),V.push(""),P.effectiveRules.length>0)V.push(` Effective rules (${P.effectiveRules.length} total):`),V.push(Yu(P.effectiveRules));else V.push(" Effective rules: (none - using built-in rules only)");return V.join(`
9
9
  `)}function Zu(P,V){let z=["Scope","Status"],Q=(ne)=>{if(!ne.exists)return dt.dim("N/A");if(!ne.valid)return dt.red(`Invalid (${ne.errors?.[0]??"unknown error"})`);return dt.green("Configured")},te=[["User",Q(P)],["Project",Q(V)]];return Zt({headers:z,rows:te})}function ps(P){let V=[];return V.push("Environment"),V.push(Xu(P)),V.join(`
10
10
  `)}function fs(P){let V=P.effectiveSafety.policyScopes,z=["Effective Safety",` Selected preset: ${P.effectiveSafety.selectedPreset}${V?` (${rr(V.levelScope)})`:""}`,` Effective: ${P.effectiveSafety.level}`],Q=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[te,ne]of Q){let ce=P.effectiveSafety.capabilities[te],he=ce.enabled?dt.green("ON"):dt.dim("OFF"),ye=ce.sources.length>0?` (${ce.sources.join(", ")})`:"";z.push(` ${ne}: ${he} via ${ce.source}${ye}`)}if(V&&V.weakenings.length>0){z.push(" Project policy deltas:");for(let te of V.weakenings)z.push(` ${te}`)}z.push(` Stored rule customizations: ${P.effectiveSafety.ruleCounts.stored}`),z.push(` Effective rule customizations: ${P.effectiveSafety.ruleCounts.effective}`);for(let[te,ne]of Object.entries(P.effectiveSafety.ruleOverrides))z.push(` ${te}: ${ne}`);return z.join(`
@@ -16,21 +16,21 @@ ${Qr(te.segment||te.command)}`,z=P.filter((te)=>te.decision!=="allow"),Q=z.filte
16
16
  `);if(P.updateAvailable)return V.push(or([["Status",`${dt.yellow("⚠")} Update Available`],["Current",P.currentVersion],["Latest",dt.green(P.latestVersion??"")]])),V.push(""),V.push(" Run: bunx cc-safety-net@latest doctor"),V.push(" Or: npx cc-safety-net@latest doctor"),V.join(`
17
17
  `);return V.push(or([["Status",`${dt.green("✓")} Up to date`],["Version",P.currentVersion]])),V.join(`
18
18
  `)}function or(P){return Zt({rows:P})}function ys(P){let V=[];return V.push("System Info"),V.push(ep(P)),V.join(`
19
- `)}function ep(P){let V=["Component","Version"],z=(ne)=>{if(ne===null)return dt.dim("not found");return ne},te=[{label:"cc-safety-net",value:P.version},...Zn.map((ne)=>({label:bt(ne),value:P.versions[ne]??null})),{label:"Node.js",value:P.nodeVersion},{label:"npm",value:P.npmVersion},{label:"Bun",value:P.bunVersion},{label:"Platform",value:P.platform}].map((ne)=>[ne.label,z(ne.value)]);return Zt({headers:V,rows:te})}function vs(P){if(P.findings.length===0)return dt.green(`
19
+ `)}function ep(P){let V=["Component","Version"],z=(ne)=>{if(ne===null)return dt.dim("not found");return ne},te=[{label:"cc-safety-net",value:P.version},...Zn.map((ne)=>({label:vt(ne),value:P.versions[ne]??null})),{label:"Node.js",value:P.nodeVersion},{label:"npm",value:P.npmVersion},{label:"Bun",value:P.bunVersion},{label:"Platform",value:P.platform}].map((ne)=>[ne.label,z(ne.value)]);return Zt({headers:V,rows:te})}function vs(P){if(P.findings.length===0)return dt.green(`
20
20
  No findings from inspected doctor facts.`);let V={error:P.findings.filter((ne)=>ne.severity==="error").length,warning:P.findings.filter((ne)=>ne.severity==="warning").length,info:P.findings.filter((ne)=>ne.severity==="info").length},z=["error","warning","info"].filter((ne)=>V[ne]>0).map((ne)=>`${V[ne]} ${ne}`),Q=P.findings.length===1?"finding":"findings",te=`
21
- ${P.findings.length} ${Q}: ${z.join(", ")}.`;if(V.error>0)return dt.red(te);if(V.warning>0)return dt.yellow(te);return dt.blue(te)}import{lstatSync as tp}from"node:fs";import{dirname as so}from"node:path";function ao(P,V){try{let z=tp(V);if(z.isSymbolicLink())return{kind:P,path:V,status:"unsafe",issues:["symlink"]};if(!z.isDirectory())return{kind:P,path:V,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:P,path:V,status:"unknown",issues:[]};let Q=[...z.uid!==process.getuid()?["ownership"]:[],...(z.mode&18)!==0?["permissions"]:[]];return{kind:P,path:V,status:Q.length>0?"unsafe":"safe",issues:Q}}catch(z){if(typeof z==="object"&&z!==null&&"code"in z&&z.code==="ENOENT")return{kind:P,path:V,status:"not-applicable",issues:[]};return{kind:P,path:V,status:"unknown",issues:[]}}}function bs(P,V){let z=O(P);return{directories:[ao("policy",so(so(V))),ao("config",so(V)),...z?[ao("audit",z)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as np}from"node:child_process";import{existsSync as Ls}from"node:fs";import{delimiter as rp,extname as op,join as ip}from"node:path";import{stripVTControlCharacters as ws}from"node:util";var xs="2.4.9",sp=5000,ap="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function wt(){return xs}function lo(P,V){let z=P[V];if(z)return z;let Q=Object.keys(P).find((te)=>te.toLowerCase()===V.toLowerCase()&&!!P[te]);return Q?P[Q]:z}function lp(P){return(lo(P,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((V)=>V.length>0)}function cp(P,V){let z=op(P)?[P]:[...lp(V).map((Q)=>`${P}${Q}`),P];if(P.includes("/")||P.includes("\\"))return z.find((Q)=>Ls(Q))??P;return(lo(V,"PATH")??"").split(rp).flatMap((Q)=>z.map((te)=>ip(Q,te))).find((Q)=>Ls(Q))??P}function ks(P){if(!/[\s"&|<>^]/.test(P))return P;return`"${P.replace(/"/g,'""')}"`}function Xt(P,V){let[z,...Q]=P,te=V[ap]==="win32"?"win32":process.platform;if(!z||te!=="win32")return{cmd:z??"",args:Q};let ne=cp(z,V);if(!/\.(?:bat|cmd)$/i.test(ne))return{cmd:ne,args:Q};return{cmd:lo(V,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",ks(ne),...Q.map(ks)].join(" ")]}}var mn=async(P,V=sp)=>{let z=await dp(P,{timeoutMs:V});if(z.code!==0)return null;return ws(z.stdout).trim()||ws(z.stderr).trim()||null};function dp(P,V){let[z,...Q]=P;if(!z)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((te)=>{try{let ne=Xt([z,...Q],process.env),ce=np(ne.cmd,ne.args,{stdio:["ignore","pipe","pipe"]}),he=!1,ye="",be="";ce.stdout.on("data",(Xe)=>{ye+=Xe.toString()}),ce.stderr.on("data",(Xe)=>{be+=Xe.toString()});let xe=(Xe)=>{if(he)return;he=!0,clearTimeout(Ie),te(Xe)},Ie=setTimeout(()=>{ce.kill(),xe({code:null,stdout:ye,stderr:be})},V.timeoutMs);ce.on("close",(Xe)=>{xe({code:Xe,stdout:ye,stderr:be})}),ce.on("error",()=>{xe({code:null,stdout:ye,stderr:be})})}catch{te({code:null,stdout:"",stderr:""})}})}function ir(P){if(!P)return null;let V=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(P);if(V)return V[1]??null;let z=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(P);if(z)return z[1]??null;return P.split(`
22
- `)[0]?.trim()||null}async function sr(P=mn){let[V,z,Q,te,ne,ce]=await Promise.all([Promise.all($t.map(async(he)=>[he.id,ir(await P([...he.probeCommand]))])),P(["codex","plugin","list"],30000),P(["amp","plugins","list"],30000),P(["node","--version"]),P(["npm","--version"]),P(["bun","--version"])]);return{version:xs,versions:Object.fromEntries(V),codexPluginListOutput:z,ampPluginListOutput:Q,nodeVersion:ir(te),npmVersion:ir(ne),bunVersion:ir(ce),platform:`${process.platform} ${process.arch}`}}function co(P,V){if(V==="dev")return!1;let z=P.split(".").map(Number),Q=V.split(".").map(Number),[te=0,ne=0,ce=0]=z,[he=0,ye=0,be=0]=Q;if(te!==he)return te>he;if(ne!==ye)return ne>ye;return ce>be}async function Wt(){let P=wt(),V=new AbortController,z=setTimeout(()=>V.abort(),3000);try{let Q=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:V.signal});if(!Q.ok)return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${Q.status}`};let te=await Q.json(),ne=co(te.version,P);return{currentVersion:P,latestVersion:te.version,updateAvailable:ne}}catch(Q){return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:Q instanceof Error?Q.message:"Network error"}}finally{clearTimeout(z)}}import*as _s from"node:readline";var Ps=(P)=>`\x1B[${P}B`,up=(P)=>`\x1B[${P}A`;var Cs=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function pp(P){return new Promise((V)=>setTimeout(V,P))}function fp(P,V,z){if(!z)return V(P);if(z.aborted)return Promise.resolve();return new Promise((Q,te)=>{let ne=()=>z.removeEventListener("abort",ce),ce=()=>{ne(),Q()};z.addEventListener("abort",ce,{once:!0}),V(P).then(()=>{ne(),Q()},(he)=>{ne(),te(he)})})}function ar(P){return Math.max(0,Math.min(1,P))}function gn(P){return Math.max(0,Math.min(255,Math.round(P)))}function uo(P){return P<=0.0031308?12.92*P:1.055*P**0.4166666666666667-0.055}function mp(P,V,z){let Q=z*Math.PI/180,te=V*Math.cos(Q),ne=V*Math.sin(Q),ce=(P+0.3963377774*te+0.2158037573*ne)**3,he=(P-0.1055613458*te-0.0638541728*ne)**3,ye=(P-0.0894841775*te-1.291485548*ne)**3;return{blue:gn(uo(ar(-0.0041960863*ce-0.7034186147*he+1.707614701*ye))*255),green:gn(uo(ar(-1.2684380046*ce+2.6097574011*he-0.3413193965*ye))*255),red:gn(uo(ar(4.0767416621*ce-3.3077115913*he+0.2309699292*ye))*255)}}function po(P,V){let z=(V*P*180/Math.PI%360+360)%360;return mp(0.72,0.15,z)}function Es(P,V=0.1){let z=po(V,P);return`\x1B[38;2;${z.red};${z.green};${z.blue}m`}function gp(P,V){return{blue:gn(P.blue+(255-P.blue)*V),green:gn(P.green+(255-P.green)*V),red:gn(P.red+(255-P.red)*V)}}function Ds(P,V,z){let Q=Math.imul(P+2654435769,2246822507)^Math.imul(V+3266489909,668265263)^Math.imul(z+374761393,2654435761),te=Q^Q>>>15,ne=Math.imul(te,739982445),ce=ne^ne>>>12,he=Math.imul(ce,695872825);return((he^he>>>15)>>>0)/4294967296}function hp(P,V,z){let Q=Math.floor(Ds(P,V,z)*Cs.length);return Cs[Q]??"░"}function Ss(P){let V=ar(P);return V*V*V*(V*(V*6-15)+10)}function yp(P){if(P.length===0)return"";let V=[],z=!1,Q="";for(let te of P){let ne=`${te.red};${te.green};${te.blue}`;if(te.bold!==z)V.push(te.bold?"\x1B[1m":"\x1B[22m"),z=te.bold;if(ne!==Q)V.push(`\x1B[38;2;${ne}m`),Q=ne;V.push(te.character)}return`${V.join("")}\x1B[22m\x1B[39m`}function vp(P,V,z,Q,te){return P.map((ne,ce)=>({...po(z,Q+V+ce/te),bold:!1,character:ne}))}function bp(P,V,z,Q,te,ne,ce,he){let ye=Math.max(1,Q*0.75),be=Math.min(1,z/ye),xe=te*Ss(be),Ie=Math.max(0,(z-ye)/Math.max(1,Q-ye)),Xe=(1-Ss(z/Q))*he*2,et=0.35*Math.max(0,1-Ie*2),Re=be>=1,at=Math.min(P.length,Math.ceil(xe+2+1));return P.slice(0,at).map((ct,lt)=>{let pt=po(ne,ce+V+lt/he+Xe),mt=lt+Ds(V,lt,7919)*2-1;if(mt>xe+2)return{...pt,bold:!1,character:" "};let gt=xe-mt,ut=0.8*Math.exp(-(gt*gt)/12.5),vt=Math.min(0.9,ut+et),Dt=!Re&&mt>xe-4;return{...gp(pt,vt),bold:vt>0.3,character:Dt?hp(V,lt,z):ct}})}function Rs(P){return`\x1B[?2026h${P.map((V,z)=>`\x1B8${z>0?Ps(z):""}${yp(V)}`).join("")}\x1B[?2026l`}async function fo(P,V={}){if(!P)return;let z=V.output??process.stdout,Q=V.sleep??pp,te=V.seed??0,ne=P.split(`
21
+ ${P.findings.length} ${Q}: ${z.join(", ")}.`;if(V.error>0)return dt.red(te);if(V.warning>0)return dt.yellow(te);return dt.blue(te)}import{lstatSync as tp}from"node:fs";import{dirname as so}from"node:path";function ao(P,V){try{let z=tp(V);if(z.isSymbolicLink())return{kind:P,path:V,status:"unsafe",issues:["symlink"]};if(!z.isDirectory())return{kind:P,path:V,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:P,path:V,status:"unknown",issues:[]};let Q=[...z.uid!==process.getuid()?["ownership"]:[],...(z.mode&18)!==0?["permissions"]:[]];return{kind:P,path:V,status:Q.length>0?"unsafe":"safe",issues:Q}}catch(z){if(typeof z==="object"&&z!==null&&"code"in z&&z.code==="ENOENT")return{kind:P,path:V,status:"not-applicable",issues:[]};return{kind:P,path:V,status:"unknown",issues:[]}}}function bs(P,V){let z=O(P);return{directories:[ao("policy",so(so(V))),ao("config",so(V)),...z?[ao("audit",z)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as np}from"node:child_process";import{existsSync as Ls}from"node:fs";import{delimiter as rp,extname as op,join as ip}from"node:path";import{stripVTControlCharacters as ws}from"node:util";var xs="2.4.10",sp=5000,ap="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function wt(){return xs}function lo(P,V){let z=P[V];if(z)return z;let Q=Object.keys(P).find((te)=>te.toLowerCase()===V.toLowerCase()&&!!P[te]);return Q?P[Q]:z}function lp(P){return(lo(P,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((V)=>V.length>0)}function cp(P,V){let z=op(P)?[P]:[...lp(V).map((Q)=>`${P}${Q}`),P];if(P.includes("/")||P.includes("\\"))return z.find((Q)=>Ls(Q))??P;return(lo(V,"PATH")??"").split(rp).flatMap((Q)=>z.map((te)=>ip(Q,te))).find((Q)=>Ls(Q))??P}function ks(P){if(!/[\s"&|<>^]/.test(P))return P;return`"${P.replace(/"/g,'""')}"`}function Xt(P,V){let[z,...Q]=P,te=V[ap]==="win32"?"win32":process.platform;if(!z||te!=="win32")return{cmd:z??"",args:Q};let ne=cp(z,V);if(!/\.(?:bat|cmd)$/i.test(ne))return{cmd:ne,args:Q};return{cmd:lo(V,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",ks(ne),...Q.map(ks)].join(" ")]}}var mn=async(P,V=sp)=>{let z=await dp(P,{timeoutMs:V});if(z.code!==0)return null;return ws(z.stdout).trim()||ws(z.stderr).trim()||null};function dp(P,V){let[z,...Q]=P;if(!z)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((te)=>{try{let ne=Xt([z,...Q],process.env),ce=np(ne.cmd,ne.args,{stdio:["ignore","pipe","pipe"]}),he=!1,ye="",be="";ce.stdout.on("data",(Xe)=>{ye+=Xe.toString()}),ce.stderr.on("data",(Xe)=>{be+=Xe.toString()});let xe=(Xe)=>{if(he)return;he=!0,clearTimeout(Ie),te(Xe)},Ie=setTimeout(()=>{ce.kill(),xe({code:null,stdout:ye,stderr:be})},V.timeoutMs);ce.on("close",(Xe)=>{xe({code:Xe,stdout:ye,stderr:be})}),ce.on("error",()=>{xe({code:null,stdout:ye,stderr:be})})}catch{te({code:null,stdout:"",stderr:""})}})}function ir(P){if(!P)return null;let V=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(P);if(V)return V[1]??null;let z=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(P);if(z)return z[1]??null;return P.split(`
22
+ `)[0]?.trim()||null}async function sr(P=mn){let[V,z,Q,te,ne,ce]=await Promise.all([Promise.all($t.map(async(he)=>[he.id,ir(await P([...he.probeCommand]))])),P(["codex","plugin","list"],30000),P(["amp","plugins","list"],30000),P(["node","--version"]),P(["npm","--version"]),P(["bun","--version"])]);return{version:xs,versions:Object.fromEntries(V),codexPluginListOutput:z,ampPluginListOutput:Q,nodeVersion:ir(te),npmVersion:ir(ne),bunVersion:ir(ce),platform:`${process.platform} ${process.arch}`}}function co(P,V){if(V==="dev")return!1;let z=P.split(".").map(Number),Q=V.split(".").map(Number),[te=0,ne=0,ce=0]=z,[he=0,ye=0,be=0]=Q;if(te!==he)return te>he;if(ne!==ye)return ne>ye;return ce>be}async function Wt(){let P=wt(),V=new AbortController,z=setTimeout(()=>V.abort(),3000);try{let Q=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:V.signal});if(!Q.ok)return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${Q.status}`};let te=await Q.json(),ne=co(te.version,P);return{currentVersion:P,latestVersion:te.version,updateAvailable:ne}}catch(Q){return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:Q instanceof Error?Q.message:"Network error"}}finally{clearTimeout(z)}}import*as _s from"node:readline";var Ps=(P)=>`\x1B[${P}B`,up=(P)=>`\x1B[${P}A`;var Cs=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function pp(P){return new Promise((V)=>setTimeout(V,P))}function fp(P,V,z){if(!z)return V(P);if(z.aborted)return Promise.resolve();return new Promise((Q,te)=>{let ne=()=>z.removeEventListener("abort",ce),ce=()=>{ne(),Q()};z.addEventListener("abort",ce,{once:!0}),V(P).then(()=>{ne(),Q()},(he)=>{ne(),te(he)})})}function ar(P){return Math.max(0,Math.min(1,P))}function gn(P){return Math.max(0,Math.min(255,Math.round(P)))}function uo(P){return P<=0.0031308?12.92*P:1.055*P**0.4166666666666667-0.055}function mp(P,V,z){let Q=z*Math.PI/180,te=V*Math.cos(Q),ne=V*Math.sin(Q),ce=(P+0.3963377774*te+0.2158037573*ne)**3,he=(P-0.1055613458*te-0.0638541728*ne)**3,ye=(P-0.0894841775*te-1.291485548*ne)**3;return{blue:gn(uo(ar(-0.0041960863*ce-0.7034186147*he+1.707614701*ye))*255),green:gn(uo(ar(-1.2684380046*ce+2.6097574011*he-0.3413193965*ye))*255),red:gn(uo(ar(4.0767416621*ce-3.3077115913*he+0.2309699292*ye))*255)}}function po(P,V){let z=(V*P*180/Math.PI%360+360)%360;return mp(0.72,0.15,z)}function Es(P,V=0.1){let z=po(V,P);return`\x1B[38;2;${z.red};${z.green};${z.blue}m`}function gp(P,V){return{blue:gn(P.blue+(255-P.blue)*V),green:gn(P.green+(255-P.green)*V),red:gn(P.red+(255-P.red)*V)}}function Ds(P,V,z){let Q=Math.imul(P+2654435769,2246822507)^Math.imul(V+3266489909,668265263)^Math.imul(z+374761393,2654435761),te=Q^Q>>>15,ne=Math.imul(te,739982445),ce=ne^ne>>>12,he=Math.imul(ce,695872825);return((he^he>>>15)>>>0)/4294967296}function hp(P,V,z){let Q=Math.floor(Ds(P,V,z)*Cs.length);return Cs[Q]??"░"}function Ss(P){let V=ar(P);return V*V*V*(V*(V*6-15)+10)}function yp(P){if(P.length===0)return"";let V=[],z=!1,Q="";for(let te of P){let ne=`${te.red};${te.green};${te.blue}`;if(te.bold!==z)V.push(te.bold?"\x1B[1m":"\x1B[22m"),z=te.bold;if(ne!==Q)V.push(`\x1B[38;2;${ne}m`),Q=ne;V.push(te.character)}return`${V.join("")}\x1B[22m\x1B[39m`}function vp(P,V,z,Q,te){return P.map((ne,ce)=>({...po(z,Q+V+ce/te),bold:!1,character:ne}))}function bp(P,V,z,Q,te,ne,ce,he){let ye=Math.max(1,Q*0.75),be=Math.min(1,z/ye),xe=te*Ss(be),Ie=Math.max(0,(z-ye)/Math.max(1,Q-ye)),Xe=(1-Ss(z/Q))*he*2,et=0.35*Math.max(0,1-Ie*2),Re=be>=1,at=Math.min(P.length,Math.ceil(xe+2+1));return P.slice(0,at).map((ct,lt)=>{let pt=po(ne,ce+V+lt/he+Xe),mt=lt+Ds(V,lt,7919)*2-1;if(mt>xe+2)return{...pt,bold:!1,character:" "};let gt=xe-mt,ut=0.8*Math.exp(-(gt*gt)/12.5),yt=Math.min(0.9,ut+et),Dt=!Re&&mt>xe-4;return{...gp(pt,yt),bold:yt>0.3,character:Dt?hp(V,lt,z):ct}})}function Rs(P){return`\x1B[?2026h${P.map((V,z)=>`\x1B8${z>0?Ps(z):""}${yp(V)}`).join("")}\x1B[?2026l`}async function fo(P,V={}){if(!P)return;let z=V.output??process.stdout,Q=V.sleep??pp,te=V.seed??0,ne=P.split(`
23
23
  `).map((xe)=>Array.from(xe)),ce=Math.max(...ne.map((xe)=>xe.length)),he=12000*ne.filter((xe)=>xe.length>0).length/40,ye=ce>0?Math.max(1,Math.ceil(he/16.666666666666668)):0,be=ye>0?he/ye:0;z.write(`\x1B[?25l${ne.length>1?`${`
24
24
  `.repeat(ne.length-1)}${up(ne.length-1)}`:""}\x1B7`);try{for(let xe=1;xe<=ye;xe+=1){if(V.signal?.aborted)break;z.write(Rs(ne.map((Ie,Xe)=>bp(Ie,Xe,xe,ye,ce,0.1,te,3)))),await fp(be,Q,V.signal)}}finally{if(z.write(Rs(ne.map((xe,Ie)=>vp(xe,Ie,0.1,te,3)))),z.write("\x1B8"),ne.length>1)z.write(Ps(ne.length-1));z.write(`
25
25
  \x1B[0m\x1B[?25h`)}}var As=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
26
  `);function Lp(P){return Boolean(P.isTTY)}async function Rn(P={}){let V=P.output??process.stdout;if(!Lp(V))return;let z=P.input??process.stdin,Q={output:V,seed:P.seed??Math.random()*8192,sleep:P.sleep};if(!z.isTTY||typeof z.setRawMode!=="function"){await fo(As,Q);return}let te=new AbortController,ne=z.readableFlowing===!0,ce=z.isRaw===!0,he=!1,ye=(be,xe)=>{if(xe.ctrl&&xe.name==="c")he=!0;if(he||xe.name==="return"||xe.name==="enter")te.abort()};_s.emitKeypressEvents(z),z.on("keypress",ye),z.setRawMode(!0),z.resume();try{await fo(As,{...Q,signal:te.signal})}finally{if(z.off("keypress",ye),z.setRawMode(ce),!ne)z.pause()}if(!he)return;if(P.onInterrupt){P.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Sp}from"node:crypto";import{existsSync as Is}from"node:fs";import{dirname as lr,join as Os}from"node:path";import{dirname as Ts,join as wp,resolve as kp}from"node:path";var xp="rule.lock";function Cp(P){return wp(Ts(P),xp)}function $s(P={}){return kp(P.cwd??process.cwd(),".safety-net.json")}function Pt(P,V){let z=V.global?V.userConfigPath??M(P,V):V.projectConfigPath??F(V.cwd??process.cwd()),Q=V.global?Be(P,V):ze(z,V.cwd??process.cwd()),te=Cp(z);return{configDir:Ts(z),configPath:z,lockPath:te,filesystemScope:Q,configTarget:i(Q,z),lockTarget:i(Q,te)}}var Rp="`cc-safety-net rule sync` is deprecated: rulebooks are live files that need no synchronization. This run only migrates the lock and cache an earlier version left behind.",Pp="cache",Ep="rulebooks";function Fs(P,V={}){let z=Pt(P,V),Q=i(z.filesystemScope,Ns(z.configDir)),te=n(z.lockTarget);if(console.log(Rp),te===null&&!Is(Q.path))return console.log(`No v2 lock or cache leftovers found in ${lr(z.configDir)}; nothing to migrate.`),0;let ne=$p(te),ce=m(z.configTarget);if(!ce.config&&(n(z.configTarget)!==null||ne.size>0))return console.error(`Cannot migrate: the rules config in ${lr(z.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let he=ce.config?.rules??[];for(let ye of he.flatMap((be)=>Dp(be,ne,z,Q,V.global===!0)))console.log(ye);return N(z.lockTarget),tt(Q),console.log(`Removed the v2 lock and cache under ${lr(z.configDir)}.`),0}function js(P,V){return[...new Set([{cwd:V},{cwd:V,global:!0}].flatMap((z)=>{let Q=Pt(P,z);return[Q.lockPath,Ns(Q.configDir)]}))].filter((z)=>Is(z))}function Dp(P,V,z,Q,te){if(!S(P))return[];let ne=A(P).name,ce=i(z.filesystemScope,I(z.configDir,ne)),he=n(ce);if(he!==null&&Ap(he,ne))return[];let ye=V.get(P),be=ye?_p(ye,ne,Q.path,z.filesystemScope):null;if(be===null)return[`Could not migrate ${P} from the v2 cache. Run \`cc-safety-net rule update ${P}${te?" --global":""}\` to vendor it.`];if(g(ce,be),he!==null)return[`Restored ${P} from the v2 cache over an invalid file.`];return[`Vendored ${P} from the v2 cache.`]}function Ap(P,V){let z=me(P);return!("problem"in z)&&z.rulebook.name===V}function _p(P,V,z,Q){let te=Os(z,Ep,`${Tp(P)}--${P.digest.replace("sha256:","").slice(0,12)}`,ue),ne=n(i(Q,te));if(ne===null||Fp(ne)!==P.digest)return null;let ce=me(ne);if("problem"in ce||ce.rulebook.name!==V)return null;return ne}function Ns(P){return Os(lr(P),Pp)}function Tp(P){return([P.owner,P.repo,P.display_ref,P.name].every((Q)=>typeof Q==="string"&&Q!=="")?`${P.owner}/${P.repo}#${P.display_ref}/${P.name}`:P.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function $p(P){let V=P===null?null:Op(P),z=Ms(V)&&Array.isArray(V.rulebooks)?V.rulebooks:[];return new Map(z.filter(Ip).map((Q)=>[Q.spec,Q]))}function Ip(P){return Ms(P)&&typeof P.spec==="string"&&typeof P.digest==="string"}function Ms(P){return!!P&&typeof P==="object"}function Op(P){try{return JSON.parse(P)}catch{return null}}function Fp(P){return`sha256:${Sp("sha256").update(P).digest("hex")}`}var Hs="\r\x1B[2K",jp="\x1B[?25l",Np="\x1B[39m",Mp="\x1B[?25h",Hp=100,Up=0.55,Gp=80,Us=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Bp(P){return new Promise((V)=>setTimeout(V,P))}async function cr(P,V={}){let z=V.output??process.stdout;if(!z.isTTY)return P;let Q=V.sleep??Bp,te=!1,ne=P.then((he)=>(te=!0,he),(he)=>{throw te=!0,he});if(await Promise.race([ne.then(()=>!0),Q(Hp).then(()=>!1)]))return ne;z.write(jp);try{for(let he=0;!te;he+=1)z.write(`${Hs}${Es(he*Up)}${Us[he%Us.length]}${Np} ${V.loadingMessage??"Loading…"}`),await Promise.race([ne,Q(Gp)]);return await ne}finally{z.write(`${Hs}${Mp}`)}}async function Pn(P,V,z,Q={}){let te=V();if(P)await z();if(P&&te.ready)await cr(te.ready,Q);return te.finish()}import{stripVTControlCharacters as qp}from"node:util";var dr="amp plugins list",Vp=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Gs(P){if(!P.ampPluginListOutput)return{platform:"amp",status:"n/a"};let V=qp(P.ampPluginListOutput).split(`
27
- `).map((z)=>Vp.exec(z)?.[1]).find((z)=>z!==void 0);if(!V)return{platform:"amp",status:"n/a"};if(V!=="active")return{platform:"amp",status:"disabled",method:dr,configPath:dr,errors:[`Amp personal plugin cc-safety-net is ${V}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:dr,configPath:dr}}import{existsSync as Wp,readFileSync as Kp}from"node:fs";import{isAbsolute as Z1,join as Jp,relative as X1}from"node:path";function En(P){return Jp(P,".gemini","config","hooks.json")}var Yp=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Zp(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];return Object.values(P).flatMap((V)=>{if(!V||typeof V!=="object"||Array.isArray(V))return[];let z=V,Q=z.PreToolUse;if(!Array.isArray(Q))return[];return Q.flatMap((te)=>{if(!te||typeof te!=="object"||Array.isArray(te))return[];let ne=te.hooks;if(!Array.isArray(ne))return[];return ne.flatMap((ce)=>{if(!ce||typeof ce!=="object"||Array.isArray(ce))return[];let he=ce.command;if(typeof he!=="string"||!Yp.test(he))return[];return[{command:he,enabled:z.enabled!==!1}]})})})}function Bs(P){let V=En(P.environment.home);if(!Wp(V))return{platform:"antigravity-cli",status:"n/a",configPath:V};let z;try{z=Zp(JSON.parse(Kp(V,"utf-8")))}catch(Q){return{platform:"antigravity-cli",status:"n/a",configPath:V,errors:[`Failed to parse Antigravity hooks config ${V}: ${Q instanceof Error?Q.message:String(Q)}`]}}if(z.some((Q)=>Q.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:V};if(z.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:V};return{platform:"antigravity-cli",status:"n/a",configPath:V}}import{join as qs}from"node:path";import{existsSync as Xp,lstatSync as Qp,readFileSync as e2}from"node:fs";function Ft(P,V=(z)=>z){if(!Xp(P))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(V(e2(P,"utf-8")))}}catch{return{kind:"unreadable"}}}function Lt(P){try{return Qp(P)}catch{return}}function ur(P,V){let z=Lt(V);if(!z)return{platform:P,status:"n/a",configPath:V};if(!z.isSymbolicLink()&&z.isDirectory())return;return{platform:P,status:"n/a",configPath:V,errors:[`${V} is a symlink or not a directory; move or remove it before installing`]}}function ft(P,V){return typeof P==="object"&&P!==null?P[V]:void 0}var mo="cc-safety-net@cc-marketplace";function Vs(P){return qs(P.home,".claude","plugins","installed_plugins.json")}function zs(P,V){let z=ft(ft(P,"plugins"),V);return Array.isArray(z)&&z.length>0}function pr(P,V){let z=Ft(Vs(P));return z.kind==="ok"&&zs(z.value,V)}function go(P){let V=Vs(P),z=Ft(V);if(z.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(z.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!zs(z.value,mo))return{platform:"claude-code",status:"n/a"};let Q=qs(P.home,".claude","settings.json"),te=Ft(Q);if(te.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(te.kind==="ok"&&ft(ft(te.value,"enabledPlugins"),mo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:Q,errors:[`${mo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:V}}function Js(P){return go(P.environment)}function Ws(P){if(!P.codexPluginListOutput)return{platform:"codex",status:"n/a"};let V=P.codexPluginListOutput.split(`
27
+ `).map((z)=>Vp.exec(z)?.[1]).find((z)=>z!==void 0);if(!V)return{platform:"amp",status:"n/a"};if(V!=="active")return{platform:"amp",status:"disabled",method:dr,configPath:dr,errors:[`Amp personal plugin cc-safety-net is ${V}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:dr,configPath:dr}}import{existsSync as Wp,readFileSync as Kp}from"node:fs";import{isAbsolute as Z1,join as Jp,relative as X1}from"node:path";function En(P){return Jp(P,".gemini","config","hooks.json")}var Yp=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Zp(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];return Object.values(P).flatMap((V)=>{if(!V||typeof V!=="object"||Array.isArray(V))return[];let z=V,Q=z.PreToolUse;if(!Array.isArray(Q))return[];return Q.flatMap((te)=>{if(!te||typeof te!=="object"||Array.isArray(te))return[];let ne=te.hooks;if(!Array.isArray(ne))return[];return ne.flatMap((ce)=>{if(!ce||typeof ce!=="object"||Array.isArray(ce))return[];let he=ce.command;if(typeof he!=="string"||!Yp.test(he))return[];return[{command:he,enabled:z.enabled!==!1}]})})})}function Bs(P){let V=En(P.environment.home);if(!Wp(V))return{platform:"antigravity-cli",status:"n/a",configPath:V};let z;try{z=Zp(JSON.parse(Kp(V,"utf-8")))}catch(Q){return{platform:"antigravity-cli",status:"n/a",configPath:V,errors:[`Failed to parse Antigravity hooks config ${V}: ${Q instanceof Error?Q.message:String(Q)}`]}}if(z.some((Q)=>Q.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:V};if(z.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:V};return{platform:"antigravity-cli",status:"n/a",configPath:V}}import{join as qs}from"node:path";import{existsSync as Xp,lstatSync as Qp,readFileSync as e2}from"node:fs";function Ft(P,V=(z)=>z){if(!Xp(P))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(V(e2(P,"utf-8")))}}catch{return{kind:"unreadable"}}}function bt(P){try{return Qp(P)}catch{return}}function ur(P,V){let z=bt(V);if(!z)return{platform:P,status:"n/a",configPath:V};if(!z.isSymbolicLink()&&z.isDirectory())return;return{platform:P,status:"n/a",configPath:V,errors:[`${V} is a symlink or not a directory; move or remove it before installing`]}}function ft(P,V){return typeof P==="object"&&P!==null?P[V]:void 0}var mo="cc-safety-net@cc-marketplace";function Vs(P){return qs(P.home,".claude","plugins","installed_plugins.json")}function zs(P,V){let z=ft(ft(P,"plugins"),V);return Array.isArray(z)&&z.length>0}function pr(P,V){let z=Ft(Vs(P));return z.kind==="ok"&&zs(z.value,V)}function go(P){let V=Vs(P),z=Ft(V);if(z.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(z.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!zs(z.value,mo))return{platform:"claude-code",status:"n/a"};let Q=qs(P.home,".claude","settings.json"),te=Ft(Q);if(te.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(te.kind==="ok"&&ft(ft(te.value,"enabledPlugins"),mo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:Q,errors:[`${mo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:V}}function Js(P){return go(P.environment)}function Ws(P){if(!P.codexPluginListOutput)return{platform:"codex",status:"n/a"};let V=P.codexPluginListOutput.split(`
28
28
  `).find((z)=>z.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!V)return{platform:"codex",status:"n/a"};if(!V.includes("installed,"))return{platform:"codex",status:"n/a"};if(!V.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 yr,readdirSync as t2,readFileSync as n2}from"node:fs";import{join as St}from"node:path";function At(P){let V="",z=0,Q=!1,te=!1,ne=-1;while(z<P.length){let ce=P[z],he=P[z+1];if(te){V+=ce,te=!1,z++;continue}if(ce==='"'&&!Q){Q=!0,ne=-1,V+=ce,z++;continue}if(ce==='"'&&Q){Q=!1,V+=ce,z++;continue}if(ce==="\\"&&Q){te=!0,V+=ce,z++;continue}if(Q){V+=ce,z++;continue}if(ce==="/"&&he==="/"){while(z<P.length&&P[z]!==`
29
29
  `)z++;continue}if(ce==="/"&&he==="*"){z+=2;while(z<P.length-1){if(P[z]==="*"&&P[z+1]==="/"){z+=2;break}z++}continue}if(ce===","){ne=V.length,V+=ce,z++;continue}if(ce==="}"||ce==="]"){if(ne!==-1){let ye=V.slice(ne+1);if(/^\s*$/.test(ye))V=V.slice(0,ne)+ye}ne=-1,V+=ce,z++;continue}if(!/\s/.test(ce))ne=-1;V+=ce,z++}return V}function Ys(P,V,z){let Q=V+1,te=!1;while(Q<P.length){if(te){te=!1,Q++;continue}if(P[Q]==="\\"){te=!0,Q++;continue}if(P[Q]==='"')return Q+1;Q++}throw Error(z)}function yo(P,V,z){let Q=P[V],te=Q==="["?"]":"}",ne=0,ce=V;while(ce<P.length){let he=z.skipComment?.(P,ce)??ce;if(he!==ce){ce=he;continue}if(P[ce]==='"'){ce=Ys(P,ce,z.stringError);continue}if(P[ce]===Q)ne++;if(P[ce]===te){if(ne--,ne===0)return ce}ce++}throw Error(z.bracketError)}function Zs(P,V){let z=P.lastIndexOf(`
30
30
  `,V)+1;return/^[ \t]*/.exec(P.slice(z))?.[0]??""}function fr(P,V){let z=V.end+(/^\s*/.exec(P.slice(V.end))?.[0].length??0);if(P[z]===","){let ce=P[z+1]===`
31
31
  `?z+2:z+1;return`${P.slice(0,V.start)}${P.slice(ce)}`}let Q=P.slice(0,V.start).search(/\s*$/)-1;if(P[Q]!==",")return`${P.slice(0,V.start)}${P.slice(V.end)}`;let te=P.lastIndexOf(`
32
32
  `,Q-1),ne=te!==-1&&/^\s*$/.test(P.slice(te+1,Q))?te:Q;return`${P.slice(0,ne)}${P.slice(V.end)}`}function ho(P,V){if(P.startsWith("//",V)){let z=P.indexOf(`
33
- `,V+2);return z===-1?P.length:z+1}if(P.startsWith("/*",V)){let z=P.indexOf("*/",V+2);return z===-1?P.length:z+2}return V}function Ks(P,V){let z=V;while(z<P.length){if(/\s/.test(P[z]??"")){z++;continue}let Q=ho(P,z);if(Q===z)return z;z=Q}return z}function Xs(P,V,z){let Q=0,te=0;while(te<P.length){let ne=ho(P,te);if(ne!==te){te=ne;continue}if(P[te]==='"'){let ce=Ys(P,te,z.stringError);if(Q===1&&JSON.parse(P.slice(te,ce))===V){let he=Ks(P,ce),ye=Ks(P,he+1);if(P[he]===":"&&P[ye]==="[")return{start:ye,end:yo(P,ye,{skipComment:ho,...z})}}te=ce;continue}if(P[te]==="{"||P[te]==="[")Q++;if(P[te]==="}"||P[te]==="]")Q--;te++}return}var jt="cc-safety-net@cc-marketplace",mr=["cc-marketplace","cc-safety-net"],Qs=["_direct","copilot-safety-net"],ea=["cc-marketplace","safety-net"],ta="safety-net@cc-marketplace";function gr(P,V){let z=V.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${z}([^a-z0-9-]|$)`,"m").test(P??"")}function na(P){return gr(P,"cc-safety-net@cc-marketplace")}function ra(P){return gr(P,"cc-marketplace")}function oa(P){return gr(P,"copilot-safety-net")}function ia(P){return gr(P,"safety-net@cc-marketplace")}function vo(P){if(!P?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(P)}function aa(P,V){if(!P)return null;let z=P.match(/(\d+)\.(\d+)\.(\d+)/);if(!z)return null;let Q=[Number(z[1]),Number(z[2]),Number(z[3])];for(let te=0;te<V.length;te++){let ne=Q[te]??0,ce=V[te]??0;if(ne!==ce)return ne>ce}return!0}function r2(P){return aa(P,[0,0,422])}function o2(P){return aa(P,[1,0,8])}function Dn(P){return P.env.get("COPILOT_HOME")||St(P.home,".copilot")}function bo(P){return(P.hooks?.preToolUse??[]).some((z)=>{if(z.type!=="command")return!1;return vo(z.command)||vo(z.bash)||vo(z.powershell)})}function hr(P){return P===void 0||typeof P==="string"}function i2(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let V=P;if(V.disableAllHooks!==void 0&&typeof V.disableAllHooks!=="boolean")return!1;if(V.hooks===void 0)return!0;if(!V.hooks||typeof V.hooks!=="object"||Array.isArray(V.hooks))return!1;let z=V.hooks.preToolUse;if(z===void 0)return!0;return Array.isArray(z)&&z.every((Q)=>Q!==null&&typeof Q==="object"&&!Array.isArray(Q)&&hr(Q.type)&&hr(Q.command)&&hr(Q.bash)&&hr(Q.powershell))}function Lo(P,V){try{let z=JSON.parse(At(n2(P,"utf-8")));if(!i2(z)){V?.push(`Invalid hook config ${P}: hooks.preToolUse must be an array of hook objects`);return}return z}catch(z){V?.push(`Failed to parse ${P}: ${z instanceof Error?z.message:String(z)}`);return}}function la(P,V){try{return t2(P).filter((z)=>z.endsWith(".json")).sort((z,Q)=>z.localeCompare(Q))}catch(z){return V?.push(`Failed to read ${P}: ${z instanceof Error?z.message:String(z)}`),[]}}function s2(P,V){if(!yr(P))return[];let z=[];for(let Q of la(P,V)){let te=St(P,Q),ne=Lo(te,V);if(ne&&bo(ne))z.push(te)}return z}function hn(P,V){if(!yr(P))return;let z=Lo(P,V);if(!z)return;return{path:P,config:z}}function sa(P,V,z,Q){if(V){P.push(`GitHub Copilot CLI ${V} does not support ${z}; requires ${Q}+`);return}P.push(`GitHub Copilot CLI version unavailable; skipping ${z} because it requires ${Q}+`)}function a2(P){for(let V of P){if(V?.config.disableAllHooks===!0)return V.path;if(V?.config.disableAllHooks===!1)return}return}function l2(P,V,z,Q){let te=Dn(P),ne=St(V,".github","hooks"),ce=St(te,"hooks"),he=St(V,".github","copilot"),ye=St(V,".claude"),be=o2(z),xe=be===!0?Q:void 0,Ie=[hn(St(he,"settings.local.json"),xe),hn(St(he,"settings.json"),xe),hn(St(ye,"settings.local.json"),xe),hn(St(ye,"settings.json"),xe)],Xe=[hn(St(te,"settings.json"),xe),hn(St(te,"config.json"),xe)];if(be!==!1){let gt=a2([...Ie,...Xe]);if(gt){if(be===null)Q.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${gt} as active`);return{activeConfigPaths:[],disabledBy:gt}}}let et=s2(ne,Q),Re=r2(z),at=Re===!0?Q:void 0,ct=yr(ce)?la(ce,at):[],lt=[];for(let gt of ct){let ut=St(ce,gt),vt=Lo(ut,at);if(vt&&bo(vt))lt.push(ut)}if(Re!==!0&&lt.length>0)sa(Q,z,`user hook files in ${ce}`,"0.0.422"),lt.length=0;let pt=[];for(let gt of[...Ie,...Xe]){if(!gt)continue;if(!bo(gt.config))continue;if(be===!0){pt.push(gt);continue}sa(Q,z,"inline hook definitions in Copilot config files","1.0.8");break}let mt=(gt)=>gt.filter((ut)=>!!ut&&pt.includes(ut)).map((ut)=>ut.path);return{activeConfigPaths:[...mt(Ie),...et,...mt(Xe),...lt]}}function ca(P){let V=[],z=l2(P.environment,P.cwd,P.copilotCliVersion,V);if(z.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:z.disabledBy,configPaths:[z.disabledBy],errors:V.length>0?V:void 0};let Q=Dn(P.environment),te=St(Q,"installed-plugins",...mr),ne=yr(te),ce=St(Q,"settings.json"),he=Ft(ce,At);if(ne&&he.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(ne&&he.kind==="ok"&&ft(ft(he.value,"enabledPlugins"),jt)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:ce,errors:[`${jt} is installed but not enabled in Copilot CLI`]};if(ne||z.activeConfigPaths.length>0){let ye=ne,be=z.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:ye?"plugin config":"hook config",configPath:be??(ye?te:void 0),configPaths:z.activeConfigPaths.length>0?z.activeConfigPaths:void 0,errors:V.length>0?V:void 0}}return{platform:"copilot-cli",status:"n/a",errors:V.length>0?V:void 0}}import{existsSync as v2,readFileSync as b2}from"node:fs";import{existsSync as da,mkdirSync as u2,readFileSync as p2}from"node:fs";import{dirname as f2,join as m2}from"node:path";import{renameSync as c2,writeFileSync as d2}from"node:fs";function kt(P,V){let z=`${P}.${process.pid}.tmp`;d2(z,V),c2(z,P)}var Nt=Object.fromEntries(Sn.map((P)=>[P.id,`npx -y cc-safety-net hook ${P.flags[1]}`]));var An=Nt.cursor,ua=30;function br(P){return m2(P.home,".cursor","hooks.json")}function Qt(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function wo(){return{command:An,timeout:ua,failClosed:!0}}function vr(P){return Qt(P)&&P.command===An}function g2(P){return Object.keys(P).length===3&&P.command===An&&P.timeout===ua&&P.failClosed===!0}function h2(P){try{return JSON.parse(p2(P,"utf-8"))}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${P}: ${V.message}`);throw V}}function pa(P){let V=h2(P);if(!Qt(V))throw Error(`Cursor hooks config ${P} must be a JSON object`);if(V.version!==1)throw Error(`Cursor hooks config ${P} must set "version": 1`);if(V.hooks!==void 0&&!Qt(V.hooks))throw Error(`Cursor hooks config ${P} "hooks" must be an object`);let z=Qt(V.hooks)?V.hooks.preToolUse:void 0;if(z!==void 0&&!Array.isArray(z))throw Error(`Cursor hooks config ${P} "hooks.preToolUse" must be an array`);return V}function fa(P){let V=Qt(P.hooks)?P.hooks.preToolUse:void 0;return Array.isArray(V)?V:[]}function y2(P){if(!P.some(vr))return[...P,wo()];return P.reduce((V,z)=>{if(!vr(z))return V.result.push(z),V;if(!V.inserted)V.result.push(wo()),V.inserted=!0;return V},{result:[],inserted:!1}).result}function ma(P,V,z){let Q=Qt(V.hooks)?V.hooks:{},te={...V,hooks:{...Q,preToolUse:z}};kt(P,`${JSON.stringify(te,null,2)}
33
+ `,V+2);return z===-1?P.length:z+1}if(P.startsWith("/*",V)){let z=P.indexOf("*/",V+2);return z===-1?P.length:z+2}return V}function Ks(P,V){let z=V;while(z<P.length){if(/\s/.test(P[z]??"")){z++;continue}let Q=ho(P,z);if(Q===z)return z;z=Q}return z}function Xs(P,V,z){let Q=0,te=0;while(te<P.length){let ne=ho(P,te);if(ne!==te){te=ne;continue}if(P[te]==='"'){let ce=Ys(P,te,z.stringError);if(Q===1&&JSON.parse(P.slice(te,ce))===V){let he=Ks(P,ce),ye=Ks(P,he+1);if(P[he]===":"&&P[ye]==="[")return{start:ye,end:yo(P,ye,{skipComment:ho,...z})}}te=ce;continue}if(P[te]==="{"||P[te]==="[")Q++;if(P[te]==="}"||P[te]==="]")Q--;te++}return}var jt="cc-safety-net@cc-marketplace",mr=["cc-marketplace","cc-safety-net"],Qs=["_direct","copilot-safety-net"],ea=["cc-marketplace","safety-net"],ta="safety-net@cc-marketplace";function gr(P,V){let z=V.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${z}([^a-z0-9-]|$)`,"m").test(P??"")}function na(P){return gr(P,"cc-safety-net@cc-marketplace")}function ra(P){return gr(P,"cc-marketplace")}function oa(P){return gr(P,"copilot-safety-net")}function ia(P){return gr(P,"safety-net@cc-marketplace")}function vo(P){if(!P?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(P)}function aa(P,V){if(!P)return null;let z=P.match(/(\d+)\.(\d+)\.(\d+)/);if(!z)return null;let Q=[Number(z[1]),Number(z[2]),Number(z[3])];for(let te=0;te<V.length;te++){let ne=Q[te]??0,ce=V[te]??0;if(ne!==ce)return ne>ce}return!0}function r2(P){return aa(P,[0,0,422])}function o2(P){return aa(P,[1,0,8])}function Dn(P){return P.env.get("COPILOT_HOME")||St(P.home,".copilot")}function bo(P){return(P.hooks?.preToolUse??[]).some((z)=>{if(z.type!=="command")return!1;return vo(z.command)||vo(z.bash)||vo(z.powershell)})}function hr(P){return P===void 0||typeof P==="string"}function i2(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let V=P;if(V.disableAllHooks!==void 0&&typeof V.disableAllHooks!=="boolean")return!1;if(V.hooks===void 0)return!0;if(!V.hooks||typeof V.hooks!=="object"||Array.isArray(V.hooks))return!1;let z=V.hooks.preToolUse;if(z===void 0)return!0;return Array.isArray(z)&&z.every((Q)=>Q!==null&&typeof Q==="object"&&!Array.isArray(Q)&&hr(Q.type)&&hr(Q.command)&&hr(Q.bash)&&hr(Q.powershell))}function Lo(P,V){try{let z=JSON.parse(At(n2(P,"utf-8")));if(!i2(z)){V?.push(`Invalid hook config ${P}: hooks.preToolUse must be an array of hook objects`);return}return z}catch(z){V?.push(`Failed to parse ${P}: ${z instanceof Error?z.message:String(z)}`);return}}function la(P,V){try{return t2(P).filter((z)=>z.endsWith(".json")).sort((z,Q)=>z.localeCompare(Q))}catch(z){return V?.push(`Failed to read ${P}: ${z instanceof Error?z.message:String(z)}`),[]}}function s2(P,V){if(!yr(P))return[];let z=[];for(let Q of la(P,V)){let te=St(P,Q),ne=Lo(te,V);if(ne&&bo(ne))z.push(te)}return z}function hn(P,V){if(!yr(P))return;let z=Lo(P,V);if(!z)return;return{path:P,config:z}}function sa(P,V,z,Q){if(V){P.push(`GitHub Copilot CLI ${V} does not support ${z}; requires ${Q}+`);return}P.push(`GitHub Copilot CLI version unavailable; skipping ${z} because it requires ${Q}+`)}function a2(P){for(let V of P){if(V?.config.disableAllHooks===!0)return V.path;if(V?.config.disableAllHooks===!1)return}return}function l2(P,V,z,Q){let te=Dn(P),ne=St(V,".github","hooks"),ce=St(te,"hooks"),he=St(V,".github","copilot"),ye=St(V,".claude"),be=o2(z),xe=be===!0?Q:void 0,Ie=[hn(St(he,"settings.local.json"),xe),hn(St(he,"settings.json"),xe),hn(St(ye,"settings.local.json"),xe),hn(St(ye,"settings.json"),xe)],Xe=[hn(St(te,"settings.json"),xe),hn(St(te,"config.json"),xe)];if(be!==!1){let gt=a2([...Ie,...Xe]);if(gt){if(be===null)Q.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${gt} as active`);return{activeConfigPaths:[],disabledBy:gt}}}let et=s2(ne,Q),Re=r2(z),at=Re===!0?Q:void 0,ct=yr(ce)?la(ce,at):[],lt=[];for(let gt of ct){let ut=St(ce,gt),yt=Lo(ut,at);if(yt&&bo(yt))lt.push(ut)}if(Re!==!0&&lt.length>0)sa(Q,z,`user hook files in ${ce}`,"0.0.422"),lt.length=0;let pt=[];for(let gt of[...Ie,...Xe]){if(!gt)continue;if(!bo(gt.config))continue;if(be===!0){pt.push(gt);continue}sa(Q,z,"inline hook definitions in Copilot config files","1.0.8");break}let mt=(gt)=>gt.filter((ut)=>!!ut&&pt.includes(ut)).map((ut)=>ut.path);return{activeConfigPaths:[...mt(Ie),...et,...mt(Xe),...lt]}}function ca(P){let V=[],z=l2(P.environment,P.cwd,P.copilotCliVersion,V);if(z.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:z.disabledBy,configPaths:[z.disabledBy],errors:V.length>0?V:void 0};let Q=Dn(P.environment),te=St(Q,"installed-plugins",...mr),ne=yr(te),ce=St(Q,"settings.json"),he=Ft(ce,At);if(ne&&he.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(ne&&he.kind==="ok"&&ft(ft(he.value,"enabledPlugins"),jt)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:ce,errors:[`${jt} is installed but not enabled in Copilot CLI`]};if(ne||z.activeConfigPaths.length>0){let ye=ne,be=z.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:ye?"plugin config":"hook config",configPath:be??(ye?te:void 0),configPaths:z.activeConfigPaths.length>0?z.activeConfigPaths:void 0,errors:V.length>0?V:void 0}}return{platform:"copilot-cli",status:"n/a",errors:V.length>0?V:void 0}}import{existsSync as v2,readFileSync as b2}from"node:fs";import{existsSync as da,mkdirSync as u2,readFileSync as p2}from"node:fs";import{dirname as f2,join as m2}from"node:path";import{renameSync as c2,writeFileSync as d2}from"node:fs";function kt(P,V){let z=`${P}.${process.pid}.tmp`;d2(z,V),c2(z,P)}var Nt=Object.fromEntries(Sn.map((P)=>[P.id,`npx -y cc-safety-net hook ${P.flags[1]}`]));var An=Nt.cursor,ua=30;function br(P){return m2(P.home,".cursor","hooks.json")}function Qt(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function wo(){return{command:An,timeout:ua,failClosed:!0}}function vr(P){return Qt(P)&&P.command===An}function g2(P){return Object.keys(P).length===3&&P.command===An&&P.timeout===ua&&P.failClosed===!0}function h2(P){try{return JSON.parse(p2(P,"utf-8"))}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${P}: ${V.message}`);throw V}}function pa(P){let V=h2(P);if(!Qt(V))throw Error(`Cursor hooks config ${P} must be a JSON object`);if(V.version!==1)throw Error(`Cursor hooks config ${P} must set "version": 1`);if(V.hooks!==void 0&&!Qt(V.hooks))throw Error(`Cursor hooks config ${P} "hooks" must be an object`);let z=Qt(V.hooks)?V.hooks.preToolUse:void 0;if(z!==void 0&&!Array.isArray(z))throw Error(`Cursor hooks config ${P} "hooks.preToolUse" must be an array`);return V}function fa(P){let V=Qt(P.hooks)?P.hooks.preToolUse:void 0;return Array.isArray(V)?V:[]}function y2(P){if(!P.some(vr))return[...P,wo()];return P.reduce((V,z)=>{if(!vr(z))return V.result.push(z),V;if(!V.inserted)V.result.push(wo()),V.inserted=!0;return V},{result:[],inserted:!1}).result}function ma(P,V,z){let Q=Qt(V.hooks)?V.hooks:{},te={...V,hooks:{...Q,preToolUse:z}};kt(P,`${JSON.stringify(te,null,2)}
34
34
  `)}function ga(P){let V=br(P);if(!da(V))return u2(f2(V),{recursive:!0}),kt(V,`${JSON.stringify({version:1,hooks:{preToolUse:[wo()]}},null,2)}
35
35
  `),{path:V,alreadyInstalled:!1};let z=pa(V),Q=fa(z),te=Q.filter(vr);if(Qt(z.hooks)&&Array.isArray(z.hooks.preToolUse)&&te.length===1&&te[0]!==void 0&&g2(te[0]))return{path:V,alreadyInstalled:!0};return ma(V,z,y2(Q)),{path:V,alreadyInstalled:!1}}function ha(P){let V=br(P);if(!da(V))return{path:V,alreadyInstalled:!1};let z=pa(V),Q=fa(z),te=Q.filter((ne)=>!vr(ne));if(te.length===Q.length)return{path:V,alreadyInstalled:!1};return ma(V,z,te),{path:V,alreadyInstalled:!0}}function L2(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];let V=P.hooks;if(!V||typeof V!=="object"||Array.isArray(V))return[];let z=V.preToolUse;if(!Array.isArray(z))return[];return z.filter((Q)=>!!Q&&typeof Q==="object"&&!Array.isArray(Q)&&Q.command===An)}function w2(P){let V=[];if(P.length>1)V.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let z=P[0];if(z&&z.failClosed!==!0)V.push('Managed hook is missing "failClosed": true; reinstall to repair');if(z&&z.timeout!==30)V.push('Managed hook "timeout" is not 30; reinstall to repair');return V}function ya(P){let V=br(P.environment);if(!v2(V))return{platform:"cursor",status:"n/a",configPath:V};let z;try{z=JSON.parse(b2(V,"utf-8"))}catch(ne){return{platform:"cursor",status:"n/a",configPath:V,errors:[`Failed to parse Cursor hooks config ${V}: ${ne instanceof Error?ne.message:String(ne)}`]}}let Q=L2(z);if(Q.length===0)return{platform:"cursor",status:"n/a",configPath:V};let te=w2(Q);return{platform:"cursor",status:"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{existsSync as k2}from"node:fs";import{join as ko}from"node:path";var xo="gemini-safety-net";function Co(P){let V=ko(P.home,".gemini","extensions"),z=ko(V,xo);if(!k2(z))return{platform:"gemini-cli",status:"n/a"};let Q=ko(V,"extension-enablement.json"),te=Ft(Q);if(te.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let ne=te.kind==="ok"?ft(ft(te.value,xo),"overrides"):void 0;if(Array.isArray(ne)&&ne.some((he)=>typeof he==="string"&&he.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:Q,errors:[`${xo} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:z}}function va(P){return Co(P.environment)}import{existsSync as R2,readFileSync as P2}from"node:fs";import{existsSync as La,mkdirSync as x2,readFileSync as wa,rmSync as C2}from"node:fs";import{dirname as S2,join as ba}from"node:path";var _n=Nt["grok-build"],kr=30;function xr(P){return ba(P.env.get("GROK_HOME")??ba(P.home,".grok"),"hooks","cc-safety-net.json")}function en(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function Lr(){return{hooks:[{type:"command",command:_n,timeout:kr}]}}function ka(P){return en(P)&&P.command===_n}function xa(P){return P.flatMap((V)=>{if(!en(V)||!Array.isArray(V.hooks))return[V];let z=V.hooks.filter((Q)=>!ka(Q));if(z.length===V.hooks.length)return[V];return z.length===0?[]:[{...V,hooks:z}]})}function Ca(P){try{let V=JSON.parse(P);return en(V)?V:null}catch{return null}}function Sa(P){let V=en(P.hooks)?P.hooks.PreToolUse:void 0;return Array.isArray(V)?V:[]}function wr(P,V,z){let Q=en(V.hooks)?V.hooks:{};kt(P,`${JSON.stringify({...V,hooks:{...Q,PreToolUse:z}},null,2)}
36
36
  `)}function Ra(P){let V=xr(P);if(!La(V))return x2(S2(V),{recursive:!0}),wr(V,{},[Lr()]),{path:V,alreadyInstalled:!1};let z=Ca(wa(V,"utf-8"));if(!z)return wr(V,{},[Lr()]),{path:V,alreadyInstalled:!1};let Q=Sa(z),te=Q.filter((ne)=>en(ne)&&Array.isArray(ne.hooks)&&ne.hooks.some(ka));if(te.length===1&&JSON.stringify(te[0])===JSON.stringify(Lr()))return{path:V,alreadyInstalled:!0};return wr(V,z,[...xa(Q),Lr()]),{path:V,alreadyInstalled:!1}}function Pa(P){let V=xr(P);if(!La(V))return{path:V,alreadyInstalled:!1};let z=Ca(wa(V,"utf-8"));if(!z)return{path:V,alreadyInstalled:!1};let Q=Sa(z),te=xa(Q);if(JSON.stringify(te)===JSON.stringify(Q))return{path:V,alreadyInstalled:!1};let ne=en(z.hooks)?z.hooks:{};if(te.length===0&&Object.keys(z).length===1&&Object.keys(ne).length===1)return C2(V),{path:V,alreadyInstalled:!0};return wr(V,z,te),{path:V,alreadyInstalled:!0}}function Tn(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function E2(P){if(!Tn(P)||!Tn(P.hooks))return[];let V=P.hooks.PreToolUse;if(!Array.isArray(V))return[];return V.filter((z)=>Tn(z)&&Array.isArray(z.hooks)&&z.hooks.some((Q)=>Tn(Q)&&Q.command===_n))}function D2(P){let z=(Array.isArray(P.hooks)?P.hooks.filter(Tn):[]).find((Q)=>Q.command===_n);return[...P.matcher===void 0||P.matcher===""||P.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...z?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...z?.timeout===kr?[]:[`Managed hook "timeout" is not ${kr}; reinstall to repair`]]}function Ea(P){let V=xr(P.environment);if(!R2(V))return{platform:"grok-build",status:"n/a",configPath:V};let z;try{z=JSON.parse(P2(V,"utf-8"))}catch(ne){return{platform:"grok-build",status:"n/a",configPath:V,errors:[`Failed to parse Grok Build hooks config ${V}: ${ne instanceof Error?ne.message:String(ne)}`]}}let Q=E2(z)[0];if(!Q)return{platform:"grok-build",status:"n/a",configPath:V};let te=D2(Q);return{platform:"grok-build",status:"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{readFileSync as Fa}from"node:fs";import{join as ja}from"node:path";var Tt="cc-safety-net",So="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",A2=30;function Da(P){return`${So}
@@ -203,15 +203,15 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
203
203
 
204
204
  def register(ctx):
205
205
  ctx.register_hook("pre_tool_call", _pre_tool_call)
206
- `}function $n(P){return[{name:"__init__.py",content:T2(P)},{name:"plugin.yaml",content:_2(P)}]}import{mkdirSync as $2,readdirSync as I2,readFileSync as O2,rmSync as Ro}from"node:fs";import{join as tn}from"node:path";var F2="__pycache__";function Po(P){let V=P.env.get("HERMES_HOME")?.trim();return V?V:tn(P.home,".hermes")}function Eo(P){return tn(Po(P),"plugins",Tt)}function Do(P){return P.startsWith(So)}function Ao(P,V){let z=Eo(P),Q=Lt(z);if(Q&&(Q.isSymbolicLink()||!Q.isDirectory()))throw Error(`Refusing to ${V} ${z}: not a regular directory. Move or remove it and rerun ${V==="install"?"install":"uninstall"} --hermes-agent.`);return z}function Aa(P,V){let z=Lt(P);if(!z)return;if(z.isSymbolicLink()||!z.isFile())throw Error(`Refusing to ${V} ${P}: not a regular file. Move or remove it.`);let Q=O2(P,"utf-8");if(!Do(Q))throw Error(`Refusing to ${V} unmanaged file at ${P}. Move or remove it.`);return Q}function _a(P){let V=Ao(P,"install"),z=$n(wt());if(z.map((te)=>Aa(tn(V,te.name),"overwrite")).every((te,ne)=>te===z[ne]?.content))return{path:V,alreadyInstalled:!0};return $2(V,{recursive:!0}),z.forEach((te)=>{kt(tn(V,te.name),te.content)}),{path:V,alreadyInstalled:!1}}function _o(P){let V=Ao(P,"remove");if(!Lt(V))return[];return $n(wt()).filter((z)=>Aa(tn(V,z.name),"remove")!==void 0)}function Ta(P){let V=Ao(P,"remove");if(!Lt(V))return{path:V,alreadyInstalled:!1};let z=_o(P);if(z.forEach((Q)=>{Ro(tn(V,Q.name))}),Ro(tn(V,F2),{recursive:!0,force:!0}),I2(V).length===0)Ro(V,{recursive:!0});return{path:V,alreadyInstalled:z.length>0}}var Cr="hermes-agent",$a=/^([^\s#][^:]*):/,j2=/^\s+([A-Za-z_][\w-]*):/,Ia=/^\s+-\s*(.*)$/;function N2(P){return P.trim().replace(/^(["'])(.*)\1$/,"$2")}function M2(P){let V=P.split(/\r?\n/),z=V.findIndex((ne)=>$a.exec(ne)?.[1]?.trim()==="plugins");if(z===-1)return[];let Q=V.slice(z+1),te=Q.findIndex((ne)=>$a.test(ne));return te===-1?Q:Q.slice(0,te)}function Oa(P,V){let z=M2(P),Q=z.findIndex((ce)=>j2.exec(ce)?.[1]===V);if(Q===-1)return[];let te=z.slice(Q+1),ne=te.findIndex((ce)=>!Ia.test(ce));return(ne===-1?te:te.slice(0,ne)).map((ce)=>N2(Ia.exec(ce)?.[1]??""))}function H2(P){try{return Fa(ja(Po(P),"config.yaml"),"utf-8")}catch{return}}function To(P){let V=H2(P)??"";return Oa(V,"enabled").includes(Tt)&&!Oa(V,"disabled").includes(Tt)}function Na(P){return/^# version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function U2(P,V){let z=Lt(P);if(!z)return{error:`${V.name} is missing from ${P}; run install --hermes-agent`};if(z.isSymbolicLink()||!z.isFile())return{error:`${P} is a symlink or not a regular file; move or remove it`};try{let Q=Fa(P,"utf-8");if(!Do(Q))return{error:`Unmanaged ${V.name} occupies ${P}; move or remove it`};if(Na(Q)===wt()&&Q!==V.content)return{error:`Modified ${V.name} occupies ${P}; run install --hermes-agent to restore it`};return{content:Q}}catch(Q){return{error:`Failed to read ${P}: ${Q instanceof Error?Q.message:String(Q)}`}}}function Ma(P){let V=Eo(P.environment),z=ur(Cr,V);if(z)return z;let Q=$n(wt()).map((he)=>U2(ja(V,he.name),he)),te=Q.flatMap((he)=>("error"in he)?[he.error]:[]);if(te.length>0)return{platform:Cr,status:"n/a",configPath:V,errors:te};let ne=Q.some((he)=>("content"in he)&&Na(he.content)!==wt()),ce=ne?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!To(P.environment))return{platform:Cr,status:"disabled",method:"plugin directory",configPath:V,errors:[`${Tt} is not enabled in Hermes; run \`hermes plugins enable ${Tt}\``,...ce]};return{platform:Cr,status:"configured",method:"plugin directory",configPath:V,errors:ne?ce:void 0}}import{existsSync as G2,readFileSync as B2}from"node:fs";import{join as Ha}from"node:path";var q2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function V2(P){return Ha(P.env.get("KIMI_CODE_HOME")||Ha(P.home,".kimi-code"),"config.toml")}function In(P){let V=V2(P.environment);if(!G2(V))return{platform:"kimi-code",status:"n/a",configPath:V};try{if(!q2.test(B2(V,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:V}}catch(z){return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Failed to read ${V}: ${z instanceof Error?z.message:String(z)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:V}}import{readFileSync as Ka}from"node:fs";import{join as Fn}from"node:path";var yt="cc-safety-net",It="index.js",yn="openclaw.plugin.json",vn="package.json";var Sr="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as W2,lstatSync as K2,readdirSync as Y2,readFileSync as Z2}from"node:fs";import{dirname as Ga,join as Gt}from"node:path";import{fileURLToPath as X2}from"node:url";import{spawn as z2}from"node:child_process";function J2(P){return P.join(" ")}function $o(P,V,z){return[`Failed to run ${J2(P)}${V===null?"":` (exit ${V})`}.`,z.trim()].filter(Boolean).join(`
206
+ `}function $n(P){return[{name:"__init__.py",content:T2(P)},{name:"plugin.yaml",content:_2(P)}]}import{mkdirSync as $2,readdirSync as I2,readFileSync as O2,rmSync as Ro}from"node:fs";import{join as tn}from"node:path";var F2="__pycache__";function Po(P){let V=P.env.get("HERMES_HOME")?.trim();return V?V:tn(P.home,".hermes")}function Eo(P){return tn(Po(P),"plugins",Tt)}function Do(P){return P.startsWith(So)}function Ao(P,V){let z=Eo(P),Q=bt(z);if(Q&&(Q.isSymbolicLink()||!Q.isDirectory()))throw Error(`Refusing to ${V} ${z}: not a regular directory. Move or remove it and rerun ${V==="install"?"install":"uninstall"} --hermes-agent.`);return z}function Aa(P,V){let z=bt(P);if(!z)return;if(z.isSymbolicLink()||!z.isFile())throw Error(`Refusing to ${V} ${P}: not a regular file. Move or remove it.`);let Q=O2(P,"utf-8");if(!Do(Q))throw Error(`Refusing to ${V} unmanaged file at ${P}. Move or remove it.`);return Q}function _a(P){let V=Ao(P,"install"),z=$n(wt());if(z.map((te)=>Aa(tn(V,te.name),"overwrite")).every((te,ne)=>te===z[ne]?.content))return{path:V,alreadyInstalled:!0};return $2(V,{recursive:!0}),z.forEach((te)=>{kt(tn(V,te.name),te.content)}),{path:V,alreadyInstalled:!1}}function _o(P){let V=Ao(P,"remove");if(!bt(V))return[];return $n(wt()).filter((z)=>Aa(tn(V,z.name),"remove")!==void 0)}function Ta(P){let V=Ao(P,"remove");if(!bt(V))return{path:V,alreadyInstalled:!1};let z=_o(P);if(z.forEach((Q)=>{Ro(tn(V,Q.name))}),Ro(tn(V,F2),{recursive:!0,force:!0}),I2(V).length===0)Ro(V,{recursive:!0});return{path:V,alreadyInstalled:z.length>0}}var Cr="hermes-agent",$a=/^([^\s#][^:]*):/,j2=/^\s+([A-Za-z_][\w-]*):/,Ia=/^\s+-\s*(.*)$/;function N2(P){return P.trim().replace(/^(["'])(.*)\1$/,"$2")}function M2(P){let V=P.split(/\r?\n/),z=V.findIndex((ne)=>$a.exec(ne)?.[1]?.trim()==="plugins");if(z===-1)return[];let Q=V.slice(z+1),te=Q.findIndex((ne)=>$a.test(ne));return te===-1?Q:Q.slice(0,te)}function Oa(P,V){let z=M2(P),Q=z.findIndex((ce)=>j2.exec(ce)?.[1]===V);if(Q===-1)return[];let te=z.slice(Q+1),ne=te.findIndex((ce)=>!Ia.test(ce));return(ne===-1?te:te.slice(0,ne)).map((ce)=>N2(Ia.exec(ce)?.[1]??""))}function H2(P){try{return Fa(ja(Po(P),"config.yaml"),"utf-8")}catch{return}}function To(P){let V=H2(P)??"";return Oa(V,"enabled").includes(Tt)&&!Oa(V,"disabled").includes(Tt)}function Na(P){return/^# version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function U2(P,V){let z=bt(P);if(!z)return{error:`${V.name} is missing from ${P}; run install --hermes-agent`};if(z.isSymbolicLink()||!z.isFile())return{error:`${P} is a symlink or not a regular file; move or remove it`};try{let Q=Fa(P,"utf-8");if(!Do(Q))return{error:`Unmanaged ${V.name} occupies ${P}; move or remove it`};if(Na(Q)===wt()&&Q!==V.content)return{error:`Modified ${V.name} occupies ${P}; run install --hermes-agent to restore it`};return{content:Q}}catch(Q){return{error:`Failed to read ${P}: ${Q instanceof Error?Q.message:String(Q)}`}}}function Ma(P){let V=Eo(P.environment),z=ur(Cr,V);if(z)return z;let Q=$n(wt()).map((he)=>U2(ja(V,he.name),he)),te=Q.flatMap((he)=>("error"in he)?[he.error]:[]);if(te.length>0)return{platform:Cr,status:"n/a",configPath:V,errors:te};let ne=Q.some((he)=>("content"in he)&&Na(he.content)!==wt()),ce=ne?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!To(P.environment))return{platform:Cr,status:"disabled",method:"plugin directory",configPath:V,errors:[`${Tt} is not enabled in Hermes; run \`hermes plugins enable ${Tt}\``,...ce]};return{platform:Cr,status:"configured",method:"plugin directory",configPath:V,errors:ne?ce:void 0}}import{existsSync as G2,readFileSync as B2}from"node:fs";import{join as Ha}from"node:path";var q2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function V2(P){return Ha(P.env.get("KIMI_CODE_HOME")||Ha(P.home,".kimi-code"),"config.toml")}function In(P){let V=V2(P.environment);if(!G2(V))return{platform:"kimi-code",status:"n/a",configPath:V};try{if(!q2.test(B2(V,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:V}}catch(z){return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Failed to read ${V}: ${z instanceof Error?z.message:String(z)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:V}}import{readFileSync as Ka}from"node:fs";import{join as Fn}from"node:path";var Lt="cc-safety-net",It="index.js",yn="openclaw.plugin.json",vn="package.json";var Sr="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as W2,lstatSync as K2,readdirSync as Y2,readFileSync as Z2}from"node:fs";import{dirname as Ga,join as Gt}from"node:path";import{fileURLToPath as X2}from"node:url";import{spawn as z2}from"node:child_process";function J2(P){return P.join(" ")}function $o(P,V,z){return[`Failed to run ${J2(P)}${V===null?"":` (exit ${V})`}.`,z.trim()].filter(Boolean).join(`
207
207
  `)}function Io(P){let V={stdout:"",stderr:""};return P.stdout.setEncoding("utf-8"),P.stderr.setEncoding("utf-8"),P.stdout.on("data",(z)=>{V.stdout+=z}),P.stderr.on("data",(z)=>{V.stderr+=z}),V}function _t(P,V){return new Promise((z,Q)=>{let te=Xt([...P],process.env),ne=z2(te.cmd,te.args,{stdio:["ignore","pipe","pipe"]}),ce=Io(ne),he=()=>[ce.stdout,ce.stderr].filter(Boolean).join(`
208
208
  `),ye=V?.timeoutMs??120000,be=setTimeout(()=>{ne.kill(),Q(Error($o(P,null,`Timed out after ${ye}ms.
209
209
  ${he()}`.trim())))},ye);ne.on("error",(xe)=>{clearTimeout(be),Q(Error($o(P,null,`${xe.message}
210
- ${he()}`.trim())))}),ne.on("close",(xe)=>{if(clearTimeout(be),xe!==0){Q(Error($o(P,xe,he())));return}z(V?.stdoutOnly?ce.stdout:he())})})}async function Oo(P){for(let V of P)await _t(V)}async function Ua(P){for(let V of P)try{await _t(V)}catch(z){console.warn(z instanceof Error?z.message:String(z))}}var Fo=Gt("openclaw",yt),Q2=[It,yn,vn];function jo(P,V){if(P==="~")return V;if(P.startsWith("~/")||P.startsWith("~\\"))return Gt(V,P.slice(2));return P}function Ba(P){let V=P.env.get("OPENCLAW_STATE_DIR")?.trim();if(V)return jo(V,P.home);let z=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return z?Ga(jo(z,P.home)):Gt(P.home,".openclaw")}function qa(P){let V=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return V?jo(V,P.home):Gt(Ba(P),"openclaw.json")}function No(P){return Gt(Ba(P),"extensions",yt)}function ef(P){let V=Y2(P);if(V.length===0)return!0;if(V.some((te)=>!Q2.includes(te)))return!1;let z=Gt(P,It),Q=Lt(z);return Q!==void 0&&!Q.isSymbolicLink()&&Q.isFile()&&Z2(z,"utf-8").startsWith(Sr)}function Mo(P){let V=No(P),z=Lt(V);if(!z)return;if(!z.isSymbolicLink()&&z.isDirectory()&&ef(V))return;throw Error(`Refusing to modify ${V}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Va(){let P=Ga(X2(import.meta.url));return[Gt(P,Fo),Gt(P,"..",Fo),Gt(P,"..","..","..","dist",Fo)]}function Ho(P=Va()){return P.find((V)=>W2(V)&&K2(V).isDirectory())}function tf(P=Va()){let V=Ho(P);if(!V)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return V}function za(P=tf()){return[["openclaw","plugins","install",P,"--force","--accept-capabilities"],["openclaw","plugins","enable",yt]]}function nf(P){let V=(()=>{try{return JSON.parse(P)}catch{return}})(),z=ft(ft(V,"plugin"),"status");return typeof z==="string"?z:void 0}async function Ja(){let P=nf(await _t(["openclaw","plugins","inspect",yt,"--runtime","--json"],{stdoutOnly:!0}));if(P==="loaded")return;throw Error(`${P===void 0?`The ${yt} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${yt} plugin with status "${P}".`} Run \`openclaw plugins inspect ${yt} --runtime\` for details.`)}var Rr="openclaw",On=`run \`openclaw plugins enable ${yt}\``;function bn(P,V){let z=Fn(P,V),Q=Lt(z);if(!Q)return{error:`${V} is missing from ${z}; run install --openclaw`};if(Q.isSymbolicLink()||!Q.isFile())return{error:`${z} is a symlink or not a regular file; move or remove it`};try{return{content:Ka(z,"utf-8")}}catch(te){return{error:`Failed to read ${z}: ${te instanceof Error?te.message:String(te)}`}}}function Ya(P){try{return JSON.parse(At(P))}catch{return}}function rf(P){let V=bn(P,yn);if("error"in V)return V.error;if(ft(Ya(V.content),"id")===yt)return;return`${Fn(P,yn)} is not a valid ${yt} manifest; run install --openclaw`}function of(P){let V=bn(P,vn);if("error"in V)return V.error;let z=ft(ft(Ya(V.content),"openclaw"),"extensions");if(Array.isArray(z)&&z.includes(`./${It}`))return;return`${Fn(P,vn)} does not point OpenClaw at ${It}; run install --openclaw`}function Wa(P){return Array.isArray(P)?P.filter((V)=>typeof V==="string"):[]}function sf(P){let V=qa(P);if(!Lt(V))return`${yt} is not enabled; ${On}`;let z=(()=>{try{return JSON.parse(At(Ka(V,"utf-8")))}catch{return}})();if(z===void 0)return`Failed to read ${V}; fix it, then ${On}`;let Q=ft(z,"plugins");if(ft(Q,"enabled")===!1)return`plugins.enabled is false in ${V}; no OpenClaw plugin loads`;let te=ft(ft(ft(Q,"entries"),yt),"enabled");if(Wa(ft(Q,"deny")).includes(yt)||te===!1)return`${yt} is disabled in ${V}; ${On}`;let ne=Wa(ft(Q,"allow"));if(ne.length>0&&!ne.includes(yt))return`plugins.allow in ${V} does not list ${yt}; add it, then ${On}`;if(ne.includes(yt)||te===!0)return;return`${yt} is not enabled; ${On}`}function Za(P){return/^\/\/ version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function af(P,V,z){if(z===void 0)return[];let Q=bn(z,It);if("error"in Q||Za(Q.content)!==V)return[];return[It,yn,vn].flatMap((te)=>{let ne=bn(P,te),ce=bn(z,te);if("error"in ne||"error"in ce||ne.content===ce.content)return[];return[`Modified ${te} occupies ${Fn(P,te)}; run install --openclaw to restore it`]})}function Xa(P){let V=No(P.environment),z=ur(Rr,V);if(z)return z;let Q=bn(V,It),ne=["error"in Q?Q.error:Q.content.startsWith(Sr)?void 0:`Unmanaged ${It} occupies ${Fn(V,It)}; move or remove it`,rf(V),of(V)].filter((xe)=>xe!==void 0),ce="content"in Q?Za(Q.content):void 0,he=ne.length>0?ne:af(V,ce,Ho());if(he.length>0)return{platform:Rr,status:"n/a",configPath:V,errors:he};let ye=ce===wt()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],be=sf(P.environment);if(be)return{platform:Rr,status:"disabled",method:"plugin directory",configPath:V,errors:[be,...ye]};return{platform:Rr,status:"configured",method:"plugin directory",configPath:V,errors:ye.length>0?ye:void 0}}import{existsSync as mf,readFileSync as gf}from"node:fs";import{join as hf}from"node:path";import{existsSync as Pr,readFileSync as Uo,rmSync as lf}from"node:fs";import{join as Bt}from"node:path";import{pathToFileURL as cf}from"node:url";var Er="cc-safety-net",nn=`${Er}@latest`,el=["opencode.json","opencode.jsonc"],Qa="CCSafetyNetPlugin",df={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Dr(P){return P.env.get("OPENCODE_CONFIG_DIR")??Bt(P.env.get("XDG_CONFIG_HOME")||Bt(P.home,".config"),"opencode")}function uf(P){return Bt(Dr(P),el[0])}function tl(P){return el.map((V)=>Bt(Dr(P),V))}function nl(P){return Bt(P.env.get("XDG_CACHE_HOME")||Bt(P.home,".cache"),"opencode","packages",nn)}function rl(P){lf(nl(P),{recursive:!0,force:!0})}async function ol(P){let V=(await _t(["opencode","--version"],{stdoutOnly:!0})).trim(),z=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(V),Q=Number(z?.[1]),te=Number(z?.[2]),ne=Number(z?.[3]);if(!z||Q!==1&&Q!==2||Q===1&&(te<18||te===18&&ne<29)||Q===2&&te===0&&ne<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${V||"an unknown version"}.`);if(Q===2){for(let ce of tl(P)){if(!Pr(ce))continue;let he=Go(Uo(ce,"utf-8"),ce);if(["plugin","plugins"].some((be)=>{let xe=ft(he,be);return Array.isArray(xe)&&xe.some((Ie)=>Bo(Ie)&&(typeof Ie==="string"?Ie:ft(Ie,"package"))!==nn)}))throw Error(`Change the cc-safety-net package spec in ${ce} to ${nn}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[["opencode","plugin","add",nn],["opencode","plugin","update",nn]],afterInstall:async()=>{let ce=await _t(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(ce))return;throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.")}}}return rl(P),{commands:[["opencode","plugin","-g","-f",nn]],afterInstall:()=>pf(P)}}async function pf(P){let V=Bt(nl(P),"node_modules",Er),z=Bt(V,"package.json");if(!Pr(z))throw Error(`The OpenCode plugin cache at ${V} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${nn}\` for details.`);let Q=ft(JSON.parse(Uo(z,"utf-8")),"main");if(typeof Q!=="string")throw Error(`The cached OpenCode plugin at ${V} declares no "main" entry.`);let te=Bt(V,Q);if(typeof(await import(cf(te).href))[Qa]==="function")return;throw Error(`The cached OpenCode plugin at ${te} does not export a callable ${Qa}, so OpenCode would load nothing and fail open.`)}function Go(P,V){try{return JSON.parse(At(P))}catch(z){if(z instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${V}: ${z.message}`);throw z}}function Bo(P){let V=typeof P==="string"?P:ft(P,"package");return typeof V==="string"&&(V===Er||V.startsWith(`${Er}@`))}function qo(P){return["plugin","plugins"].some((V)=>{let z=ft(P,V);return Array.isArray(z)&&z.some(Bo)})}function ff(P,V){let Q=["plugin","plugins"].flatMap((te)=>{let ne=Xs(P,te,df);if(!ne)return[];let ce=[],he=0,ye=ne.start+1,be=P.slice(ne.start+1,ne.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let xe of be){if(xe[0].startsWith("//")||xe[0].startsWith("/*"))continue;let Ie=ne.start+1+xe.index;if(he===0)ye=Ie;if(xe[0]==="{"||xe[0]==="[")he++;if(xe[0]==="}"||xe[0]==="]")he--;if(he!==0||xe[0]===",")continue;let Xe=Ie+xe[0].length;if(Bo(JSON.parse(At(P.slice(ye,Xe)))))ce.push({start:ye,end:Xe})}return ce}).sort((te,ne)=>te.start-ne.start).reverse().reduce((te,ne)=>{let ce=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(te.slice(ne.end));if(ce?.[0].includes("/")){let he=ne.end+ce[0].length-1;return te.slice(0,ne.start)+te.slice(ne.end,he)+te.slice(he+1)}return fr(te,ne)},P);return Go(Q,V),Q}function il(P){rl(P);let V=tl(P),z=V.find((ne)=>Pr(ne)),Q=[],te=[];for(let ne of V){if(!Pr(ne))continue;try{let ce=Uo(ne,"utf-8");if(!qo(Go(ce,ne)))continue;kt(ne,ff(ce,ne)),te.push(ne)}catch(ce){Q.push(ce instanceof Error?ce.message:String(ce))}}if(Q.length>0)throw Error(Q.join(`
210
+ ${he()}`.trim())))}),ne.on("close",(xe)=>{if(clearTimeout(be),xe!==0){Q(Error($o(P,xe,he())));return}z(V?.stdoutOnly?ce.stdout:he())})})}async function Oo(P){for(let V of P)await _t(V)}async function Ua(P){for(let V of P)try{await _t(V)}catch(z){console.warn(z instanceof Error?z.message:String(z))}}var Fo=Gt("openclaw",Lt),Q2=[It,yn,vn];function jo(P,V){if(P==="~")return V;if(P.startsWith("~/")||P.startsWith("~\\"))return Gt(V,P.slice(2));return P}function Ba(P){let V=P.env.get("OPENCLAW_STATE_DIR")?.trim();if(V)return jo(V,P.home);let z=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return z?Ga(jo(z,P.home)):Gt(P.home,".openclaw")}function qa(P){let V=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return V?jo(V,P.home):Gt(Ba(P),"openclaw.json")}function No(P){return Gt(Ba(P),"extensions",Lt)}function ef(P){let V=Y2(P);if(V.length===0)return!0;if(V.some((te)=>!Q2.includes(te)))return!1;let z=Gt(P,It),Q=bt(z);return Q!==void 0&&!Q.isSymbolicLink()&&Q.isFile()&&Z2(z,"utf-8").startsWith(Sr)}function Mo(P){let V=No(P),z=bt(V);if(!z)return;if(!z.isSymbolicLink()&&z.isDirectory()&&ef(V))return;throw Error(`Refusing to modify ${V}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Va(){let P=Ga(X2(import.meta.url));return[Gt(P,Fo),Gt(P,"..",Fo),Gt(P,"..","..","..","dist",Fo)]}function Ho(P=Va()){return P.find((V)=>W2(V)&&K2(V).isDirectory())}function tf(P=Va()){let V=Ho(P);if(!V)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return V}function za(P=tf()){return[["openclaw","plugins","install",P,"--force","--accept-capabilities"]]}function nf(P){let V=(()=>{try{return JSON.parse(P)}catch{return}})(),z=ft(ft(V,"plugin"),"status");return typeof z==="string"?z:void 0}async function Ja(){let P=nf(await _t(["openclaw","plugins","inspect",Lt,"--runtime","--json"],{stdoutOnly:!0}));if(P==="loaded")return;throw Error(`${P===void 0?`The ${Lt} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${Lt} plugin with status "${P}".`} Run \`openclaw plugins inspect ${Lt} --runtime\` for details.`)}var Rr="openclaw",On=`run \`openclaw plugins enable ${Lt}\``;function bn(P,V){let z=Fn(P,V),Q=bt(z);if(!Q)return{error:`${V} is missing from ${z}; run install --openclaw`};if(Q.isSymbolicLink()||!Q.isFile())return{error:`${z} is a symlink or not a regular file; move or remove it`};try{return{content:Ka(z,"utf-8")}}catch(te){return{error:`Failed to read ${z}: ${te instanceof Error?te.message:String(te)}`}}}function Ya(P){try{return JSON.parse(At(P))}catch{return}}function rf(P){let V=bn(P,yn);if("error"in V)return V.error;if(ft(Ya(V.content),"id")===Lt)return;return`${Fn(P,yn)} is not a valid ${Lt} manifest; run install --openclaw`}function of(P){let V=bn(P,vn);if("error"in V)return V.error;let z=ft(ft(Ya(V.content),"openclaw"),"extensions");if(Array.isArray(z)&&z.includes(`./${It}`))return;return`${Fn(P,vn)} does not point OpenClaw at ${It}; run install --openclaw`}function Wa(P){return Array.isArray(P)?P.filter((V)=>typeof V==="string"):[]}function sf(P){let V=qa(P);if(!bt(V))return`${Lt} is not enabled; ${On}`;let z=(()=>{try{return JSON.parse(At(Ka(V,"utf-8")))}catch{return}})();if(z===void 0)return`Failed to read ${V}; fix it, then ${On}`;let Q=ft(z,"plugins");if(ft(Q,"enabled")===!1)return`plugins.enabled is false in ${V}; no OpenClaw plugin loads`;let te=ft(ft(ft(Q,"entries"),Lt),"enabled");if(Wa(ft(Q,"deny")).includes(Lt)||te===!1)return`${Lt} is disabled in ${V}; ${On}`;let ne=Wa(ft(Q,"allow"));if(ne.length>0&&!ne.includes(Lt))return`plugins.allow in ${V} does not list ${Lt}; add it, then ${On}`;if(ne.includes(Lt)||te===!0)return;return`${Lt} is not enabled; ${On}`}function Za(P){return/^\/\/ version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function af(P,V,z){if(z===void 0)return[];let Q=bn(z,It);if("error"in Q||Za(Q.content)!==V)return[];return[It,yn,vn].flatMap((te)=>{let ne=bn(P,te),ce=bn(z,te);if("error"in ne||"error"in ce||ne.content===ce.content)return[];return[`Modified ${te} occupies ${Fn(P,te)}; run install --openclaw to restore it`]})}function Xa(P){let V=No(P.environment),z=ur(Rr,V);if(z)return z;let Q=bn(V,It),ne=["error"in Q?Q.error:Q.content.startsWith(Sr)?void 0:`Unmanaged ${It} occupies ${Fn(V,It)}; move or remove it`,rf(V),of(V)].filter((xe)=>xe!==void 0),ce="content"in Q?Za(Q.content):void 0,he=ne.length>0?ne:af(V,ce,Ho());if(he.length>0)return{platform:Rr,status:"n/a",configPath:V,errors:he};let ye=ce===wt()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],be=sf(P.environment);if(be)return{platform:Rr,status:"disabled",method:"plugin directory",configPath:V,errors:[be,...ye]};return{platform:Rr,status:"configured",method:"plugin directory",configPath:V,errors:ye.length>0?ye:void 0}}import{existsSync as mf,readFileSync as gf}from"node:fs";import{join as hf}from"node:path";import{existsSync as Pr,readFileSync as Uo,rmSync as lf}from"node:fs";import{join as Bt}from"node:path";import{pathToFileURL as cf}from"node:url";var Er="cc-safety-net",nn=`${Er}@latest`,el=["opencode.json","opencode.jsonc"],Qa="CCSafetyNetPlugin",df={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Dr(P){return P.env.get("OPENCODE_CONFIG_DIR")??Bt(P.env.get("XDG_CONFIG_HOME")||Bt(P.home,".config"),"opencode")}function uf(P){return Bt(Dr(P),el[0])}function tl(P){return el.map((V)=>Bt(Dr(P),V))}function nl(P){return Bt(P.env.get("XDG_CACHE_HOME")||Bt(P.home,".cache"),"opencode","packages",nn)}function rl(P){lf(nl(P),{recursive:!0,force:!0})}async function ol(P){let V=(await _t(["opencode","--version"],{stdoutOnly:!0})).trim(),z=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(V),Q=Number(z?.[1]),te=Number(z?.[2]),ne=Number(z?.[3]);if(!z||Q!==1&&Q!==2||Q===1&&(te<18||te===18&&ne<29)||Q===2&&te===0&&ne<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${V||"an unknown version"}.`);if(Q===2){for(let ce of tl(P)){if(!Pr(ce))continue;let he=Go(Uo(ce,"utf-8"),ce);if(["plugin","plugins"].some((be)=>{let xe=ft(he,be);return Array.isArray(xe)&&xe.some((Ie)=>Bo(Ie)&&(typeof Ie==="string"?Ie:ft(Ie,"package"))!==nn)}))throw Error(`Change the cc-safety-net package spec in ${ce} to ${nn}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[["opencode","plugin","add",nn],["opencode","plugin","update",nn]],afterInstall:async()=>{let ce=await _t(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(ce))return;throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.")}}}return rl(P),{commands:[["opencode","plugin","-g","-f",nn]],afterInstall:()=>pf(P)}}async function pf(P){let V=Bt(nl(P),"node_modules",Er),z=Bt(V,"package.json");if(!Pr(z))throw Error(`The OpenCode plugin cache at ${V} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${nn}\` for details.`);let Q=ft(JSON.parse(Uo(z,"utf-8")),"main");if(typeof Q!=="string")throw Error(`The cached OpenCode plugin at ${V} declares no "main" entry.`);let te=Bt(V,Q);if(typeof(await import(cf(te).href))[Qa]==="function")return;throw Error(`The cached OpenCode plugin at ${te} does not export a callable ${Qa}, so OpenCode would load nothing and fail open.`)}function Go(P,V){try{return JSON.parse(At(P))}catch(z){if(z instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${V}: ${z.message}`);throw z}}function Bo(P){let V=typeof P==="string"?P:ft(P,"package");return typeof V==="string"&&(V===Er||V.startsWith(`${Er}@`))}function qo(P){return["plugin","plugins"].some((V)=>{let z=ft(P,V);return Array.isArray(z)&&z.some(Bo)})}function ff(P,V){let Q=["plugin","plugins"].flatMap((te)=>{let ne=Xs(P,te,df);if(!ne)return[];let ce=[],he=0,ye=ne.start+1,be=P.slice(ne.start+1,ne.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let xe of be){if(xe[0].startsWith("//")||xe[0].startsWith("/*"))continue;let Ie=ne.start+1+xe.index;if(he===0)ye=Ie;if(xe[0]==="{"||xe[0]==="[")he++;if(xe[0]==="}"||xe[0]==="]")he--;if(he!==0||xe[0]===",")continue;let Xe=Ie+xe[0].length;if(Bo(JSON.parse(At(P.slice(ye,Xe)))))ce.push({start:ye,end:Xe})}return ce}).sort((te,ne)=>te.start-ne.start).reverse().reduce((te,ne)=>{let ce=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(te.slice(ne.end));if(ce?.[0].includes("/")){let he=ne.end+ce[0].length-1;return te.slice(0,ne.start)+te.slice(ne.end,he)+te.slice(he+1)}return fr(te,ne)},P);return Go(Q,V),Q}function il(P){rl(P);let V=tl(P),z=V.find((ne)=>Pr(ne)),Q=[],te=[];for(let ne of V){if(!Pr(ne))continue;try{let ce=Uo(ne,"utf-8");if(!qo(Go(ce,ne)))continue;kt(ne,ff(ce,ne)),te.push(ne)}catch(ce){Q.push(ce instanceof Error?ce.message:String(ce))}}if(Q.length>0)throw Error(Q.join(`
211
211
  `));return{path:te[0]??z??uf(P),alreadyInstalled:te.length>0}}function sl(P){let V=[],z=Dr(P.environment),Q=["opencode.json","opencode.jsonc"];for(let te of Q){let ne=hf(z,te);if(mf(ne))try{let ce=gf(ne,"utf-8"),he=At(ce),ye=JSON.parse(he);if(qo(ye))return{platform:"opencode",status:"configured",method:"plugin array",configPath:ne,errors:V.length>0?V:void 0}}catch(ce){V.push(`Failed to parse ${te}: ${ce instanceof Error?ce.message:String(ce)}`)}}return{platform:"opencode",status:"n/a",errors:V.length>0?V:void 0}}import{join as yf}from"node:path";function Vo(P){return yf(P.home,".pi","agent","settings.json")}function zo(P){if(typeof P!=="string")return!1;return P==="npm:cc-safety-net"||P.startsWith("npm:cc-safety-net@")}function al(P){let V=Vo(P.environment),z=Ft(V);if(z.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(z.kind==="missing")return{platform:"pi",status:"n/a"};let Q=ft(z.value,"packages");if(!Array.isArray(Q))return{platform:"pi",status:"n/a"};let te=Q.find((he)=>zo(typeof he==="string"?he:ft(he,"source")));if(te===void 0)return{platform:"pi",status:"n/a"};let ne=ft(te,"extensions");if(Array.isArray(ne)&&ne.some((he)=>typeof he==="string"&&he.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:V,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:V}}var vf={amp:Gs,"antigravity-cli":Bs,"claude-code":Js,codex:Ws,"copilot-cli":ca,cursor:ya,"gemini-cli":va,"grok-build":Ea,"hermes-agent":Ma,"kimi-code":In,openclaw:Xa,opencode:sl,pi:al};function Ln(P,V,z){let Q={...z,cwd:V,environment:P};return Zn.map((te)=>bf(vf[te](Q)))}function bf(P){if(P.status==="not-inspected")return{platform:P.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:P.platform,detected:P.status!=="n/a",configured:P.status==="configured",inspectionStatus:P.status!=="n/a"?"verified":P.errors&&P.errors.length>0?"failed":"not-applicable",method:P.method,configPath:P.configPath,configPaths:P.configPaths,errors:P.errors}}import{join as Lf}from"node:path";var wf=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}]),kf=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([])})})}),xf={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 ll(P){let V=Lf(P.tmpdir,"cc-safety-net-self-test"),z=wf.map((Q)=>{let te=D(P,d("self-test",{command:Q.command},{kind:"command",shell:"auto"},{configCwd:V,executionCwd:V},Q.command),{guard:{dependencies:{loadPolicySnapshot:()=>kf,getModes:()=>xf,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),ne=Q.expectBlocked?"blocked":"allowed",ce=te.decision.kind==="deny"?"blocked":"allowed";return{command:Q.command,description:Q.description,expected:ne,actual:ce,passed:ne===ce,reason:te.decision.kind==="deny"?te.decision.reason:void 0,ruleId:te.decision.kind==="deny"?te.decision.ruleId:void 0}});return{passed:z.filter((Q)=>Q.passed).length,failed:z.filter((Q)=>!Q.passed).length,total:z.length,results:z}}function Jo(P){let V=xt({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},P);if(Ht(V.errors))return null;return{json:V.flags.json,skipUpdateCheck:V.flags.skipUpdateCheck}}async function cl(P,V={}){let z=await Pn(!V.json,()=>{let Q=Cf(P,V);return{ready:Q,finish:()=>Q}},()=>Rn(),{loadingMessage:"Checking system status…"});if(V.json)console.log(JSON.stringify(z,null,2));else Sf(z);return z.engineSelfTest.failed>0||z.findings.some((Q)=>Q.severity==="error")?1:0}async function Cf(P,V){let z=V.cwd??process.cwd(),Q=await sr(),te=Ln(P,z,{ampPluginListOutput:Q.ampPluginListOutput,codexPluginListOutput:Q.codexPluginListOutput,copilotCliVersion:Q.versions["copilot-cli"]}),ne=os(P,z),ce=is(P),he=E(P,{cwd:z}),ye=he.policy,be=R(ye,P.env),xe=G(ye,be.capabilities),Ie=tr(P,7),Xe=js(P,z),et=V.skipUpdateCheck?{currentVersion:wt(),latestVersion:null,updateAvailable:!1}:await Wt(),Re={hooks:te,engineSelfTest:ll(P),userConfig:ne.userConfig,projectConfig:ne.projectConfig,configState:Ne(he),effectiveRules:ne.effectiveRules,environment:ce,effectiveSafety:{selectedPreset:ye.safety.level??"standard",level:be.effectiveLevel,capabilities:be.capabilities,ruleOverrides:ye.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(xe).filter(([,at])=>at.source==="rule_override"&&at.override==="off"&&at.inheritedEnabled&&at.changesInherited).map(([at])=>at),ruleCounts:{stored:Object.keys(ye.destructiveCommandRuleOverrides).length,effective:Object.values(xe).filter((at)=>at.changesInherited).length},...he.policyScopes?{policyScopes:he.policyScopes}:{}},...Xe.length>0?{v2Leftovers:Xe}:{},posture:bs(P,ne.userConfig.path),activity:Ie,update:et,system:Q};return{...Re,findings:as(Re)}}function Sf(P){console.log(),console.log(cs(P.hooks)),console.log(),console.log(ds(P.engineSelfTest)),console.log(),console.log(us(P)),console.log(),console.log(ps(P.environment)),console.log(),console.log(fs(P)),console.log(),console.log(ms(P.findings)),console.log(),console.log(gs(P.activity)),console.log(),console.log(ys(P.system)),console.log(),console.log(hs(P.update)),console.log(vs(P))}import{existsSync as Rf}from"node:fs";var Pf=/^[A-Za-z0-9_@%+=:,./-]+$/,dl="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Wo(P){let V=xt({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},P);if(Ht(V.errors))return console.error(dl),console.error("Pass -- before a command that starts with dashes."),null;if(V.values.cwd!==void 0&&!Rf(V.values.cwd))return console.error(`Error: --cwd path does not exist: ${V.values.cwd}`),null;let z=V.positionals.length===1?V.positionals[0]:V.positionals.map((Q)=>Pf.test(Q)?Q:`'${Q.replaceAll("'","'\\''")}'`).join(" ");if(!z)return console.error("Error: No command provided"),console.error(dl),null;return{json:V.flags.json,cwd:V.values.cwd,command:z}}function ul(P){if(P)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 pl(P,V){let Q=V-18;return[`${P.dtl}${P.dh.repeat(V)}${P.dtr}`,`${P.dv} Command Analysis${" ".repeat(Q)}${P.dv}`,`${P.dbl}${P.dh.repeat(V)}${P.dbr}`]}function Ko(P){return JSON.stringify(P)}function fl(P,V=0){return`[${P.map((Q,te)=>ls(Q,te,V)).join(",")}]`}function jn(P,V,z=70){let Q=P.split(" "),te=[],ne="";for(let ce of Q)if(ne&&ne.length+ce.length+1>z)te.push(ne),ne=ce;else ne=ne?`${ne} ${ce}`:ce;if(ne)te.push(ne);return te.map((ce,he)=>he===0?ce:`${V}${ce}`)}function ml(P,V,z){let Q=[];switch(P.type){case"parse":return null;case"env-strip":return Q.push(""),Q.push(`STEP ${V} ${z.h} Strip environment variables`),Q.push(` Removed: ${P.envVars.map((te)=>`${te}=<redacted>`).join(", ")}`),Q.push(` Tokens: ${Ko(P.output)}`),{lines:Q,incrementStep:!0};case"leading-tokens-stripped":return Q.push(""),Q.push(`STEP ${V} ${z.h} Strip wrappers`),Q.push(` Removed: ${P.removed.join(", ")}`),Q.push(` Tokens: ${Ko(P.output)}`),{lines:Q,incrementStep:!0};case"shell-wrapper":return Q.push(""),Q.push(`STEP ${V} ${z.h} Detect shell wrapper`),Q.push(` Wrapper: ${P.wrapper} -c`),Q.push(` Inner: ${P.innerCommand}`),{lines:Q,incrementStep:!0};case"interpreter":{if(Q.push(""),Q.push(`STEP ${V} ${z.h} Detect interpreter`),Q.push(` Interpreter: ${P.interpreter}`),Q.push(` Code: ${P.codeArg}`),P.paranoidBlocked)Q.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:Q,incrementStep:!0}}case"busybox":return Q.push(""),Q.push(`STEP ${V} ${z.h} Busybox wrapper`),Q.push(` Subcommand: ${P.subcommand}`),{lines:Q,incrementStep:!0};case"transparent-wrapper":return Q.push(""),Q.push(`STEP ${V} ${z.h} Transparent wrapper`),Q.push(` Wrapper: ${P.wrapper}`),Q.push(` Tokens: ${Ko(P.output)}`),{lines:Q,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(Q.push(""),Q.push(`STEP ${V} ${z.h} Match rules`),Q.push(` Rule: ${P.rule}()`),P.matched)Q.push(" Result: MATCHED");else Q.push(" Result: No match");return{lines:Q,incrementStep:!0}}case"worktree-relaxation":return Q.push(""),Q.push(`STEP ${V} ${z.h} Worktree relaxation`),Q.push(` Mode: ${o.worktree.name}`),Q.push(` Git cwd: ${P.gitCwd}`),Q.push(" Result: Allowed local discard in linked worktree"),{lines:Q,incrementStep:!0};case"temp-root-relaxation":return Q.push(""),Q.push(`STEP ${V} ${z.h} Temp-root relaxation`),Q.push(` Git cwd: ${P.gitCwd}`),Q.push(" Result: Allowed git discard in a temp-root repository"),{lines:Q,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(P.embeddedCommandFound)return Q.push(""),Q.push(`STEP ${V} ${z.h} Fallback scan`),Q.push(` Found: ${P.embeddedCommandFound}`),{lines:Q,incrementStep:!0};return null}case"custom-rules-check":{if(P.rulesChecked){if(Q.push(""),Q.push(`STEP ${V} ${z.h} Custom rules`),P.matched)Q.push(" Result: MATCHED");else Q.push(" Result: No match");return{lines:Q,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(P.matched)return Q.push(""),Q.push(`STEP ${V} ${z.h} Dangerous text check`),Q.push(` Token: ${P.token}`),Q.push(" Result: MATCHED"),{lines:Q,incrementStep:!0};return null}case"strict-unparseable":return Q.push(""),Q.push(`STEP ${V} ${z.h} Strict mode check`),Q.push(` Command: ${P.rawCommand}`),Q.push(" Result: ✗ UNPARSEABLE"),{lines:Q,incrementStep:!0};case"segment-skipped":return null;case"error":return Q.push(""),Q.push(`ERROR: ${P.message}`),{lines:Q,incrementStep:!1};default:return P}}function Yo(P,V){let z=ul(V?.asciiOnly??!1),Q=58,te=[],ne=1;te.push(...pl(z,58)),te.push("");let ce=P.trace.steps.find((Re)=>Re.type==="error");if(ce&&ce.type==="error"){te.push("ERROR"),te.push(` ${ce.message}`),te.push(""),te.push("RESULT"),te.push(` Status: ${P.result==="blocked"?dt.red("BLOCKED"):dt.green("ALLOWED")}`),te.push(""),te.push("CONFIG");let Re=P.configSource??"none";return te.push(` Path: ${Re}`),te.join(`
212
- `)}let he=P.trace.steps.find((Re)=>Re.type==="parse");if(he&&he.type==="parse"){te.push("INPUT"),te.push(` ${he.input}`),te.push(""),te.push(`STEP ${ne} ${z.h} Split shell commands`),ne++;for(let Re=0;Re<he.segments.length;Re++){let at=he.segments[Re];if(at){let ct=Math.random();te.push(` Segment ${Re+1}: ${fl(at,ct)}`)}}}let ye=P.trace.segments,be=ye.length>1;for(let Re of ye){if(be){te.push("");let pt="";if(he&&he.type==="parse"){let Xr=he.segments[Re.index];if(Xr)pt=Xr.join(" ")}let mt=54,gt=pt,ut=` Segment ${Re.index+1}: `,vt=" ";if(pt){if(ut.length+pt.length+vt.length>mt){let Hd=mt-ut.length-vt.length;gt=`${pt.substring(0,Hd-1)}…`}}let Dt=pt?`${ut}${gt}${vt}`:` Segment ${Re.index+1} `,Nd=pt?`${ut}${dt.cyan(gt)}${vt}`:Dt,$i=58-Dt.length,Ii=Math.floor($i/2),Md=$i-Ii;te.push(`${z.sh.repeat(Ii)}${Nd}${z.sh.repeat(Md)}`)}if(Re.steps.find((pt)=>pt.type==="segment-skipped")){te.push(""),te.push(" (skipped — prior segment blocked)");continue}let ct=!1,lt=!1;for(let pt of Re.steps){let mt=ml(pt,ne,z);if(mt){if(lt=!0,pt.type==="recurse"){te.push("");let gt=" RECURSING ",ut=58-gt.length-4;te.push(` ${z.tl}${z.h}${gt}${z.h.repeat(ut)}`),te.push(` ${z.v}`),ct=!0;continue}for(let gt of mt.lines)if(ct)te.push(` ${z.v} ${gt}`);else te.push(gt);if(mt.incrementStep)ne++}}if(ct)te.push(` ${z.v}`),te.push(` ${z.bl}${z.h.repeat(56)}`);if(!lt)te.push(""),te.push(` ${dt.green("✓")} Allowed (no matching rules)`)}if(te.push(""),te.push("RESULT"),P.result==="blocked"){if(te.push(` Status: ${dt.red("BLOCKED")}`),P.customRule){if(te.push(` Rule: ${P.customRule.id}`),P.customRule.rulebook)te.push(` Rulebook: ${P.customRule.rulebook.name} ${P.customRule.rulebook.version}`);if(P.customRule.source)te.push(` Source: ${P.customRule.source}`);if(P.customRule.override)te.push(` Override: reason ${P.customRule.override.reason}`)}if(P.reason){let Re=jn(P.reason," ");te.push(` Reason: ${Re[0]}`);for(let at=1;at<Re.length;at++)te.push(Re[at]??"")}}else te.push(` Status: ${dt.green("ALLOWED")}`);te.push(""),te.push("CONFIG");let xe=P.configSource??"none",Ie=P.configValid?"":" (invalid)";te.push(` Path: ${xe}${Ie}`);let Xe=P.safetyPresetScope;te.push(` Safety preset: ${P.selectedPreset??"standard"}${Xe?` (${rr(Xe)})`:""}`),te.push(` Effective capabilities: ${P.effectiveLevel}`);let et=Object.entries(P.destructiveCommandRuleOverrides??{});if(te.push(` Rule customizations: ${et.length}`),P.ruleActivation)te.push(` Rule activation: ${P.ruleActivation.id} — ${P.ruleActivation.enabled?"on":"off"} via ${P.ruleActivation.source}`);return te.join(`
213
- `)}function Zo(P){return JSON.stringify(P,null,2)}import{resolve as Tf}from"node:path";var Ef=["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 gl(P){let V=0,z={allocateSegment(){return V++},getNextSegmentIndex(){return V},recordGlobal(Q){P.record({kind:"step",scope:"global",step:Q})},recordSegment(Q,te=z.currentSegmentIndex){if(te===void 0)return;P.record({kind:"step",scope:"segment",segmentIndex:te,step:Q})}};return z}function hl(P={}){let V=[],z=P.maxEvents??512,Q={maxTextLength:P.maxTextLength??2048,maxListLength:P.maxListLength??128,maxObjectProperties:P.maxObjectProperties??P.maxListLength??128,maxDepth:P.maxDepth??16},te,ne=new Set;return{record(ce){if(te)return;if(!ce||V.length>=z)return;try{V.push(ei(Df(ce,Q,ne)))}catch{}},finish(){if(te)return te;return te=ei({events:Object.freeze(V)}),te}}}function Df(P,V,z){if(P.kind!=="step")throw TypeError("invalid trace event");let{scope:Q,step:te}=P;Ar(te,z,V);let ne=Xo(te,V,z);if(Q==="global")return{kind:"step",scope:"global",step:ne};if(Q!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:P.segmentIndex,step:ne}}function Ar(P,V,z,Q=0,te=new WeakSet){if(typeof P==="string"){let he=P.slice(0,z.maxTextLength);if(!Ge(he))return;for(let ye of Ze(he))for(let be of ye.match(/[^\s"'()$]+/g)??[])V.add(yl(be));return}if(!P||typeof P!=="object"||Q>=z.maxDepth||te.has(P))return;if(te.add(P),Array.isArray(P)){let he=Math.min(P.length,z.maxListLength);for(let ye=0;ye<he;ye++)Ar(P[ye],V,z,Q+1,te);return}let ne=0,ce=new Set;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ne>=z.maxObjectProperties)break;ne++,Ar(he,V,z);let ye=Qo(he,z,V);if(ce.has(ye))continue;ce.add(ye),Ar(P[he],V,z,Q+1,te)}}function Xo(P,V,z,Q=0,te=new WeakSet){if(typeof P==="string")return Qo(P,V,z);if(!P||typeof P!=="object")return P;if(Q>=V.maxDepth)return;if(te.has(P))return;if(te.add(P),Array.isArray(P)){let he=[],ye=Math.min(P.length,V.maxListLength);for(let be=0;be<ye;be++)he.push(Xo(P[be],V,z,Q+1,te));return he}let ne={},ce=0;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ce>=V.maxObjectProperties)break;ce++;let ye=Qo(he,V,z);if(Object.hasOwn(ne,ye))continue;Object.defineProperty(ne,ye,{value:Xo(P[he],V,z,Q+1,te),enumerable:!0,configurable:!0,writable:!0})}return ne}function Qo(P,V,z){let Q=P.slice(0,V.maxTextLength),te=Ge(Q)?Ue(Q):Q,ne=z.size>0?_f(te,z):te;return(Af(ne)?ke(ne):ne).slice(0,V.maxTextLength)}function Af(P){return P.includes("PRIVATE KEY")||P.includes("://")||P.includes("eyJ")||P.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(P)||P.length>=14&&Ef.some((V)=>P.includes(V))||P.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(P)}function _f(P,V){return P.replace(/[^\s"'()$]+/g,(z)=>V.has(yl(z))?"<redacted>":z)}function yl(P){let V=2166136261,z=2166136261;for(let Q=0;Q<P.length;Q++)V=Math.imul(V^P.charCodeAt(Q),16777619),z=Math.imul(z^P.charCodeAt(P.length-Q-1),16777619);return`${V>>>0}:${z>>>0}:${P.length}`}function ei(P){if(P&&typeof P==="object"&&!Object.isFrozen(P)){for(let V of Object.values(P))ei(V);Object.freeze(P)}return P}function Nn(P,V={},z){let Q=Tf(V.cwd??process.cwd()),te=V.policySnapshot??E(z,{cwd:Q,userConfigDir:V.userConfigDir}),ne=R(te.policy,z.env),ce=Fe({policySnapshot:te,effectiveCapabilities:ne.capabilities,strict:ne.strict,paranoidRm:ne.paranoidRm,paranoidInterpreters:ne.paranoidInterpreters,worktreeMode:ne.worktreeMode}),he={effectiveLevel:ce.effectiveLevel,selectedPreset:te.policy.safety.level??"standard",...te.policyScopes?{safetyPresetScope:te.policyScopes.levelScope}:{},effectiveCapabilities:ce.effectiveCapabilities,destructiveCommandRuleOverrides:te.policy.destructiveCommandRuleOverrides},{configSource:ye,configValid:be}=If(z,{cwd:Q,userConfigDir:V.userConfigDir});if(!P||!P.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:ye,configValid:be,...he};let xe=h(P,"auto");if(xe.status==="limited")throw new y;let Ie=xe.dialect==="powershell"?h(P,"posix"):xe,Xe=st(Ie),et=hl(),Re=gl(et);Re.recordGlobal({type:"parse",input:P,segments:Xe.map((Dt)=>[...Dt])});let at=d("Bash",{command:P},{kind:"command",shell:"auto"},{configCwd:Q,executionCwd:Q},P),ct=W(at,{environment:z,trace:Re,dependencies:{loadPolicySnapshot:()=>te}}),lt=ct.decision.kind==="deny"?ct.decision:null;if(lt&&(ct.stage==="policy-protection"||ct.stage==="secret-protection")){let Dt=$f(lt);return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Dt.rule,matched:!0,reason:lt.reason}]}]},result:"blocked",reason:k(lt.reason),segment:k(vl(lt,P)),...Dt.ruleId?{ruleId:k(Dt.ruleId)}:{},configSource:ye,configValid:be,...he}}let pt=Re.getNextSegmentIndex();if(lt&&pt>0&&pt<Xe.length)Re.recordSegment({type:"segment-skipped",index:pt,reason:"prior-segment-blocked"},pt);let mt=et.finish(),gt=lt?.ruleId??Of(at,te,ne,z),ut=U.find((Dt)=>Dt.id===gt&&Dt.activationCapability),vt=ut?ce.policy.effectiveDestructiveCommandRules[ut.id]:void 0;return{trace:jf(mt),result:lt?"blocked":"allowed",reason:lt?k(lt.reason):void 0,segment:lt?k(vl(lt,P)):void 0,ruleId:lt?.ruleId?k(lt.ruleId):void 0,customRule:Ff(Nf(lt?.ruleId,te)),configSource:ye,configValid:be,...he,...ut&&vt?{ruleActivation:{id:ut.id,...vt}}:{}}}function vl(P,V){return P.evidence?.segment??V}function $f(P){if(P.reason===$e)return{ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};if(P.reason===Me)return{ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};if(P.reason===x)return{ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};return{ruleId:P.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"}}function If(P,V){let z=F(V.cwd),Q=M(P,V),te=K(P,{cwd:V.cwd,userConfigDir:V.userConfigDir});try{if(n(te.projectConfigTarget)!==null){if(Jt(te.projectConfigTarget).errors.length===0)return{configSource:z,configValid:!0};return{configSource:z,configValid:!1}}}catch(ne){if(ne instanceof r)return{configSource:z,configValid:!1};throw ne}try{if(n(te.userConfigTarget)!==null){let ne=Jt(te.userConfigTarget);return{configSource:Q,configValid:ne.errors.length===0}}return{configSource:null,configValid:!0}}catch(ne){if(ne instanceof r)return{configSource:Q,configValid:!1};throw ne}}function Of(P,V,z,Q){let te=V.policy,ne=Ee({...te,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...te.destructiveCommandRuleOverrides,...Object.fromEntries(U.flatMap((he)=>he.activationCapability?[[he.id,"on"]]:[]))}},V.state==="degraded"?{diagnostics:V.diagnostics,reason:V.reason}:void 0),ce=W(P,{environment:Q,dependencies:{loadPolicySnapshot:()=>ne,getModes:()=>({...z,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return ce.decision.kind==="deny"?ce.decision.ruleId:void 0}function Ff(P){if(!P)return;return{id:k(P.id),...P.rulebook?{rulebook:{name:k(P.rulebook.name),version:k(P.rulebook.version)}}:{},...P.source?{source:k(P.source)}:{},...P.override?{override:{type:"reason",reason:k(P.override.reason)}}:{}}}function jf(P){let V=P.events.flatMap((Q)=>Q.kind==="step"&&Q.scope==="global"?[Q.step]:[]),z=new Map;for(let Q of P.events){if(Q.kind!=="step"||Q.scope!=="segment")continue;let te=z.get(Q.segmentIndex)??{index:Q.segmentIndex,steps:[]};te.steps.push(Q.step),z.set(Q.segmentIndex,te)}return{steps:V,segments:[...z.values()]}}function Nf(P,V){let z=P?.replace(/^custom\./,"");if(!z||!V.policy.rules.some((Q)=>Q.name===z))return;return V.ruleMetadata[z]??Object.freeze({id:z})}function bl(P){return new Promise((V)=>{process.stdout.write(`${P}
214
- `,()=>V())})}async function Ll(P,V){let z=Wo(V);if(!z)return 1;try{let Q=Nn(z.command,{cwd:z.cwd},P),te=!!process.env.NO_COLOR||!process.stdout.isTTY;return await bl(z.json?Zo(Q):Yo(Q,{asciiOnly:te})),0}catch(Q){let te=Mf(Q instanceof p?Q.cause:Q);if(te===void 0)throw Q;if(z.json)return await bl(JSON.stringify({error:te})),1;return console.error(te),1}}function Mf(P){if(P instanceof y)return P.message;if(P instanceof f)return P.message;if(P instanceof s&&a[P.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var wl="2.4.9",Ot=" ",rn="cc-safety-net";function kl(P){return P.argument?`${P.flags} ${P.argument}`:P.flags}function Hf(P){return Math.max(...P.map((V)=>kl(V).length))}function Uf(P){return Math.max(...P.map((V)=>V.usage.length))}function Gf(P){return Math.max(...P.map((V)=>`${rn} ${V.usage}`.length))}function Bf(P,V){let z=`${rn} ${P.usage}`;return`${Ot}${z.padEnd(V+2)}${P.description}`}function qt(P,V){return`${Ot}${P.padEnd(Math.max(40,P.length+2))}${V}`}function wn(P,V=console.log){let z=[];if(z.push(`${rn} ${P.name}`),z.push(""),z.push(`${Ot}${P.description}`),z.push(""),z.push("USAGE:"),z.push(`${Ot}${rn} ${P.usage}`),z.push(""),P.subcommands&&P.subcommands.length>0){z.push("SUBCOMMANDS:");let Q=Uf(P.subcommands);for(let te of P.subcommands)z.push(`${Ot}${te.usage.padEnd(Q+2)}${te.description}`);z.push("")}if(P.options.length>0){z.push("OPTIONS:");let Q=Hf(P.options);for(let te of P.options){let ne=kl(te),ce=te.default?`${te.description} (default: ${te.default})`:te.description;z.push(`${Ot}${ne.padEnd(Q+2)}${ce}`)}z.push("")}if(P.examples&&P.examples.length>0){z.push("EXAMPLES:");for(let Q of P.examples)z.push(`${Ot}${Q}`)}V(z.join(`
212
+ `)}let he=P.trace.steps.find((Re)=>Re.type==="parse");if(he&&he.type==="parse"){te.push("INPUT"),te.push(` ${he.input}`),te.push(""),te.push(`STEP ${ne} ${z.h} Split shell commands`),ne++;for(let Re=0;Re<he.segments.length;Re++){let at=he.segments[Re];if(at){let ct=Math.random();te.push(` Segment ${Re+1}: ${fl(at,ct)}`)}}}let ye=P.trace.segments,be=ye.length>1;for(let Re of ye){if(be){te.push("");let pt="";if(he&&he.type==="parse"){let Xr=he.segments[Re.index];if(Xr)pt=Xr.join(" ")}let mt=54,gt=pt,ut=` Segment ${Re.index+1}: `,yt=" ";if(pt){if(ut.length+pt.length+yt.length>mt){let Hd=mt-ut.length-yt.length;gt=`${pt.substring(0,Hd-1)}…`}}let Dt=pt?`${ut}${gt}${yt}`:` Segment ${Re.index+1} `,Nd=pt?`${ut}${dt.cyan(gt)}${yt}`:Dt,$i=58-Dt.length,Ii=Math.floor($i/2),Md=$i-Ii;te.push(`${z.sh.repeat(Ii)}${Nd}${z.sh.repeat(Md)}`)}if(Re.steps.find((pt)=>pt.type==="segment-skipped")){te.push(""),te.push(" (skipped — prior segment blocked)");continue}let ct=!1,lt=!1;for(let pt of Re.steps){let mt=ml(pt,ne,z);if(mt){if(lt=!0,pt.type==="recurse"){te.push("");let gt=" RECURSING ",ut=58-gt.length-4;te.push(` ${z.tl}${z.h}${gt}${z.h.repeat(ut)}`),te.push(` ${z.v}`),ct=!0;continue}for(let gt of mt.lines)if(ct)te.push(` ${z.v} ${gt}`);else te.push(gt);if(mt.incrementStep)ne++}}if(ct)te.push(` ${z.v}`),te.push(` ${z.bl}${z.h.repeat(56)}`);if(!lt)te.push(""),te.push(` ${dt.green("✓")} Allowed (no matching rules)`)}if(te.push(""),te.push("RESULT"),P.result==="blocked"){if(te.push(` Status: ${dt.red("BLOCKED")}`),P.customRule){if(te.push(` Rule: ${P.customRule.id}`),P.customRule.rulebook)te.push(` Rulebook: ${P.customRule.rulebook.name} ${P.customRule.rulebook.version}`);if(P.customRule.source)te.push(` Source: ${P.customRule.source}`);if(P.customRule.override)te.push(` Override: reason ${P.customRule.override.reason}`)}if(P.reason){let Re=jn(P.reason," ");te.push(` Reason: ${Re[0]}`);for(let at=1;at<Re.length;at++)te.push(Re[at]??"")}}else te.push(` Status: ${dt.green("ALLOWED")}`);te.push(""),te.push("CONFIG");let xe=P.configSource??"none",Ie=P.configValid?"":" (invalid)";te.push(` Path: ${xe}${Ie}`);let Xe=P.safetyPresetScope;te.push(` Safety preset: ${P.selectedPreset??"standard"}${Xe?` (${rr(Xe)})`:""}`),te.push(` Effective capabilities: ${P.effectiveLevel}`);let et=Object.entries(P.destructiveCommandRuleOverrides??{});if(te.push(` Rule customizations: ${et.length}`),P.ruleActivation)te.push(` Rule activation: ${P.ruleActivation.id} — ${P.ruleActivation.enabled?"on":"off"} via ${P.ruleActivation.source}`);return te.join(`
213
+ `)}function Zo(P){return JSON.stringify(P,null,2)}import{resolve as Tf}from"node:path";var Ef=["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 gl(P){let V=0,z={allocateSegment(){return V++},getNextSegmentIndex(){return V},recordGlobal(Q){P.record({kind:"step",scope:"global",step:Q})},recordSegment(Q,te=z.currentSegmentIndex){if(te===void 0)return;P.record({kind:"step",scope:"segment",segmentIndex:te,step:Q})}};return z}function hl(P={}){let V=[],z=P.maxEvents??512,Q={maxTextLength:P.maxTextLength??2048,maxListLength:P.maxListLength??128,maxObjectProperties:P.maxObjectProperties??P.maxListLength??128,maxDepth:P.maxDepth??16},te,ne=new Set;return{record(ce){if(te)return;if(!ce||V.length>=z)return;try{V.push(ei(Df(ce,Q,ne)))}catch{}},finish(){if(te)return te;return te=ei({events:Object.freeze(V)}),te}}}function Df(P,V,z){if(P.kind!=="step")throw TypeError("invalid trace event");let{scope:Q,step:te}=P;Ar(te,z,V);let ne=Xo(te,V,z);if(Q==="global")return{kind:"step",scope:"global",step:ne};if(Q!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:P.segmentIndex,step:ne}}function Ar(P,V,z,Q=0,te=new WeakSet){if(typeof P==="string"){let he=P.slice(0,z.maxTextLength);if(!Ge(he))return;for(let ye of Ze(he))for(let be of ye.match(/[^\s"'()$]+/g)??[])V.add(yl(be));return}if(!P||typeof P!=="object"||Q>=z.maxDepth||te.has(P))return;if(te.add(P),Array.isArray(P)){let he=Math.min(P.length,z.maxListLength);for(let ye=0;ye<he;ye++)Ar(P[ye],V,z,Q+1,te);return}let ne=0,ce=new Set;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ne>=z.maxObjectProperties)break;ne++,Ar(he,V,z);let ye=Qo(he,z,V);if(ce.has(ye))continue;ce.add(ye),Ar(P[he],V,z,Q+1,te)}}function Xo(P,V,z,Q=0,te=new WeakSet){if(typeof P==="string")return Qo(P,V,z);if(!P||typeof P!=="object")return P;if(Q>=V.maxDepth)return;if(te.has(P))return;if(te.add(P),Array.isArray(P)){let he=[],ye=Math.min(P.length,V.maxListLength);for(let be=0;be<ye;be++)he.push(Xo(P[be],V,z,Q+1,te));return he}let ne={},ce=0;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ce>=V.maxObjectProperties)break;ce++;let ye=Qo(he,V,z);if(Object.hasOwn(ne,ye))continue;Object.defineProperty(ne,ye,{value:Xo(P[he],V,z,Q+1,te),enumerable:!0,configurable:!0,writable:!0})}return ne}function Qo(P,V,z){let Q=P.slice(0,V.maxTextLength),te=Ge(Q)?Ue(Q):Q,ne=z.size>0?_f(te,z):te;return(Af(ne)?ke(ne):ne).slice(0,V.maxTextLength)}function Af(P){return P.includes("PRIVATE KEY")||P.includes("://")||P.includes("eyJ")||P.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(P)||P.length>=14&&Ef.some((V)=>P.includes(V))||P.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(P)}function _f(P,V){return P.replace(/[^\s"'()$]+/g,(z)=>V.has(yl(z))?"<redacted>":z)}function yl(P){let V=2166136261,z=2166136261;for(let Q=0;Q<P.length;Q++)V=Math.imul(V^P.charCodeAt(Q),16777619),z=Math.imul(z^P.charCodeAt(P.length-Q-1),16777619);return`${V>>>0}:${z>>>0}:${P.length}`}function ei(P){if(P&&typeof P==="object"&&!Object.isFrozen(P)){for(let V of Object.values(P))ei(V);Object.freeze(P)}return P}function Nn(P,V={},z){let Q=Tf(V.cwd??process.cwd()),te=V.policySnapshot??E(z,{cwd:Q,userConfigDir:V.userConfigDir}),ne=R(te.policy,z.env),ce=Fe({policySnapshot:te,effectiveCapabilities:ne.capabilities,strict:ne.strict,paranoidRm:ne.paranoidRm,paranoidInterpreters:ne.paranoidInterpreters,worktreeMode:ne.worktreeMode}),he={effectiveLevel:ce.effectiveLevel,selectedPreset:te.policy.safety.level??"standard",...te.policyScopes?{safetyPresetScope:te.policyScopes.levelScope}:{},effectiveCapabilities:ce.effectiveCapabilities,destructiveCommandRuleOverrides:te.policy.destructiveCommandRuleOverrides},{configSource:ye,configValid:be}=If(z,{cwd:Q,userConfigDir:V.userConfigDir});if(!P||!P.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:ye,configValid:be,...he};let xe=h(P,"auto");if(xe.status==="limited")throw new y;let Ie=xe.dialect==="powershell"?h(P,"posix"):xe,Xe=st(Ie),et=hl(),Re=gl(et);Re.recordGlobal({type:"parse",input:P,segments:Xe.map((Dt)=>[...Dt])});let at=d("Bash",{command:P},{kind:"command",shell:"auto"},{configCwd:Q,executionCwd:Q},P),ct=W(at,{environment:z,trace:Re,dependencies:{loadPolicySnapshot:()=>te}}),lt=ct.decision.kind==="deny"?ct.decision:null;if(lt&&(ct.stage==="policy-protection"||ct.stage==="secret-protection")){let Dt=$f(lt);return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Dt.rule,matched:!0,reason:lt.reason}]}]},result:"blocked",reason:k(lt.reason),segment:k(vl(lt,P)),...Dt.ruleId?{ruleId:k(Dt.ruleId)}:{},configSource:ye,configValid:be,...he}}let pt=Re.getNextSegmentIndex();if(lt&&pt>0&&pt<Xe.length)Re.recordSegment({type:"segment-skipped",index:pt,reason:"prior-segment-blocked"},pt);let mt=et.finish(),gt=lt?.ruleId??Of(at,te,ne,z),ut=U.find((Dt)=>Dt.id===gt&&Dt.activationCapability),yt=ut?ce.policy.effectiveDestructiveCommandRules[ut.id]:void 0;return{trace:jf(mt),result:lt?"blocked":"allowed",reason:lt?k(lt.reason):void 0,segment:lt?k(vl(lt,P)):void 0,ruleId:lt?.ruleId?k(lt.ruleId):void 0,customRule:Ff(Nf(lt?.ruleId,te)),configSource:ye,configValid:be,...he,...ut&&yt?{ruleActivation:{id:ut.id,...yt}}:{}}}function vl(P,V){return P.evidence?.segment??V}function $f(P){if(P.reason===$e)return{ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};if(P.reason===Me)return{ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};if(P.reason===x)return{ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};return{ruleId:P.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"}}function If(P,V){let z=F(V.cwd),Q=M(P,V),te=K(P,{cwd:V.cwd,userConfigDir:V.userConfigDir});try{if(n(te.projectConfigTarget)!==null){if(Jt(te.projectConfigTarget).errors.length===0)return{configSource:z,configValid:!0};return{configSource:z,configValid:!1}}}catch(ne){if(ne instanceof r)return{configSource:z,configValid:!1};throw ne}try{if(n(te.userConfigTarget)!==null){let ne=Jt(te.userConfigTarget);return{configSource:Q,configValid:ne.errors.length===0}}return{configSource:null,configValid:!0}}catch(ne){if(ne instanceof r)return{configSource:Q,configValid:!1};throw ne}}function Of(P,V,z,Q){let te=V.policy,ne=Ee({...te,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...te.destructiveCommandRuleOverrides,...Object.fromEntries(U.flatMap((he)=>he.activationCapability?[[he.id,"on"]]:[]))}},V.state==="degraded"?{diagnostics:V.diagnostics,reason:V.reason}:void 0),ce=W(P,{environment:Q,dependencies:{loadPolicySnapshot:()=>ne,getModes:()=>({...z,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return ce.decision.kind==="deny"?ce.decision.ruleId:void 0}function Ff(P){if(!P)return;return{id:k(P.id),...P.rulebook?{rulebook:{name:k(P.rulebook.name),version:k(P.rulebook.version)}}:{},...P.source?{source:k(P.source)}:{},...P.override?{override:{type:"reason",reason:k(P.override.reason)}}:{}}}function jf(P){let V=P.events.flatMap((Q)=>Q.kind==="step"&&Q.scope==="global"?[Q.step]:[]),z=new Map;for(let Q of P.events){if(Q.kind!=="step"||Q.scope!=="segment")continue;let te=z.get(Q.segmentIndex)??{index:Q.segmentIndex,steps:[]};te.steps.push(Q.step),z.set(Q.segmentIndex,te)}return{steps:V,segments:[...z.values()]}}function Nf(P,V){let z=P?.replace(/^custom\./,"");if(!z||!V.policy.rules.some((Q)=>Q.name===z))return;return V.ruleMetadata[z]??Object.freeze({id:z})}function bl(P){return new Promise((V)=>{process.stdout.write(`${P}
214
+ `,()=>V())})}async function Ll(P,V){let z=Wo(V);if(!z)return 1;try{let Q=Nn(z.command,{cwd:z.cwd},P),te=!!process.env.NO_COLOR||!process.stdout.isTTY;return await bl(z.json?Zo(Q):Yo(Q,{asciiOnly:te})),0}catch(Q){let te=Mf(Q instanceof p?Q.cause:Q);if(te===void 0)throw Q;if(z.json)return await bl(JSON.stringify({error:te})),1;return console.error(te),1}}function Mf(P){if(P instanceof y)return P.message;if(P instanceof f)return P.message;if(P instanceof s&&a[P.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var wl="2.4.10",Ot=" ",rn="cc-safety-net";function kl(P){return P.argument?`${P.flags} ${P.argument}`:P.flags}function Hf(P){return Math.max(...P.map((V)=>kl(V).length))}function Uf(P){return Math.max(...P.map((V)=>V.usage.length))}function Gf(P){return Math.max(...P.map((V)=>`${rn} ${V.usage}`.length))}function Bf(P,V){let z=`${rn} ${P.usage}`;return`${Ot}${z.padEnd(V+2)}${P.description}`}function qt(P,V){return`${Ot}${P.padEnd(Math.max(40,P.length+2))}${V}`}function wn(P,V=console.log){let z=[];if(z.push(`${rn} ${P.name}`),z.push(""),z.push(`${Ot}${P.description}`),z.push(""),z.push("USAGE:"),z.push(`${Ot}${rn} ${P.usage}`),z.push(""),P.subcommands&&P.subcommands.length>0){z.push("SUBCOMMANDS:");let Q=Uf(P.subcommands);for(let te of P.subcommands)z.push(`${Ot}${te.usage.padEnd(Q+2)}${te.description}`);z.push("")}if(P.options.length>0){z.push("OPTIONS:");let Q=Hf(P.options);for(let te of P.options){let ne=kl(te),ce=te.default?`${te.description} (default: ${te.default})`:te.description;z.push(`${Ot}${ne.padEnd(Q+2)}${ce}`)}z.push("")}if(P.examples&&P.examples.length>0){z.push("EXAMPLES:");for(let Q of P.examples)z.push(`${Ot}${Q}`)}V(z.join(`
215
215
  `))}function ti(){let P=Gf(Qn),V=[];V.push(`${rn} v${wl}`),V.push(""),V.push("Blocks destructive commands and secret access."),V.push(""),V.push("COMMANDS:");for(let z of Qn)V.push(Bf(z,P));V.push(""),V.push("GLOBAL OPTIONS:"),V.push(`${Ot}-h, --help Show help (use with command for command-specific help)`),V.push(`${Ot}-V, --version Show version`),V.push(""),V.push("HELP:"),V.push(`${Ot}${rn} help <command> Show help for a specific command`),V.push(`${Ot}${rn} <command> --help Show help for a specific command`),V.push(""),V.push("ENVIRONMENT VARIABLES:"),V.push(qt(`${o.level.name}=standard|strict|paranoid`,"Set session safety level")),V.push(qt(`${o.worktree.name}=1`,"Allow local git discards in linked worktrees")),V.push(qt(`${o.debug.name}=1`,"Print diagnostic messages to stderr")),V.push(qt(`${o.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),V.push(qt("CC_SAFETY_NET_HOME","Override rule config home directory")),V.push(""),V.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),V.push(qt(`${o.strict.name}=1`,"Force safety.overrides.fail_closed on")),V.push(qt(`${o.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),V.push(qt(`${o.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),V.push(qt(`${o.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),V.push(""),V.push("Documentation: https://ccsafetynet.com/docs"),console.log(V.join(`
216
216
  `))}function xl(){console.log(wl)}function Mn(P,V=console.log){let z=er(P);if(!z)return!1;if(z.name.toLowerCase()!==P.toLowerCase())return!1;return wn(z,V),!0}import{existsSync as mi,readFileSync as bc}from"node:fs";import{join as pi}from"node:path";import*as Kt from"node:readline";function qf(P){return P==="install"?"Install":"Uninstall"}function Vf(P){return P==="install"?"Installing":"Uninstalling"}function zf(P){return P==="install"?"into":"from"}function Rl(P){return P?.available===!0}function Jf(P,V){let z=new Set(V);return P.filter((Q)=>z.has(Q.target)).map((Q)=>Q.target)}function Cl(P,V,z){if(P.every((Q)=>!Q.available))return V;return Array.from({length:P.length},(Q,te)=>te+1).map((Q)=>(V+Q*z+P.length)%P.length).find((Q)=>Rl(P[Q]))}function Wf(P,V,z){if(z.ctrl&&z.name==="c")return"interrupt";if(z.name==="escape"||V==="q")return"abort";if(P==="install"&&(V==="u"||V==="U"))return"update";if(z.name==="up"||V==="k")return"up";if(z.name==="down"||V==="j")return"down";if(z.name==="space"||V===" ")return"toggle";if(z.name==="return"||z.name==="enter")return"confirm";return null}function Kf(P){return{cursor:P.findIndex((V)=>V.available),selected:[]}}function Yf(P,V,z){if(z==="confirm"||z==="update"||z==="abort"||z==="interrupt")return{state:P,done:z};if(z==="up")return{state:{...P,cursor:Cl(V,P.cursor,-1)}};if(z==="down")return{state:{...P,cursor:Cl(V,P.cursor,1)}};let Q=V[P.cursor];if(!Rl(Q))return{state:P};let te=P.selected.includes(Q.target)?P.selected.filter((ne)=>ne!==Q.target):Jf(V,[...P.selected,Q.target]);return{state:{...P,selected:te}}}var Pl="◉",El="◯",Dl=">",Al=" ";function Zf(P,V,z,Q={}){let te=Q.color!==!1,ne=te?dt.dim:(ye)=>ye,ce=te?dt.green:(ye)=>ye,he=te?dt.bold:(ye)=>ye;return["",`${qf(P)} CC Safety Net ${zf(P)}:`,"",...V.map((ye,be)=>{let xe=z.selected.includes(ye.target),Ie=be===z.cursor,Xe=xe?Pl:El,et=Ie?Dl:Al,Re=ye.available?"":` (${ye.unavailableReason??"not installed"})`,at=`${Xe} ${ye.label}${Re}`,ct=!ye.available?ne(at):xe?ce(at):Ie?he(at):at;return`${et} ${ct}`}),"",P==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":V.some((ye)=>ye.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${P}. q/Esc: close`].join(`
217
217
  `)}var Sl=["global-hook","plugin"];function Xf(P,V,z={}){let Q=z.color!==!1?dt.bold:(ne)=>ne;return["","Install the Kimi Code integration as:","",...[`Global hook — ${V?"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((ne,ce)=>{let he=ce===P,ye=`${he?Pl:El} ${ne}`;return`${he?Dl:Al} ${he?Q(ye):ye}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
@@ -224,9 +224,9 @@ ${he()}`.trim())))}),ne.on("close",(xe)=>{if(clearTimeout(be),xe!==0){Q(Error($o
224
224
  `))}async function Fl(P){let V=await P(["amp","plugins","repositories","--json"]);if(V.status===null)throw Error(`${V.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 (${V.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
225
225
  ${V.stderr}`.trim());if(V.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${V.status}). Sign in with "amp login" and rerun install --amp.
226
226
  ${[V.stdout,V.stderr].filter(Boolean).join(`
227
- `)}`.trim());let z=Ol(V.stdout),Q=(Array.isArray(z)?z:[]).filter((te)=>ft(te,"scope")==="user"&&ft(te,"exists")===!0&&ft(te,"viewerCanWrite")===!0).map((te)=>ft(te,"cloneRef")).find((te)=>typeof te==="string"&&te.length>0);if(!Q)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 Q}async function jl(P,V,z){let Q=nm(Et(V.tmpdir,"cc-safety-net-amp-"));try{return await Hn(P,["amp","clone","user-plugins",Q]),await z(Q)}finally{Tr(Q,{recursive:!0,force:!0})}}function si(P){return`rerun ${P==="overwrite"?"install":"uninstall"} --amp`}function Nl(P,V,z){let Q=Et(P,V),te=Lt(Q);if(!te)return;if(te.isSymbolicLink()||!te.isFile())throw Error(`Refusing to ${z} ${V} in your Amp personal plugins repository: not a regular file. Remove it there and ${si(z)}.`);let ne=xn(Q);if($r(ne))return ne;throw Error(`Refusing to ${z} unmanaged file ${V} in your Amp personal plugins repository. Remove it there and ${si(z)}.`)}function Ml(P,V){let z=Et(P,on),Q=Lt(z);if(!Q)return;if(Q.isSymbolicLink()||!Q.isDirectory())throw Error(`Refusing to ${V} ${on} in your Amp personal plugins repository: not a regular directory. Remove it there and ${si(V)}.`);return Nl(P,sn,V)}function dm(P){let V=Et(P,kn),z=Lt(V);if(!z||z.isSymbolicLink()||!z.isFile())return;let Q=xn(V);return $r(Q)?Q:void 0}async function Hl(P,V,z,Q){if(await Hn(P,z,V),(await Hn(P,["git","status","--porcelain"],V)).stdout.trim()==="")return!1;return await Hn(P,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",Q],V),await Hn(P,["git","push","origin","HEAD"],V),!0}function _r(P,V){um(P,V),pm(P,V)}function Ul(P,V){if(V==="keep")return;throw Error(`Local Amp plugin ${P} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function um(P,V){let z=am(P),Q=Lt(z);if(!Q)return;if(!Q.isSymbolicLink()&&Q.isFile()&&$r(xn(z))){Tr(z);return}Ul(z,V)}function pm(P,V){let z=Et(P.home,".config","amp","plugins",on),Q=Lt(z);if(!Q)return;if(!Q.isSymbolicLink()&&Q.isDirectory()&&fm(z)){Tr(z,{recursive:!0});return}Ul(z,V)}function fm(P){let V=om(sn);if(rm(P).join("\x00")!==V)return!1;let z=Et(P,V),Q=Lt(z);return!!Q&&!Q.isSymbolicLink()&&Q.isFile()&&$r(xn(z))}function mm(P){let V=u(P);if(!Il(V))return"";let z=Ol(xn(V,"utf-8"));if(!z||typeof z!=="object"||Array.isArray(z))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(C(z,P.home))};
227
+ `)}`.trim());let z=Ol(V.stdout),Q=(Array.isArray(z)?z:[]).filter((te)=>ft(te,"scope")==="user"&&ft(te,"exists")===!0&&ft(te,"viewerCanWrite")===!0).map((te)=>ft(te,"cloneRef")).find((te)=>typeof te==="string"&&te.length>0);if(!Q)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 Q}async function jl(P,V,z){let Q=nm(Et(V.tmpdir,"cc-safety-net-amp-"));try{return await Hn(P,["amp","clone","user-plugins",Q]),await z(Q)}finally{Tr(Q,{recursive:!0,force:!0})}}function si(P){return`rerun ${P==="overwrite"?"install":"uninstall"} --amp`}function Nl(P,V,z){let Q=Et(P,V),te=bt(Q);if(!te)return;if(te.isSymbolicLink()||!te.isFile())throw Error(`Refusing to ${z} ${V} in your Amp personal plugins repository: not a regular file. Remove it there and ${si(z)}.`);let ne=xn(Q);if($r(ne))return ne;throw Error(`Refusing to ${z} unmanaged file ${V} in your Amp personal plugins repository. Remove it there and ${si(z)}.`)}function Ml(P,V){let z=Et(P,on),Q=bt(z);if(!Q)return;if(Q.isSymbolicLink()||!Q.isDirectory())throw Error(`Refusing to ${V} ${on} in your Amp personal plugins repository: not a regular directory. Remove it there and ${si(V)}.`);return Nl(P,sn,V)}function dm(P){let V=Et(P,kn),z=bt(V);if(!z||z.isSymbolicLink()||!z.isFile())return;let Q=xn(V);return $r(Q)?Q:void 0}async function Hl(P,V,z,Q){if(await Hn(P,z,V),(await Hn(P,["git","status","--porcelain"],V)).stdout.trim()==="")return!1;return await Hn(P,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",Q],V),await Hn(P,["git","push","origin","HEAD"],V),!0}function _r(P,V){um(P,V),pm(P,V)}function Ul(P,V){if(V==="keep")return;throw Error(`Local Amp plugin ${P} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function um(P,V){let z=am(P),Q=bt(z);if(!Q)return;if(!Q.isSymbolicLink()&&Q.isFile()&&$r(xn(z))){Tr(z);return}Ul(z,V)}function pm(P,V){let z=Et(P.home,".config","amp","plugins",on),Q=bt(z);if(!Q)return;if(!Q.isSymbolicLink()&&Q.isDirectory()&&fm(z)){Tr(z,{recursive:!0});return}Ul(z,V)}function fm(P){let V=om(sn);if(rm(P).join("\x00")!==V)return!1;let z=Et(P,V),Q=bt(z);return!!Q&&!Q.isSymbolicLink()&&Q.isFile()&&$r(xn(z))}function mm(P){let V=u(P);if(!Il(V))return"";let z=Ol(xn(V,"utf-8"));if(!z||typeof z!=="object"||Array.isArray(z))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(C(z,P.home))};
228
228
  `}async function Gl(P,V=cm(),z=oi){let Q=Buffer.concat([xn(V),Buffer.from(mm(P),"utf-8")]),te=await Fl(z);return jl(z,P,async(ne)=>{let ce=`${te}/${on}`,he=Ml(ne,"overwrite"),ye=Nl(ne,kn,"overwrite");if(he?.equals(Q)&&!ye)return _r(P,"fail"),{path:ce,alreadyInstalled:!0};if(tm(Et(ne,on),{recursive:!0}),kt(Et(ne,sn),Q),ye)Tr(Et(ne,kn));let be=await Hl(z,ne,["git","add","--",sn,...ye?[kn]:[]],`chore: update cc-safety-net plugin to v${wt()}`);return _r(P,"fail"),{path:ce,alreadyInstalled:!be}})}async function Bl(P,V=oi){let z=await Fl(V);return jl(V,P,async(Q)=>{let te=Ml(Q,"remove"),ne=dm(Q),ce=`${z}/${ne&&!te?kn:on}`;if(!te&&!ne)return _r(P,"keep"),{path:ce,alreadyInstalled:!1};return await Hl(V,Q,["git","rm","--",...te?[sn]:[],...ne?[kn]:[]],`chore: remove cc-safety-net plugin v${wt()}`),_r(P,"keep"),{path:ce,alreadyInstalled:!0}})}import{existsSync as ql,mkdirSync as gm,readFileSync as hm}from"node:fs";import{dirname as ym}from"node:path";var ai=Nt["antigravity-cli"],an="cc-safety-net";function ln(P){return Boolean(P)&&typeof P==="object"&&!Array.isArray(P)}function Or(){return{PreToolUse:[{hooks:[{type:"command",command:ai,timeout:30}]}]}}function Vl(P){try{let V=JSON.parse(hm(P,"utf-8"));if(!V||typeof V!=="object"||Array.isArray(V))throw Error("Antigravity hooks config must be a JSON object");return V}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${P}: ${V.message}`);throw V}}function zl(P){let V=P[an];if(V===void 0){let Q=Or();return P[an]=Q,{definition:Q,preToolUse:Q.PreToolUse??[]}}if(!ln(V))throw Error(`Antigravity hooks config entry "${an}" must be an object`);let z=Array.isArray(V.PreToolUse)?V.PreToolUse:[];return V.PreToolUse=z,{definition:V,preToolUse:z}}function Jl(P){if(!Array.isArray(P.PreToolUse))return!1;return P.PreToolUse.some((V)=>ln(V)&&Array.isArray(V.hooks)&&V.hooks.some((z)=>ln(z)&&z.command===ai))}function vm(P){return Object.values(P).some((V)=>ln(V)&&V.enabled!==!1&&Jl(V))}function bm(P){if(P[an]===void 0)return!1;let V=zl(P);if(V.definition.enabled!==!1||!Jl(V.definition))return!1;return V.definition.enabled=!0,!0}function Lm(P){if(P[an]===void 0){P[an]=Or();return}let V=zl(P);V.definition.enabled=!0,V.preToolUse.push(Or().PreToolUse?.[0]??{hooks:[]})}function wm(P){let V=!1;for(let z of Object.values(P)){if(!ln(z)||!Array.isArray(z.PreToolUse))continue;z.PreToolUse=z.PreToolUse.flatMap((Q)=>{if(!ln(Q)||!Array.isArray(Q.hooks))return[Q];let te=Q.hooks.filter((ne)=>!ln(ne)||ne.command!==ai);if(te.length!==Q.hooks.length)V=!0;return te.length===0?[]:[{...Q,hooks:te}]})}return V}function Ir(P,V){kt(P,`${JSON.stringify(V,null,2)}
229
- `)}function Wl(P){let V=En(P.home);if(gm(ym(V),{recursive:!0}),!ql(V))return Ir(V,{[an]:Or()}),{path:V,alreadyInstalled:!1};let z=Vl(V);if(vm(z))return{path:V,alreadyInstalled:!0};if(bm(z))return Ir(V,z),{path:V,alreadyInstalled:!1};return Lm(z),Ir(V,z),{path:V,alreadyInstalled:!1}}function Kl(P){let V=En(P.home);if(!ql(V))return{path:V,alreadyInstalled:!1};let z=Vl(V);if(!wm(z))return{path:V,alreadyInstalled:!1};return Ir(V,z),{path:V,alreadyInstalled:!0}}import{existsSync as km,readdirSync as xm,rmSync as Cm}from"node:fs";import{join as Sm}from"node:path";function Yl(P,V=process.platform,z){if(!km(P))return;let Q=V==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);xm(P).filter((te)=>te!==z&&Q.test(te)).forEach((te)=>{Cm(Sm(P,te),{recursive:!0,force:!0})})}import{spawn as Rm}from"node:child_process";var Mt=$t.map((P)=>({target:P.id,flag:P.flag,label:bt(P.id),probeCommand:P.probeCommand}));function li(P){let V=new Set(P);return Mt.map((z)=>z.target).filter((z)=>V.has(z))}async function Zl(P,V){for(let z of P)await V(z)}var Pm=5000;function ci(P,V=Pm){return new Promise((z)=>{let Q=Xt([...P],process.env),te=Rm(Q.cmd,Q.args,{env:process.env,stdio:"ignore"}),ne=!1,ce=(ye)=>{if(ne)return;ne=!0,clearTimeout(he),z(ye)},he=setTimeout(()=>{te.kill(),ce(!1)},V);te.on("error",()=>ce(!1)),te.on("close",(ye)=>ce(ye===0))})}function Xl(P=ci,V={}){let z=new Set(V.configuredTargets??[]);return Promise.all(Mt.map(async(Q)=>({target:Q.target,flag:Q.flag,label:Q.label,...ec(V.action,await P(Q.probeCommand),z.has(Q.target))})))}function Ql(P,V){let z=new Set(V.configuredTargets??[]);return P.map((Q)=>({...Q,...ec(V.action,Q.available,z.has(Q.target))}))}function ec(P,V,z){if(P==="uninstall")return z?{available:!0}:{available:!1,unavailableReason:"not installed"};if(P==="install"&&z)return{available:!1,unavailableReason:"already installed"};if(!V)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as tc,readdirSync as Em,rmSync as Dm}from"node:fs";import{join as Cn}from"node:path";function Fr(P,V=process.platform){let z=Cn(P.env.get("npm_config_cache")||(V==="win32"?Cn(P.env.get("LOCALAPPDATA")||Cn(P.home,"AppData","Local"),"npm-cache"):Cn(P.home,".npm")),"_npx");if(!tc(z))return;Em(z).filter((Q)=>tc(Cn(z,Q,"node_modules","cc-safety-net"))).forEach((Q)=>{Dm(Cn(z,Q),{recursive:!0,force:!0})})}import{existsSync as ac,mkdirSync as _m,readFileSync as lc}from"node:fs";import{dirname as Tm,join as sc}from"node:path";function Am(P,V){if(P[V]!=="#")return V;let z=P.indexOf(`
229
+ `)}function Wl(P){let V=En(P.home);if(gm(ym(V),{recursive:!0}),!ql(V))return Ir(V,{[an]:Or()}),{path:V,alreadyInstalled:!1};let z=Vl(V);if(vm(z))return{path:V,alreadyInstalled:!0};if(bm(z))return Ir(V,z),{path:V,alreadyInstalled:!1};return Lm(z),Ir(V,z),{path:V,alreadyInstalled:!1}}function Kl(P){let V=En(P.home);if(!ql(V))return{path:V,alreadyInstalled:!1};let z=Vl(V);if(!wm(z))return{path:V,alreadyInstalled:!1};return Ir(V,z),{path:V,alreadyInstalled:!0}}import{existsSync as km,readdirSync as xm,rmSync as Cm}from"node:fs";import{join as Sm}from"node:path";function Yl(P,V=process.platform,z){if(!km(P))return;let Q=V==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);xm(P).filter((te)=>te!==z&&Q.test(te)).forEach((te)=>{Cm(Sm(P,te),{recursive:!0,force:!0})})}import{spawn as Rm}from"node:child_process";var Mt=$t.map((P)=>({target:P.id,flag:P.flag,label:vt(P.id),probeCommand:P.probeCommand}));function li(P){let V=new Set(P);return Mt.map((z)=>z.target).filter((z)=>V.has(z))}async function Zl(P,V){for(let z of P)await V(z)}var Pm=5000;function ci(P,V=Pm){return new Promise((z)=>{let Q=Xt([...P],process.env),te=Rm(Q.cmd,Q.args,{env:process.env,stdio:"ignore"}),ne=!1,ce=(ye)=>{if(ne)return;ne=!0,clearTimeout(he),z(ye)},he=setTimeout(()=>{te.kill(),ce(!1)},V);te.on("error",()=>ce(!1)),te.on("close",(ye)=>ce(ye===0))})}function Xl(P=ci,V={}){let z=new Set(V.configuredTargets??[]);return Promise.all(Mt.map(async(Q)=>({target:Q.target,flag:Q.flag,label:Q.label,...ec(V.action,await P(Q.probeCommand),z.has(Q.target))})))}function Ql(P,V){let z=new Set(V.configuredTargets??[]);return P.map((Q)=>({...Q,...ec(V.action,Q.available,z.has(Q.target))}))}function ec(P,V,z){if(P==="uninstall")return z?{available:!0}:{available:!1,unavailableReason:"not installed"};if(P==="install"&&z)return{available:!1,unavailableReason:"already installed"};if(!V)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as tc,readdirSync as Em,rmSync as Dm}from"node:fs";import{join as Cn}from"node:path";function Fr(P,V=process.platform){let z=Cn(P.env.get("npm_config_cache")||(V==="win32"?Cn(P.env.get("LOCALAPPDATA")||Cn(P.home,"AppData","Local"),"npm-cache"):Cn(P.home,".npm")),"_npx");if(!tc(z))return;Em(z).filter((Q)=>tc(Cn(z,Q,"node_modules","cc-safety-net"))).forEach((Q)=>{Dm(Cn(z,Q),{recursive:!0,force:!0})})}import{existsSync as ac,mkdirSync as _m,readFileSync as lc}from"node:fs";import{dirname as Tm,join as sc}from"node:path";function Am(P,V){if(P[V]!=="#")return V;let z=P.indexOf(`
230
230
  `,V+1);return z===-1?P.length:z+1}function di(P,V,z){let Q=new RegExp(`^(\\s*)${V}\\s*=\\s*\\[`),te=0;for(let ne of P.split(`
231
231
  `)){if(/^\s*\[/.test(ne))return;let ce=Q.exec(ne);if(ce){let he=te+ce[0].lastIndexOf("[");return{start:he,end:yo(P,he,{skipComment:Am,...z})}}te+=ne.length+1}return}function nc(P,V,z){let Q=P.slice(0,V.end).trimEnd(),te=Zs(P,V.end),ne=te===""?" ":`${te} `,ce=!Q.endsWith("[")&&!Q.endsWith(",");return`${Q}${ce?",":""}
232
232
  ${ne}${z}${P.slice(V.end)}`}function rc(P,V,z){let Q=P.indexOf(z,V.start);if(Q===-1||Q>V.end)return P;return fr(P,{start:Q,end:Q+z.length})}function oc(P,V){let z=new RegExp(`^\\s*${V}\\s*=\\s*\\[\\s*]\\s*(?:#.*)?$`),Q=P.split(`
@@ -239,28 +239,28 @@ command = "${Un}"`,cc=`{ event = "PreToolUse", command = "${Un}" }`,dc={stringEr
239
239
  ${ui}
240
240
  `}function pc(P){let V=uc(P);if(_m(Tm(V),{recursive:!0}),!ac(V))return kt(V,`${ui}
241
241
  `),{path:V,alreadyInstalled:!1};let z=lc(V,"utf-8");if(z.includes(Un))return{path:V,alreadyInstalled:!0};return kt(V,$m(z)),{path:V,alreadyInstalled:!1}}function fc(P){let V=uc(P);if(!ac(V))return{path:V,alreadyInstalled:!1};let z=lc(V,"utf-8");if(!z.includes(Un))return{path:V,alreadyInstalled:!1};let Q=di(z,"hooks",dc),te=Q?rc(z,Q,cc):`${ic(z,"hooks",Un)}
242
- `;return kt(V,te),{path:V,alreadyInstalled:!0}}var fi="safety-net@cc-marketplace",mc=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gc=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function gi(P){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Lc(P){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Im(P){return/^Marketplace `cc-marketplace`\s*$/m.test(P??"")}var wc={"claude-code":{installCommands:(P)=>{let V=pr(P,"cc-safety-net@cc-marketplace");return{commands:[...V?[["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"]],...go(P).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:pr(P,fi)?[["claude","plugin","uninstall",fi]]:[],update:V}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(P,V)=>{let z=V??await _t(["codex","plugin","list"]),Q=Lc(z);return{commands:[Q||Im(z)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:gi(z)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:Q}},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 P=await _t(["copilot","plugin","list"]),V=[...oa(P)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...ia(P)?[["copilot","plugin","uninstall",ta]]:[]];if(na(P))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",jt]],cleanupCommands:V,update:!0};return{commands:[ra(await _t(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",jt]],cleanupCommands:V}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(P)=>{let V=Co(P);if(V.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(V.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:Mo,installCommands:()=>({commands:za()}),uninstallCommands:[["openclaw","plugins","uninstall",yt,"--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(`
242
+ `;return kt(V,te),{path:V,alreadyInstalled:!0}}var fi="safety-net@cc-marketplace",mc=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gc=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function gi(P){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Lc(P){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Im(P){return/^Marketplace `cc-marketplace`\s*$/m.test(P??"")}var wc={"claude-code":{installCommands:(P)=>{let V=pr(P,"cc-safety-net@cc-marketplace");return{commands:[...V?[["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"]],...go(P).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:pr(P,fi)?[["claude","plugin","uninstall",fi]]:[],update:V}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(P,V)=>{let z=V??await _t(["codex","plugin","list"]),Q=Lc(z);return{commands:[Q||Im(z)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:gi(z)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:Q}},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 P=await _t(["copilot","plugin","list"]),V=[...oa(P)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...ia(P)?[["copilot","plugin","uninstall",ta]]:[]];if(na(P))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",jt]],cleanupCommands:V,update:!0};return{commands:[ra(await _t(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",jt]],cleanupCommands:V}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(P)=>{let V=Co(P);if(V.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(V.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:Mo,installCommands:()=>({commands:za()}),uninstallCommands:[["openclaw","plugins","uninstall",Lt,"--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(`
243
243
  `)},opencode:{installCommands:ol},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function kc(P,V=(z)=>z){try{let z=JSON.parse(V(bc(P,"utf-8")));if(!z||typeof z!=="object"||Array.isArray(z))throw Error(`Settings file ${P} must be a JSON object`);return z}catch(z){if(z instanceof SyntaxError)throw Error(`Failed to parse ${P}: ${z.message}`);throw z}}function Om(P){let V=pi(Dn(P),"settings.json");if(!mi(V))return;let z=kc(V,At),Q=z.enabledPlugins;if(!Q||typeof Q!=="object"||Array.isArray(Q))return;if(Q[jt]!==!1)return;let te=bc(V,"utf-8"),ne=te.replace(new RegExp(`("${jt}"\\s*:\\s*)false`),"$1true");return Q[jt]=!0,kt(V,ne!==te?ne:`${JSON.stringify(z,null,2)}
244
244
  `),`Enabled ${jt} plugin in ${V}`}function Fm(P){let V=Vo(P);if(!mi(V))return;let z=kc(V);if(!Array.isArray(z.packages))return;let Q=z.packages.find((te)=>!!te&&typeof te==="object"&&!Array.isArray(te)&&zo(te.source)&&("extensions"in te));if(!Q)return;return delete Q.extensions,kt(V,`${JSON.stringify(z,null,2)}
245
- `),`Enabled npm:cc-safety-net extensions in ${V}`}function hc(P,V){let z=xt({label:V,booleans:Object.fromEntries(Mt.map((ne)=>[ne.target,[ne.flag]]))},P),Q=z.errors[0];if(Q)throw Error(Q);let te=Mt.filter((ne)=>z.flags[ne.target]).map((ne)=>ne.target);if(te.length!==1)throw Error(`Choose exactly one ${V} target: ${Mt.map((ne)=>ne.flag).join(", ")}`);return te[0]}async function xc(P,V=mn){let[z,Q,te]=await Promise.all([V(["amp","plugins","list"],30000),V(["codex","plugin","list"],30000),V(["copilot","--binary-version"])]);return{codexPluginListOutput:Q,hooks:Ln(P,process.cwd(),{ampPluginListOutput:z,codexPluginListOutput:Q,copilotCliVersion:te})}}async function jm(P,V,z=mn){let Q=await xc(P,z);return Q.hooks.filter((te)=>V==="install"?te.configured:te.detected||te.inspectionStatus==="not-inspected").filter((te)=>te.platform!=="codex"||!gi(Q.codexPluginListOutput)||Lc(Q.codexPluginListOutput)).map((te)=>te.platform)}function Nm(P,V,z,Q){if(z.length>0)return{finish:async()=>[hc(z,V)]};if(!Q.selectTargets&&!ni(Q.input,Q.output))return{finish:async()=>[hc(z,V)]};let te=Q.detectConfiguredTargets??(()=>jm(P,V,Q.fetchVersion)),ne=Promise.all([Xl(Q.probeTargets),te()]);return{ready:ne,finish:async()=>{let[ce,he]=await ne,ye=Ql(ce,{action:V,configuredTargets:he}),be=Q.selectTargets?await Q.selectTargets(V,vc(V,ye)):await $l(V,vc(V,ye),{input:Q.input,output:Q.output});if(be==="update")return be;if(!be||be.length===0)return null;return li(be)}}}async function Mm(P,V,z=!1,Q){let te=wc[P];te.beforeInstall?.(V);let ne=typeof te.installCommands==="function"?await te.installCommands(V,Q):{commands:te.installCommands};return await Oo(ne.commands),await Ua(ne.cleanupCommands??[]),await ne.afterInstall?.(),[`${ne.update||z?"Updated":"Installed"} ${bt(P)} integration`,te.postInstallMessage].filter(Boolean).join(`
246
- `)}async function Hm(P){let V=wc[P];if(!V.uninstallCommands)throw Error(`${bt(P)} uninstall is not supported`);return await Oo(V.uninstallCommands),`Uninstalled ${bt(P)} integration`}function Um(P){let V=il(P);return V.alreadyInstalled?`Uninstalled OpenCode plugin from ${V.path}`:`OpenCode plugin not installed in ${V.path}`}var Cc={"antigravity-cli":{install:Wl,uninstall:Kl},cursor:{install:ga,uninstall:ha},"grok-build":{install:Ra,uninstall:Pa},"kimi-code":{install:pc,uninstall:fc}};function Gm(P,V,z,Q=!1){if(P==="install"&&!Q)Fr(z);let te=Cc[V][P](z),ne=bt(V),ce=P!=="install"?"Uninstalled":Q?"Updated":"Installed";return P==="install"&&te.alreadyInstalled?Q?`${ne} hook up to date in ${te.path}`:`${ne} hook already installed in ${te.path}`:P==="uninstall"&&!te.alreadyInstalled?`${ne} hook not installed in ${te.path}`:`${ce} ${ne} hook ${P==="install"?"in":"from"} ${te.path}`}var Sc={amp:{install:Gl,uninstall:Bl,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:_a,uninstall:Ta,afterInstall:async(P)=>{let V=To(P);return await _t(["hermes","plugins","enable",Tt,"--no-allow-tool-override"]),!V},beforeUninstall:async(P)=>{_o(P);try{await _t(["hermes","plugins","disable",Tt])}catch(V){console.warn(`${V instanceof Error?V.message:String(V)}
247
- Removing the plugin files anyway; ${Tt} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Bm(P,V,z,Q=!1){let te=Sc[V];if(P==="uninstall")await te.beforeUninstall?.(z);let ne=P==="install"?await te.install(z):await te.uninstall(z),ce=P==="install"&&await te.afterInstall?.(z),he=bt(V),ye=!ce&&(P==="install"&&ne.alreadyInstalled||P==="uninstall"&&!ne.alreadyInstalled);return[ye?P==="install"?`${he} plugin ${Q?"up to date":"already installed"} at ${ne.path}`:`${he} plugin not installed at ${ne.path}`:`${P!=="install"?"Uninstalled":Q?"Updated":"Installed"} ${he} plugin ${P==="install"?"at":"from"} ${ne.path}`,ye?void 0:te.restartNote].filter(Boolean).join(`
245
+ `),`Enabled npm:cc-safety-net extensions in ${V}`}function hc(P,V){let z=xt({label:V,booleans:Object.fromEntries(Mt.map((ne)=>[ne.target,[ne.flag]]))},P),Q=z.errors[0];if(Q)throw Error(Q);let te=Mt.filter((ne)=>z.flags[ne.target]).map((ne)=>ne.target);if(te.length!==1)throw Error(`Choose exactly one ${V} target: ${Mt.map((ne)=>ne.flag).join(", ")}`);return te[0]}async function xc(P,V=mn){let[z,Q,te]=await Promise.all([V(["amp","plugins","list"],30000),V(["codex","plugin","list"],30000),V(["copilot","--binary-version"])]);return{codexPluginListOutput:Q,hooks:Ln(P,process.cwd(),{ampPluginListOutput:z,codexPluginListOutput:Q,copilotCliVersion:te})}}async function jm(P,V,z=mn){let Q=await xc(P,z);return Q.hooks.filter((te)=>V==="install"?te.configured:te.detected||te.inspectionStatus==="not-inspected").filter((te)=>te.platform!=="codex"||!gi(Q.codexPluginListOutput)||Lc(Q.codexPluginListOutput)).map((te)=>te.platform)}function Nm(P,V,z,Q){if(z.length>0)return{finish:async()=>[hc(z,V)]};if(!Q.selectTargets&&!ni(Q.input,Q.output))return{finish:async()=>[hc(z,V)]};let te=Q.detectConfiguredTargets??(()=>jm(P,V,Q.fetchVersion)),ne=Promise.all([Xl(Q.probeTargets),te()]);return{ready:ne,finish:async()=>{let[ce,he]=await ne,ye=Ql(ce,{action:V,configuredTargets:he}),be=Q.selectTargets?await Q.selectTargets(V,vc(V,ye)):await $l(V,vc(V,ye),{input:Q.input,output:Q.output});if(be==="update")return be;if(!be||be.length===0)return null;return li(be)}}}async function Mm(P,V,z=!1,Q){let te=wc[P];te.beforeInstall?.(V);let ne=typeof te.installCommands==="function"?await te.installCommands(V,Q):{commands:te.installCommands};return await Oo(ne.commands),await Ua(ne.cleanupCommands??[]),await ne.afterInstall?.(),[`${ne.update||z?"Updated":"Installed"} ${vt(P)} integration`,te.postInstallMessage].filter(Boolean).join(`
246
+ `)}async function Hm(P){let V=wc[P];if(!V.uninstallCommands)throw Error(`${vt(P)} uninstall is not supported`);return await Oo(V.uninstallCommands),`Uninstalled ${vt(P)} integration`}function Um(P){let V=il(P);return V.alreadyInstalled?`Uninstalled OpenCode plugin from ${V.path}`:`OpenCode plugin not installed in ${V.path}`}var Cc={"antigravity-cli":{install:Wl,uninstall:Kl},cursor:{install:ga,uninstall:ha},"grok-build":{install:Ra,uninstall:Pa},"kimi-code":{install:pc,uninstall:fc}};function Gm(P,V,z,Q=!1){if(P==="install"&&!Q)Fr(z);let te=Cc[V][P](z),ne=vt(V),ce=P!=="install"?"Uninstalled":Q?"Updated":"Installed";return P==="install"&&te.alreadyInstalled?Q?`${ne} hook up to date in ${te.path}`:`${ne} hook already installed in ${te.path}`:P==="uninstall"&&!te.alreadyInstalled?`${ne} hook not installed in ${te.path}`:`${ce} ${ne} hook ${P==="install"?"in":"from"} ${te.path}`}var Sc={amp:{install:Gl,uninstall:Bl,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:_a,uninstall:Ta,afterInstall:async(P)=>{let V=To(P);return await _t(["hermes","plugins","enable",Tt,"--no-allow-tool-override"]),!V},beforeUninstall:async(P)=>{_o(P);try{await _t(["hermes","plugins","disable",Tt])}catch(V){console.warn(`${V instanceof Error?V.message:String(V)}
247
+ Removing the plugin files anyway; ${Tt} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Bm(P,V,z,Q=!1){let te=Sc[V];if(P==="uninstall")await te.beforeUninstall?.(z);let ne=P==="install"?await te.install(z):await te.uninstall(z),ce=P==="install"&&await te.afterInstall?.(z),he=vt(V),ye=!ce&&(P==="install"&&ne.alreadyInstalled||P==="uninstall"&&!ne.alreadyInstalled);return[ye?P==="install"?`${he} plugin ${Q?"up to date":"already installed"} at ${ne.path}`:`${he} plugin not installed at ${ne.path}`:`${P!=="install"?"Uninstalled":Q?"Updated":"Installed"} ${he} plugin ${P==="install"?"at":"from"} ${ne.path}`,ye?void 0:te.restartNote].filter(Boolean).join(`
248
248
  `)}var qm={"copilot-cli":{afterInstall:Om},"hermes-agent":{beforeInstall:(P,V)=>{if(!V)Fr(P)}},openclaw:{afterInstall:async()=>{await Ja();return},beforeUninstall:Mo},pi:{afterInstall:Fm}};function Vm(P){return P in Cc}function zm(P){return P in Sc}var yc=["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(`
249
249
  `);function Jm(P){if(In({environment:P,cwd:process.cwd()}).status!=="configured")return yc;return[yc,"",dt.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(`
250
250
  `))].join(`
251
251
  `)}function vc(P,V){return V.map((z)=>P==="install"&&z.target==="kimi-code"&&z.unavailableReason==="already installed"?{...z,available:!0,unavailableReason:void 0,label:`${z.label} (global hook installed)`}:z)}function Wm(P,V){if(P.selectKimiInstallMethod)return P.selectKimiInstallMethod();if(!ni(P.input,P.output))return Promise.resolve("global-hook");return Tl({input:P.input,output:P.output,globalHookInstalled:In({environment:V,cwd:process.cwd()}).status==="configured"})}async function Rc(P,V,z,Q=!1,te){let ne=qm[V];if(P==="install")ne?.beforeInstall?.(z,Q);if(P==="uninstall")ne?.beforeUninstall?.(z);if(Vm(V))return Gm(P,V,z,Q);if(zm(V))return Bm(P,V,z,Q);if(P==="uninstall")return V==="opencode"?Um(z):Hm(V);return[await Mm(V,z,Q,te),await ne?.afterInstall?.(z)].filter(Boolean).join(`
252
252
  `)}function Km(P){let V=xt({label:"update"},P).errors[0];if(V)throw Error(V)}async function Ym(P,V=mn){let z=await xc(P,V),Q=pi(Dn(P),"installed-plugins");return{targets:li([...z.hooks.filter((ne)=>ne.platform!=="copilot-cli"&&ne.detected).map((ne)=>ne.platform),...[mr,ea,Qs].flatMap((ne)=>mi(pi(Q,...ne))?["copilot-cli"]:[]),...pr(P,fi)?["claude-code"]:[],...gi(z.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:z.codexPluginListOutput}}async function Zm(P){let V=c(),z=P.output??process.stdout,Q=(P.scriptPath??process.argv[1]??"").split(/[\\/]/),te=Q.find((et)=>/^bunx-\d+-/.test(et)),ne=te!==void 0||Q.includes("_npx")?null:(P.checkLatestVersion??Wt)(),ce=async()=>{let et=ne&&await ne;if(et?.updateAvailable)z.write(`
253
253
  Update available: cc-safety-net ${et.currentVersion} → ${et.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
254
- `)},he=Ym(V,P.fetchVersion??mn).then(async(et)=>{let Re=new Set(et.targets);return{targets:et.targets,codexPluginListOutput:et.codexPluginListOutput,available:new Map(await Promise.all(Mt.filter((at)=>Re.has(at.target)&&mc.has(at.target)).map(async(at)=>[at.target,await ci(at.probeCommand)])))}}),ye=await Pn(P.showBanner??!0,()=>({ready:he,finish:()=>he}),()=>Rn({input:P.input??process.stdin,output:z}),{loadingMessage:"Checking installed integrations…",output:z}),be=await Promise.resolve().then(()=>(Yl(V.tmpdir,process.platform,te),null)).catch((et)=>Gn(et));if(ye.targets.length===0){if(z.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),be!==null)console.error(be);return await ce(),be===null?0:1}let xe=ye.targets.some((et)=>gc.has(et))?await Promise.resolve().then(()=>(Fr(V),null)).catch((et)=>Gn(et)):null,Ie=await cr(Promise.all(ye.targets.map((et)=>{if(mc.has(et)&&!ye.available.get(et))return Promise.resolve({message:`${bt(et)} not found; skipped`,failed:!1});if(xe!==null&&gc.has(et))return Promise.resolve({message:xe,failed:!0});return Rc("install",et,V,!0,ye.codexPluginListOutput).then((Re)=>({message:Re,failed:!1}),(Re)=>({message:Gn(Re),failed:!0}))})),{loadingMessage:`Updating ${ye.targets.length} integration${ye.targets.length===1?"":"s"}…`,output:z}),Xe=be===null?Ie:[...Ie,{message:be,failed:!0}];return Xe.forEach((et)=>et.failed?console.error(et.message):z.write(`${et.message}
254
+ `)},he=Ym(V,P.fetchVersion??mn).then(async(et)=>{let Re=new Set(et.targets);return{targets:et.targets,codexPluginListOutput:et.codexPluginListOutput,available:new Map(await Promise.all(Mt.filter((at)=>Re.has(at.target)&&mc.has(at.target)).map(async(at)=>[at.target,await ci(at.probeCommand)])))}}),ye=await Pn(P.showBanner??!0,()=>({ready:he,finish:()=>he}),()=>Rn({input:P.input??process.stdin,output:z}),{loadingMessage:"Checking installed integrations…",output:z}),be=await Promise.resolve().then(()=>(Yl(V.tmpdir,process.platform,te),null)).catch((et)=>Gn(et));if(ye.targets.length===0){if(z.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),be!==null)console.error(be);return await ce(),be===null?0:1}let xe=ye.targets.some((et)=>gc.has(et))?await Promise.resolve().then(()=>(Fr(V),null)).catch((et)=>Gn(et)):null,Ie=await cr(Promise.all(ye.targets.map((et)=>{if(mc.has(et)&&!ye.available.get(et))return Promise.resolve({message:`${vt(et)} not found; skipped`,failed:!1});if(xe!==null&&gc.has(et))return Promise.resolve({message:xe,failed:!0});return Rc("install",et,V,!0,ye.codexPluginListOutput).then((Re)=>({message:Re,failed:!1}),(Re)=>({message:Gn(Re),failed:!0}))})),{loadingMessage:`Updating ${ye.targets.length} integration${ye.targets.length===1?"":"s"}…`,output:z}),Xe=be===null?Ie:[...Ie,{message:be,failed:!0}];return Xe.forEach((et)=>et.failed?console.error(et.message):z.write(`${et.message}
255
255
  `)),await ce(),Xe.some((et)=>et.failed)?1:0}function hi(P,V={}){return Promise.resolve().then(()=>Km(P)).then(()=>Zm(V)).catch((z)=>(console.error(Gn(z)),1))}async function Bn(P,V,z={}){try{let Q=c(),te=await Pn(!0,()=>Nm(Q,P,V,z),()=>Rn({input:z.input??process.stdin,output:z.output??process.stdout}),{loadingMessage:P==="install"?"Checking available integrations…":"Checking installed integrations…",output:z.output??process.stdout});if(!te)return(z.output??process.stdout).write(`Cancelled: nothing was ${P}ed.
256
256
  `),0;if(te==="update")return(z.runUpdate??(()=>hi([],{fetchVersion:z.fetchVersion,input:z.input,output:z.output,showBanner:!1})))();let ne=z.output??process.stdout;return await Zl(te,async(ce)=>{if(ce==="kimi-code"&&P==="install"){let ye=await Wm(z,Q);if(ye===null){ne.write(`Cancelled: Kimi Code integration was not installed.
257
257
  `);return}if(ye==="plugin"){ne.write(`${Jm(Q)}
258
- `);return}}let he=await cr(Rc(P,ce,Q),{loadingMessage:`${P==="install"?"Installing":"Uninstalling"} ${bt(ce)} integration…`,output:ne});ne.write(`${he}
258
+ `);return}}let he=await cr(Rc(P,ce,Q),{loadingMessage:`${P==="install"?"Installing":"Uninstalling"} ${vt(ce)} integration…`,output:ne});ne.write(`${he}
259
259
  `)}),0}catch(Q){return console.error(Gn(Q)),1}}function Gn(P){let V=P instanceof Error?P.message:String(P),z=typeof P==="object"&&P!==null&&"code"in P?P.code:null;if(z==="EACCES"||z==="EPERM")return`${V}
260
260
  Check file permissions for the target config file and parent directory.`;if(z==="ENOENT")return`${V}
261
261
  Check that the target config path and parent directory exist.`;if(z==="ENOTDIR")return`${V}
262
262
  Check that every parent path component is a directory.`;return V}import{mkdirSync as rg}from"node:fs";import{dirname as og}from"node:path";import{createInterface as ig}from"node:readline";import{existsSync as Ec,readFileSync as Xm}from"node:fs";function cn(P,V){let z=Ye(P,V);return{policy:z.policy,errors:ie(qe(z.issues,Je,(Q)=>Q.kind==="custom")," "," ")}}function qn(P,V){return cn(P,V).errors}function Pc(P,V){return{"safety.level":P.safety.level,...yi("safety.overrides",P.safety.overrides),"workflow.worktree_mode":String(P.workflow.worktree_mode),"destructive_command_protection.enabled":String(P.destructive_command_protection.enabled),...yi("destructive_command_protection.overrides",P.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":vi(P.destructive_command_protection.allow_paths),"secret_protection.enabled":String(P.secret_protection.enabled),...yi("secret_protection.overrides",P.secret_protection.overrides),"secret_protection.deny_paths":vi(P.secret_protection.deny_paths),"secret_protection.allow_paths":vi(P.secret_protection.allow_paths),...V?{"audit.retention_days":String(P.audit.retention_days)}:{}}}function jr(P,V,z){let Q=Pc(P,z),te=Pc(V,z);return[...new Set([...Object.keys(Q),...Object.keys(te)])].flatMap((ne)=>Q[ne]===te[ne]?[]:[{field:ne,before:Q[ne],after:te[ne]}])}function Vn(P,V){let z=u(P,V);if(!Ec(z))return{baseline:C(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,P.home),diagnostics:[]};let Q=dn(z),te=cn(Q.value,P.home);return{baseline:te.policy,diagnostics:Q.errors.length>0?Q.errors:te.errors}}function dn(P){if(!Ec(P))return{errors:[`${P}: file not found`]};try{return{value:JSON.parse(Xm(P,"utf-8")),errors:[]}}catch(V){let z=V instanceof Error?V.message:String(V);return{errors:[`${P}: ${V instanceof SyntaxError?`Invalid JSON: ${z}`:z}`]}}}function Nr(P,V){let z=Qm(P)?P:{};return{version:V.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((Q)=>z[Q]!==void 0).map((Q)=>[Q,z[Q]]))}}function yi(P,V){return Object.fromEntries(Object.entries(V).flatMap(([z,Q])=>Q===void 0?[]:[[`${P}.${z}`,String(Q)]]))}function vi(P){return P.length===0?"(none)":P.join(", ")}function Qm(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{chmodSync as eg,existsSync as Dc,mkdirSync as tg,readFileSync as Ac}from"node:fs";import{dirname as ng}from"node:path";function _c(P,V={}){let z=u(P,V);if(!Dc(z))return{path:z,exists:!1,raw:"",policy:H(),errors:[]};let Q=Ac(z,"utf-8");if(!Q.trim())return{path:z,exists:!0,raw:Q,policy:H(),errors:["Config file is empty"]};try{let te=cn(JSON.parse(Q),P.home);return{path:z,exists:!0,raw:Q,policy:te.policy,errors:te.errors}}catch(te){return{path:z,exists:!0,raw:Q,policy:H(),errors:[`Invalid JSON: ${te instanceof Error?te.message:String(te)}`]}}}function Vt(P,V,z={}){let Q=u(P,z),te=cn(V,P.home);if(te.errors.length>0)return{path:Q,policy:H(),errors:te.errors};let ne=te.policy;return tg(ng(Q),{recursive:!0,mode:448}),g(re(Q),`${JSON.stringify(ne,null,2)}
263
- `,384),eg(Q,384),{path:Q,policy:ne,errors:[]}}function Tc(P,V){let z=cn(V,P.home);if(z.errors.length>0)return{errors:z.errors};return{preview:Ae(z.policy,P.env),errors:[]}}function $c(P,V={}){let z=u(P,V);if(!Dc(z))return Vt(P,Z,V);let Q=Ac(z,"utf-8");if(!Q.trim())return Vt(P,Z,V);try{return Vt(P,C(JSON.parse(Q),P.home),V)}catch{return Vt(P,Z,V)}}var Ic=new Set(["check","apply"]),Oc="(unset)";async function jc(P,V,z={}){let Q=xt({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},V),te=Q.positionals[0],ne=[...Q.errors,...te&&!Ic.has(te)?[`Unknown policy subcommand: ${te}`]:[],...te&&Ic.has(te)&&!Q.positionals[1]?[`policy ${te} requires a file`]:[],...Q.positionals.slice(2).map((Re)=>`Unexpected policy argument: ${Re}`)];if(ne.length>0){for(let Re of ne)console.error(Re);return 1}let ce=Q.positionals[1];if(!te||!ce)return wn(Xn,console.error),1;let he=Q.flags.global?u(P):b(z.cwd??process.cwd()),ye=dn(ce),be=[...ye.errors,...qn(ye.value,P.home).map((Re)=>`${ce}: ${Re}`),...!Q.flags.global&&lg(ye.value)&&ye.value.audit!==void 0?[`${ce}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(be.length>0){for(let Re of be)console.error(Re);return 1}let xe=C(ye.value,P.home);if(console.log(`Scope: ${Q.flags.global?"user":"project"} (${he})`),console.log(`Proposal: ${ce}`),Q.flags.global)Fc(C(dn(he).value,P.home),xe,!0);if(!Q.flags.global){let Re=Vn(P).baseline;console.log("Effective policy (user + project merged):"),Fc(Y(Re,ae(dn(he).value,P.home).policy).policy,Y(Re,ae(ye.value,P.home).policy).policy,!1)}if(te==="check")return 0;let Ie=z.input??process.stdin,Xe=z.output??process.stdout;if(!Ie.isTTY||!Xe.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${ce}${Q.flags.global?" --global":""}`),1;if(!await sg(`Apply this policy to ${he}? [y/N] `,Ie,Xe))return console.log("Cancelled; nothing was written."),0;return ag(P,he,ye.value,xe,Q.flags.global),console.log(`Policy applied: ${he}`),0}function sg(P,V,z){let Q=ig({input:V,output:z,terminal:!1});return new Promise((te)=>{Q.once("close",()=>te(!1)),Q.question(P,(ne)=>{te(/^y(es)?$/i.test(ne.trim())),Q.close()})})}function ag(P,V,z,Q,te){if(te){Vt(P,Q);return}rg(og(V),{recursive:!0}),Rt(V,Nr(z,Q))}function Fc(P,V,z){let Q=jr(P,V,z);if(Q.length===0){console.log("No changes.");return}console.log(`Changes (${Q.length}):`);for(let te of Q)console.log(` ${te.field}: ${te.before??Oc} -> ${te.after??Oc}`)}function lg(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{join as wh}from"node:path";var Nc="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Mr(P,V){if(!P.ok){Bc(P);return}Uc(P,V)}function Hc(P,V,z){if(P.ok)console.log(z);if(!P.add){Mr(P,`Added rulebook source: ${V}`);return}if(!P.ok){Bc(P);return}if(P.add.added.length>0)console.log(`Added ${P.add.added.length} ${P.add.added.length===1?"rulebook":"rulebooks"} from ${P.add.source} at ${P.add.ref}:`),P.add.added.forEach((Q)=>{console.log(` - ${Q}`)});if(P.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${P.add.source} at ${P.add.ref}: ${P.add.alreadyConfigured.join(", ")}`);if(P.add.commits.length>0)console.log(`Vendored at ${P.add.commits.map((Q)=>Q.slice(0,7)).join(", ")}.`);Uc(P,"Rule config updated.")}function Uc(P,V){for(let z of P.changes??[])console.log(z);console.log(V),console.log(""),cg(P.entries)}function cg(P){if(P.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${P.length}):`);for(let V of P)console.log(` - ${V.name} ${V.version} (${dg(V.ruleCount)})`),console.log(` Source: ${V.spec}`)}function dg(P){return`${P} ${P===1?"rule":"rules"}`}function Gc(P){un("Active sources",P.rulebooks,(V)=>[`[${V.source}] ${V.name} ${V.version}`,` Source: ${V.spec}`]),un("Active rules",P.rules,(V)=>[`[${pg(P,V.name)}] ${V.name}`,...ug(V),` Reason: ${V.reason}`]),un("Disabled rules",Mc(P,"off"),(V)=>[V.key]),un("Reason overrides",Mc(P,"reason"),(V)=>[V.key,` Reason: ${V.value.reason}`]),un("Transparent wrappers",P.transparent_wrappers,(V)=>[V]),un("Issues",P.errors,(V)=>[V]),un("Warnings",P.warnings,(V)=>[V])}function un(P,V,z){if(V.length===0){console.log(`${P}: (none)`);return}console.log(`${P} (${V.length}):`);for(let Q of V){let[te,...ne]=z(Q);console.log(` - ${te}`);for(let ce of ne)console.log(` ${ce}`)}}function ug(P){if(!P.match)return[` Command: ${P.subcommand?`${P.command} ${P.subcommand}`:P.command}`,` Block args: ${P.block_args.join(", ")}`];return[` Command: ${[P.command,...P.match.command_path].join(" ")}`,...P.match.any_args?[` Any args: ${P.match.any_args.join(", ")}`]:[],...P.match.exclude_args?[` Exclude args: ${P.match.exclude_args.join(", ")}`]:[]]}function pg(P,V){return P.rulebooks.find((z)=>z.rules.includes(V))?.source??"project"}function Mc(P,V){return Object.entries({...P.userConfig?.overrides,...P.projectConfig?.overrides}).filter((z)=>{if(V==="off")return z[1]==="off";return!!z[1]&&typeof z[1]==="object"}).map(([z,Q])=>({key:z,value:Q}))}function Bc(P){for(let V of P.errors)console.error(V)}import{dirname as pd,join as Jr}from"node:path";import{join as xi,resolve as Cg}from"node:path";function bi(P){let V=m(P);if(V.errors.length>0)return{ok:!1,result:{ok:!1,errors:V.errors,entries:[]}};return{ok:!0,config:V.config??it}}function qc(P){Rt(P,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function Vc(P){Rt(P,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Br}from"node:path";var fg="custom.";function Hr(P){if(P.rulebook_version!==2)return[];let V=P.rules.map((z)=>({name:z.name,command:z.command,block_args:[],match:z.match,reason:z.reason,intent:z.intent}));return(P.tests??[]).flatMap((z,Q)=>{let te=Li(h(z.command));if(te.length===0)return[`tests[${Q}]: could not parse fixture command: ${z.command}`];let ne=te.reduce((ce,he)=>ce??_(he,V)?.id.slice(fg.length),void 0);if(z.expect==="blocked"){if(ne===z.rule)return[];let ce=ne?`"${ne}" matched first`:"no rule matched";return[`tests[${Q}]: expected "${z.rule}" to block "${z.command}" but ${ce}`]}return ne?[`tests[${Q}]: expected "${z.command}" to be allowed but "${ne}" matched`]:[]})}function Li(P){return P.nodes.flatMap((V)=>{if(V.kind==="group"||V.kind==="function")return Li(V.body);if(V.kind!=="command")return[];let z=ge(X(V.dialect,V.words)).words.map(t);return[...z.length>0?[z]:[],...V.nested.flatMap((Q)=>Li(Q))]})}var Ur=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Gr(P={}){return{requests:0,responseBytes:0,maxRequests:P.maxRequests??Ur.maxRequests,maxResponseBytes:P.maxResponseBytes??Ur.maxResponseBytes}}function zt(P){return{controller:new AbortController,budget:Gr(),resolveUrl:P}}function zc(P){return P instanceof Error&&P.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Jc(P){if(P.requests>=P.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.requests++}function Wc(P,V){if(V>P.maxResponseBytes-P.responseBytes)throw P.responseBytes+=V,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.responseBytes+=V}var Zc=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Kc(P,V,z=v(Br(Br(V)),"rules policy"),Q=zt()){if(S(P))return yg(P,Q);return hg(P,V,z)}async function Xc(P,V,z,Q,te,ne){if(!S(P))return Kc(P,V,z,Q);let ce=te?null:mg(P,V,z);if(ce)return ce;if(!te&&!ne)throw Error(`${P} is not vendored; run rule update ${P} to vendor it`);return Kc(P,V,z,Q)}function mg(P,V,z=v(Br(Br(V)),"rules policy")){let Q=A(P),te=I(V,Q.name),ne=n(i(z,te));if(ne===null)return null;let ce=se(wi(ne,`Invalid rulebook ${te}.`));if(ce.name!==Q.name)throw Error(`rulebook name "${ce.name}" in ${te} must match "${Q.name}"`);return{spec:P,rulebook:ce,content:ne}}async function Qc(P,V={}){if(!q(P))throw Error(`Invalid GitHub repository source: ${P}`);let[z,Q]=P.split("/");if(!z||!Q)throw Error(`Invalid GitHub repository source: ${P}`);if(V.ref!==void 0&&!oe(V.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${V.ref}`);let te=V.operation??zt(),ne=V.ref??await gg(z,Q,P,te),ce=await td(z,Q,ne,P,te),he=await qr(`https://api.github.com/repos/${z}/${Q}/git/trees/${ce}?recursive=1`,"tree",te),ye=he.response;if(!ye.ok)throw Error(`Failed to inspect ${P}: GitHub tree returned ${ye.status}`);let be=JSON.parse(he.content);if(!Array.isArray(be?.tree))throw Error(`Failed to inspect ${P}: unexpected GitHub tree response`);let xe=be.tree,Ie=[...new Set(xe.flatMap((Xe)=>{if(!Xe||typeof Xe!=="object")return[];let et=Xe;if(et.type!=="blob"||typeof et.path!=="string")return[];let Re=et.path.match(rt);return Re?.[1]?[Re[1]]:[]}))].sort();if(Ie.length===0)throw Error(`No rulebooks found in ${P} under ${de}/`);return{source:P,owner:z,repo:Q,ref:ne,commit:ce,names:Ie}}async function gg(P,V,z,Q){let te=await qr(`https://api.github.com/repos/${P}/${V}`,"metadata",Q),ne=te.response;if(!ne.ok)throw Error(`Failed to inspect ${z}: GitHub returned ${ne.status}`);let he=JSON.parse(te.content)?.default_branch;if(typeof he!=="string"||he==="")throw Error(`Failed to inspect ${z}: missing default branch`);if(!oe(he))throw Error(`GitHub returned an invalid default branch: ${he}`);return he}function hg(P,V,z){ot(P);let Q=I(V,P),te=n(i(z,Q));if(te===null)throw Error(`Rulebook source not found: ${P}`);let ne=ed(wi(te,"Invalid local rulebook source."));if(ne.name!==P)throw Error(`rulebook name "${ne.name}" must match local source "${P}"`);return{spec:P,rulebook:ne,content:te}}async function yg(P,V){let z=A(P),Q=await td(z.owner,z.repo,z.ref,P,V),te=await qr(`https://raw.githubusercontent.com/${z.owner}/${z.repo}/${Q}/${z.path}`,"raw",V),ne=te.response;if(!ne.ok)throw Error(`Failed to fetch ${P}: GitHub raw returned ${ne.status}`);let ce=te.content,he=ed(wi(ce,"Invalid GitHub rulebook response."));if(he.name!==z.name)throw Error(`rulebook name "${he.name}" must match GitHub source "${z.name}"`);return{spec:P,rulebook:he,content:ce}}function ed(P){let V=se(P),z=Hr(V);if(z.length>0)throw Error(z.join("; "));return V}function wi(P,V){try{return JSON.parse(P)}catch{throw Error(V)}}async function td(P,V,z,Q,te){let ne=await qr(`https://api.github.com/repos/${P}/${V}/commits/${encodeURIComponent(z)}`,"commit",te),ce=ne.response;if(!ce.ok)throw Error(`Failed to resolve ${Q}: GitHub returned ${ce.status}`);let he=JSON.parse(ne.content);if(typeof he?.sha!=="string"||he.sha==="")throw Error(`Failed to resolve commit for ${Q}`);return he.sha}async function vg(P,V,z={}){if(z.signal?.aborted)throw z.signal.reason;let Q=z.budget??Gr(),te=new AbortController,ne=()=>te.abort(z.signal?.reason);z.signal?.addEventListener("abort",ne,{once:!0});let ce=!1,he=setTimeout(()=>{if(te.signal.aborted)return;ce=!0,te.abort()},z.timeoutMs??Zc.timeoutMs);try{if(z.signal?.aborted)throw z.signal.reason;Jc(Q);let ye=await fetch(P,{signal:te.signal,redirect:"error"});if(!ye.ok)return nd(ye),{response:ye,content:""};return{response:ye,content:await bg(ye,V,Q,()=>te.abort())}}catch(ye){if(ce)throw Error("GitHub request timed out",{cause:ye});if(z.signal?.aborted)throw z.signal.reason;throw ye}finally{clearTimeout(he),z.signal?.removeEventListener("abort",ne)}}function qr(P,V,z){return vg(z.resolveUrl?.(P)??P,V,{budget:z.budget,signal:z.controller.signal})}async function bg(P,V,z=Gr(),Q){let te=Zc[`${V}Bytes`],ne=Number(P.headers.get("content-length"));if(Number.isFinite(ne)&&ne>te)throw nd(P),Error(`GitHub ${V} response exceeds ${te} bytes`);if(!P.body)return"";let ce=P.body.getReader(),he=[],ye=0;while(!0){let be=await ce.read();if(be.done)break;try{Wc(z,be.value.byteLength)}catch(xe){throw Q?.(),Yc(ce),xe}if(ye+=be.value.byteLength,ye>te)throw Q?.(),Yc(ce),Error(`GitHub ${V} response exceeds ${te} bytes`);he.push(Buffer.from(be.value))}return Buffer.concat(he,ye).toString("utf-8")}function nd(P){if(!P.body)return;rd(()=>P.body?.cancel())}function Yc(P){rd(()=>P.cancel())}function rd(P){try{Promise.resolve(P()).catch(()=>{})}catch{}}var Lg=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function od(P,V){let z=ad(P.rules,V);if(z.length>0)return{ok:!0,specs:z};return sd(P.rules,V)}function id(P,V){let z=ad(P,V);if(z.length>0)return{ok:!0,specs:z};let Q=kg(P,V);if(Q.length>0)return{ok:!0,specs:Q};let te=xg(P,V);if(!te.ok)return te;if(te.specs.length>0)return{ok:!0,specs:te.specs};return sd(P,V)}function sd(P,V){let z=P.filter((Q)=>ki(Q)?.name===V);if(z.length===1)return{ok:!0,specs:z};return wg(V,z)}function wg(P,V){return{ok:!1,result:{ok:!1,errors:V.length===0?[`No configured rulebook matches ${P}`]:[`Ambiguous rulebook match ${P}: ${V.join(", ")}`],entries:[]}}}function ad(P,V){return P.filter((z)=>z===V)}function kg(P,V){let z=V.match(Lg),Q=z?.[1],te=z?.[2],ne=z?.[3];if(!Q||!te||!ne||!oe(ne))return[];return ld(P,(ce)=>ce.owner===Q&&ce.repo===te&&ce.ref===ne)}function xg(P,V){if(!q(V))return{ok:!0,specs:[]};let[z,Q]=V.split("/"),te=ld(P,(ce)=>ce.owner===z&&ce.repo===Q);if(new Set(te.map((ce)=>ki(ce)?.ref).filter((ce)=>!!ce)).size<2)return{ok:!0,specs:te};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${V}. Use an explicit ref:`,` cc-safety-net rule remove ${V}#<ref>`],entries:[]}}}function ki(P){try{return A(P)}catch{return null}}function ld(P,V){return P.filter((z)=>{let Q=ki(z);return Q?V(Q):!1})}async function zr(P,V={}){let z=Ci(V);return Sg(P,z,await Vr(P,z,zt()))}function Sg(P,V,z){if(!z.ok)return z;let Q=Pt(P,V),te=[...new Set(j(Q.configPath,Q.filesystemScope))];if(te.length===0)return z;return{ok:!1,errors:te,entries:z.entries}}async function Vr(P,V,z,Q={},te=new Set,ne=new Set){try{let ce=Pt(P,V),he=bi(ce.configTarget);if(!he.ok)return he.result;let ye=he.config,be=V.only?od(ye,V.only):{ok:!0,specs:ye.rules};if(!be.ok)return be.result;let xe=new Set([...V.refresh?be.specs:[],...te]),Ie=(ut)=>Xc(ut,ce.configDir,ce.filesystemScope,z,xe.has(ut),!V.refresh||xe.has(ut)),Xe=await Fg(ye.rules,V.refresh?(ut)=>Ie(ut).then((vt)=>({ok:!0,item:vt})).catch((vt)=>{if(zc(vt))throw vt;return{ok:!1,spec:ut,message:vt instanceof Error?vt.message:String(vt)}}):async(ut)=>({ok:!0,item:await Ie(ut)}),z),et=Xe.filter((ut)=>!ut.ok),Re=Xe.filter((ut)=>ut.ok).map((ut)=>ut.item),at=Re.flatMap((ut)=>Rg(ut,ye.rules)),ct=Re.flatMap((ut)=>Pg(ut,ne,ce)),lt=new Set([...at,...ct].map((ut)=>ut.spec)),pt=[...et,...at,...ct],mt=[],gt=Dg(mt,()=>Re.flatMap((ut)=>lt.has(ut.spec)||pt.length>0&&ne.has(ut.spec)?[]:Eg(ut,ce,Q,mt)));return{ok:pt.length===0,errors:pt.map((ut)=>`Failed to update ${ut.spec}: ${ut.message}`),entries:Re.map(_g),changes:gt}}catch(ce){return Jn(ce)}}function Rg(P,V){if(!S(P.spec))return[];let z=Pe(P.spec),Q=V.filter((te)=>te!==P.spec&&Pe(te).toLowerCase()===z.toLowerCase());if(Q.length===0)return[];return[{ok:!1,spec:P.spec,message:`rulebook name "${z}" is also claimed by ${Q.join(", ")}; rename one of them`}]}function Pg(P,V,z){if(!V.has(P.spec)||!S(P.spec))return[];let Q=I(z.configDir,P.rulebook.name),te=n(i(z.filesystemScope,Q));if(te===null||te===P.content)return[];return[{ok:!1,spec:P.spec,message:`${Q} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Eg(P,V,z,Q){if(!S(P.spec))return[];let te=I(V.configDir,P.rulebook.name),ne=i(V.filesystemScope,te),ce=n(ne);if(ce===P.content)return[];return Q?.push({target:ne,previous:ce}),g(ne,P.content,void 0,z._testAfterPolicyRename),Ag(P,ce)}function Dg(P,V){try{return V()}catch(z){for(let Q of[...P].reverse()){if(Q.previous===null){N(Q.target);continue}g(Q.target,Q.previous)}throw z}}function Ag(P,V){if(V===null)return[`Vendored ${P.spec} (${P.rulebook.version})`];let z=me(V),Q="problem"in z?null:z.rulebook,te=new Map(Q?.rules.map((ce)=>[ce.name,JSON.stringify(ce)])??[]),ne=new Set(P.rulebook.rules.map((ce)=>ce.name));return[`Updated ${P.spec} (${Q?.version??"unreadable"} -> ${P.rulebook.version})`,...[...ne].filter((ce)=>!te.has(ce)).map((ce)=>` + ${ce}`),...[...te.keys()].filter((ce)=>!ne.has(ce)).map((ce)=>` - ${ce}`),...P.rulebook.rules.filter((ce)=>{let he=te.get(ce.name);return he!==void 0&&he!==JSON.stringify(ce)}).map((ce)=>` ~ ${ce.name}`)]}function _g(P){return{spec:P.spec,name:P.rulebook.name,version:P.rulebook.version,ruleCount:P.rulebook.rules.length}}async function cd(P,V,z={}){return Tg(P,V,Ng(z),zt())}async function Tg(P,V,z,Q,te={}){let ne=null,ce=!1;try{let he=Pt(P,z),ye=n(he.configTarget);ne={target:he.configTarget,content:ye};let be=bi(he.configTarget);if(!be.ok)return be.result;let xe=be.config,Ie=q(V);$g(V,z,Ie);let Xe=Ie?await Qc(V,{ref:z.ref,operation:Q}):null,et=Xe?Ig(Xe,z.rulebooks):[],Re=Xe?et.map((mt)=>Og(xe.rules,Xe,mt)??`${V}#${Xe.ref}/${mt}`):[V],at=Re.filter((mt)=>!xe.rules.includes(mt)),ct=[...xe.rules,...at];if(ct.length>pe)return jg();if(ct.length!==xe.rules.length)ce=!0,Rt(he.configTarget,{version:1,rules:ct,overrides:xe.overrides??{},transparent_wrappers:xe.transparent_wrappers??[]},void 0,te._testAfterPolicyRename);let lt=await Vr(P,z,Q,te,new Set(at),new Set(at));if(!lt.ok)zn(he.configTarget,ye);if(!lt.ok||!Xe)return lt;let pt=et.filter((mt,gt)=>at.includes(Re[gt]??""));return{...lt,add:{source:V,ref:Xe.ref,selected:et,added:pt,alreadyConfigured:et.filter((mt)=>!pt.includes(mt)),commits:at.length>0?[Xe.commit]:[]}}}catch(he){if(ce&&ne)try{zn(ne.target,ne.content)}catch(ye){return Jn(ye)}return Jn(he)}}function $g(P,V,z){if(!z&&V.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!z&&V.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${P}`);if(V.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let Q=V.rulebooks?.filter((te)=>!l.test(te))??[];if(Q.length>0)throw Error(`Invalid rulebook names: ${Q.join(", ")}`)}function Ig(P,V){let z=V?[...new Set(V)]:P.names,Q=z.filter((te)=>!P.names.includes(te));if(Q.length>0)throw Error(`Rulebooks not found in ${P.source} at ${P.ref}: ${Q.join(", ")}
263
+ `,384),eg(Q,384),{path:Q,policy:ne,errors:[]}}function Tc(P,V){let z=cn(V,P.home);if(z.errors.length>0)return{errors:z.errors};return{preview:Ae(z.policy,P.env),errors:[]}}function $c(P,V={}){let z=u(P,V);if(!Dc(z))return Vt(P,Z,V);let Q=Ac(z,"utf-8");if(!Q.trim())return Vt(P,Z,V);try{return Vt(P,C(JSON.parse(Q),P.home),V)}catch{return Vt(P,Z,V)}}var Ic=new Set(["check","apply"]),Oc="(unset)";async function jc(P,V,z={}){let Q=xt({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},V),te=Q.positionals[0],ne=[...Q.errors,...te&&!Ic.has(te)?[`Unknown policy subcommand: ${te}`]:[],...te&&Ic.has(te)&&!Q.positionals[1]?[`policy ${te} requires a file`]:[],...Q.positionals.slice(2).map((Re)=>`Unexpected policy argument: ${Re}`)];if(ne.length>0){for(let Re of ne)console.error(Re);return 1}let ce=Q.positionals[1];if(!te||!ce)return wn(Xn,console.error),1;let he=Q.flags.global?u(P):b(z.cwd??process.cwd()),ye=dn(ce),be=[...ye.errors,...qn(ye.value,P.home).map((Re)=>`${ce}: ${Re}`),...!Q.flags.global&&lg(ye.value)&&ye.value.audit!==void 0?[`${ce}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(be.length>0){for(let Re of be)console.error(Re);return 1}let xe=C(ye.value,P.home);if(console.log(`Scope: ${Q.flags.global?"user":"project"} (${he})`),console.log(`Proposal: ${ce}`),Q.flags.global)Fc(C(dn(he).value,P.home),xe,!0);if(!Q.flags.global){let Re=Vn(P).baseline;console.log("Effective policy (user + project merged):"),Fc(Y(Re,ae(dn(he).value,P.home).policy).policy,Y(Re,ae(ye.value,P.home).policy).policy,!1)}if(te==="check")return 0;let Ie=z.input??process.stdin,Xe=z.output??process.stdout;if(!Ie.isTTY||!Xe.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${ce}${Q.flags.global?" --global":""}`),1;if(!await sg(`Apply this policy to ${he}? [y/N] `,Ie,Xe))return console.log("Cancelled; nothing was written."),0;return ag(P,he,ye.value,xe,Q.flags.global),console.log(`Policy applied: ${he}`),0}function sg(P,V,z){let Q=ig({input:V,output:z,terminal:!1});return new Promise((te)=>{Q.once("close",()=>te(!1)),Q.question(P,(ne)=>{te(/^y(es)?$/i.test(ne.trim())),Q.close()})})}function ag(P,V,z,Q,te){if(te){Vt(P,Q);return}rg(og(V),{recursive:!0}),Rt(V,Nr(z,Q))}function Fc(P,V,z){let Q=jr(P,V,z);if(Q.length===0){console.log("No changes.");return}console.log(`Changes (${Q.length}):`);for(let te of Q)console.log(` ${te.field}: ${te.before??Oc} -> ${te.after??Oc}`)}function lg(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{join as wh}from"node:path";var Nc="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Mr(P,V){if(!P.ok){Bc(P);return}Uc(P,V)}function Hc(P,V,z){if(P.ok)console.log(z);if(!P.add){Mr(P,`Added rulebook source: ${V}`);return}if(!P.ok){Bc(P);return}if(P.add.added.length>0)console.log(`Added ${P.add.added.length} ${P.add.added.length===1?"rulebook":"rulebooks"} from ${P.add.source} at ${P.add.ref}:`),P.add.added.forEach((Q)=>{console.log(` - ${Q}`)});if(P.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${P.add.source} at ${P.add.ref}: ${P.add.alreadyConfigured.join(", ")}`);if(P.add.commits.length>0)console.log(`Vendored at ${P.add.commits.map((Q)=>Q.slice(0,7)).join(", ")}.`);Uc(P,"Rule config updated.")}function Uc(P,V){for(let z of P.changes??[])console.log(z);console.log(V),console.log(""),cg(P.entries)}function cg(P){if(P.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${P.length}):`);for(let V of P)console.log(` - ${V.name} ${V.version} (${dg(V.ruleCount)})`),console.log(` Source: ${V.spec}`)}function dg(P){return`${P} ${P===1?"rule":"rules"}`}function Gc(P){un("Active sources",P.rulebooks,(V)=>[`[${V.source}] ${V.name} ${V.version}`,` Source: ${V.spec}`]),un("Active rules",P.rules,(V)=>[`[${pg(P,V.name)}] ${V.name}`,...ug(V),` Reason: ${V.reason}`]),un("Disabled rules",Mc(P,"off"),(V)=>[V.key]),un("Reason overrides",Mc(P,"reason"),(V)=>[V.key,` Reason: ${V.value.reason}`]),un("Transparent wrappers",P.transparent_wrappers,(V)=>[V]),un("Issues",P.errors,(V)=>[V]),un("Warnings",P.warnings,(V)=>[V])}function un(P,V,z){if(V.length===0){console.log(`${P}: (none)`);return}console.log(`${P} (${V.length}):`);for(let Q of V){let[te,...ne]=z(Q);console.log(` - ${te}`);for(let ce of ne)console.log(` ${ce}`)}}function ug(P){if(!P.match)return[` Command: ${P.subcommand?`${P.command} ${P.subcommand}`:P.command}`,` Block args: ${P.block_args.join(", ")}`];return[` Command: ${[P.command,...P.match.command_path].join(" ")}`,...P.match.any_args?[` Any args: ${P.match.any_args.join(", ")}`]:[],...P.match.exclude_args?[` Exclude args: ${P.match.exclude_args.join(", ")}`]:[]]}function pg(P,V){return P.rulebooks.find((z)=>z.rules.includes(V))?.source??"project"}function Mc(P,V){return Object.entries({...P.userConfig?.overrides,...P.projectConfig?.overrides}).filter((z)=>{if(V==="off")return z[1]==="off";return!!z[1]&&typeof z[1]==="object"}).map(([z,Q])=>({key:z,value:Q}))}function Bc(P){for(let V of P.errors)console.error(V)}import{dirname as pd,join as Jr}from"node:path";import{join as xi,resolve as Cg}from"node:path";function bi(P){let V=m(P);if(V.errors.length>0)return{ok:!1,result:{ok:!1,errors:V.errors,entries:[]}};return{ok:!0,config:V.config??it}}function qc(P){Rt(P,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function Vc(P){Rt(P,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Br}from"node:path";var fg="custom.";function Hr(P){if(P.rulebook_version!==2)return[];let V=P.rules.map((z)=>({name:z.name,command:z.command,block_args:[],match:z.match,reason:z.reason,intent:z.intent}));return(P.tests??[]).flatMap((z,Q)=>{let te=Li(h(z.command));if(te.length===0)return[`tests[${Q}]: could not parse fixture command: ${z.command}`];let ne=te.reduce((ce,he)=>ce??_(he,V)?.id.slice(fg.length),void 0);if(z.expect==="blocked"){if(ne===z.rule)return[];let ce=ne?`"${ne}" matched first`:"no rule matched";return[`tests[${Q}]: expected "${z.rule}" to block "${z.command}" but ${ce}`]}return ne?[`tests[${Q}]: expected "${z.command}" to be allowed but "${ne}" matched`]:[]})}function Li(P){return P.nodes.flatMap((V)=>{if(V.kind==="group"||V.kind==="function")return Li(V.body);if(V.kind!=="command")return[];let z=ge(X(V.dialect,V.words)).words.map(t);return[...z.length>0?[z]:[],...V.nested.flatMap((Q)=>Li(Q))]})}var Ur=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Gr(P={}){return{requests:0,responseBytes:0,maxRequests:P.maxRequests??Ur.maxRequests,maxResponseBytes:P.maxResponseBytes??Ur.maxResponseBytes}}function zt(P){return{controller:new AbortController,budget:Gr(),resolveUrl:P}}function zc(P){return P instanceof Error&&P.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Jc(P){if(P.requests>=P.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.requests++}function Wc(P,V){if(V>P.maxResponseBytes-P.responseBytes)throw P.responseBytes+=V,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.responseBytes+=V}var Zc=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Kc(P,V,z=v(Br(Br(V)),"rules policy"),Q=zt()){if(S(P))return yg(P,Q);return hg(P,V,z)}async function Xc(P,V,z,Q,te,ne){if(!S(P))return Kc(P,V,z,Q);let ce=te?null:mg(P,V,z);if(ce)return ce;if(!te&&!ne)throw Error(`${P} is not vendored; run rule update ${P} to vendor it`);return Kc(P,V,z,Q)}function mg(P,V,z=v(Br(Br(V)),"rules policy")){let Q=A(P),te=I(V,Q.name),ne=n(i(z,te));if(ne===null)return null;let ce=se(wi(ne,`Invalid rulebook ${te}.`));if(ce.name!==Q.name)throw Error(`rulebook name "${ce.name}" in ${te} must match "${Q.name}"`);return{spec:P,rulebook:ce,content:ne}}async function Qc(P,V={}){if(!q(P))throw Error(`Invalid GitHub repository source: ${P}`);let[z,Q]=P.split("/");if(!z||!Q)throw Error(`Invalid GitHub repository source: ${P}`);if(V.ref!==void 0&&!oe(V.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${V.ref}`);let te=V.operation??zt(),ne=V.ref??await gg(z,Q,P,te),ce=await td(z,Q,ne,P,te),he=await qr(`https://api.github.com/repos/${z}/${Q}/git/trees/${ce}?recursive=1`,"tree",te),ye=he.response;if(!ye.ok)throw Error(`Failed to inspect ${P}: GitHub tree returned ${ye.status}`);let be=JSON.parse(he.content);if(!Array.isArray(be?.tree))throw Error(`Failed to inspect ${P}: unexpected GitHub tree response`);let xe=be.tree,Ie=[...new Set(xe.flatMap((Xe)=>{if(!Xe||typeof Xe!=="object")return[];let et=Xe;if(et.type!=="blob"||typeof et.path!=="string")return[];let Re=et.path.match(rt);return Re?.[1]?[Re[1]]:[]}))].sort();if(Ie.length===0)throw Error(`No rulebooks found in ${P} under ${de}/`);return{source:P,owner:z,repo:Q,ref:ne,commit:ce,names:Ie}}async function gg(P,V,z,Q){let te=await qr(`https://api.github.com/repos/${P}/${V}`,"metadata",Q),ne=te.response;if(!ne.ok)throw Error(`Failed to inspect ${z}: GitHub returned ${ne.status}`);let he=JSON.parse(te.content)?.default_branch;if(typeof he!=="string"||he==="")throw Error(`Failed to inspect ${z}: missing default branch`);if(!oe(he))throw Error(`GitHub returned an invalid default branch: ${he}`);return he}function hg(P,V,z){ot(P);let Q=I(V,P),te=n(i(z,Q));if(te===null)throw Error(`Rulebook source not found: ${P}`);let ne=ed(wi(te,"Invalid local rulebook source."));if(ne.name!==P)throw Error(`rulebook name "${ne.name}" must match local source "${P}"`);return{spec:P,rulebook:ne,content:te}}async function yg(P,V){let z=A(P),Q=await td(z.owner,z.repo,z.ref,P,V),te=await qr(`https://raw.githubusercontent.com/${z.owner}/${z.repo}/${Q}/${z.path}`,"raw",V),ne=te.response;if(!ne.ok)throw Error(`Failed to fetch ${P}: GitHub raw returned ${ne.status}`);let ce=te.content,he=ed(wi(ce,"Invalid GitHub rulebook response."));if(he.name!==z.name)throw Error(`rulebook name "${he.name}" must match GitHub source "${z.name}"`);return{spec:P,rulebook:he,content:ce}}function ed(P){let V=se(P),z=Hr(V);if(z.length>0)throw Error(z.join("; "));return V}function wi(P,V){try{return JSON.parse(P)}catch{throw Error(V)}}async function td(P,V,z,Q,te){let ne=await qr(`https://api.github.com/repos/${P}/${V}/commits/${encodeURIComponent(z)}`,"commit",te),ce=ne.response;if(!ce.ok)throw Error(`Failed to resolve ${Q}: GitHub returned ${ce.status}`);let he=JSON.parse(ne.content);if(typeof he?.sha!=="string"||he.sha==="")throw Error(`Failed to resolve commit for ${Q}`);return he.sha}async function vg(P,V,z={}){if(z.signal?.aborted)throw z.signal.reason;let Q=z.budget??Gr(),te=new AbortController,ne=()=>te.abort(z.signal?.reason);z.signal?.addEventListener("abort",ne,{once:!0});let ce=!1,he=setTimeout(()=>{if(te.signal.aborted)return;ce=!0,te.abort()},z.timeoutMs??Zc.timeoutMs);try{if(z.signal?.aborted)throw z.signal.reason;Jc(Q);let ye=await fetch(P,{signal:te.signal,redirect:"error"});if(!ye.ok)return nd(ye),{response:ye,content:""};return{response:ye,content:await bg(ye,V,Q,()=>te.abort())}}catch(ye){if(ce)throw Error("GitHub request timed out",{cause:ye});if(z.signal?.aborted)throw z.signal.reason;throw ye}finally{clearTimeout(he),z.signal?.removeEventListener("abort",ne)}}function qr(P,V,z){return vg(z.resolveUrl?.(P)??P,V,{budget:z.budget,signal:z.controller.signal})}async function bg(P,V,z=Gr(),Q){let te=Zc[`${V}Bytes`],ne=Number(P.headers.get("content-length"));if(Number.isFinite(ne)&&ne>te)throw nd(P),Error(`GitHub ${V} response exceeds ${te} bytes`);if(!P.body)return"";let ce=P.body.getReader(),he=[],ye=0;while(!0){let be=await ce.read();if(be.done)break;try{Wc(z,be.value.byteLength)}catch(xe){throw Q?.(),Yc(ce),xe}if(ye+=be.value.byteLength,ye>te)throw Q?.(),Yc(ce),Error(`GitHub ${V} response exceeds ${te} bytes`);he.push(Buffer.from(be.value))}return Buffer.concat(he,ye).toString("utf-8")}function nd(P){if(!P.body)return;rd(()=>P.body?.cancel())}function Yc(P){rd(()=>P.cancel())}function rd(P){try{Promise.resolve(P()).catch(()=>{})}catch{}}var Lg=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function od(P,V){let z=ad(P.rules,V);if(z.length>0)return{ok:!0,specs:z};return sd(P.rules,V)}function id(P,V){let z=ad(P,V);if(z.length>0)return{ok:!0,specs:z};let Q=kg(P,V);if(Q.length>0)return{ok:!0,specs:Q};let te=xg(P,V);if(!te.ok)return te;if(te.specs.length>0)return{ok:!0,specs:te.specs};return sd(P,V)}function sd(P,V){let z=P.filter((Q)=>ki(Q)?.name===V);if(z.length===1)return{ok:!0,specs:z};return wg(V,z)}function wg(P,V){return{ok:!1,result:{ok:!1,errors:V.length===0?[`No configured rulebook matches ${P}`]:[`Ambiguous rulebook match ${P}: ${V.join(", ")}`],entries:[]}}}function ad(P,V){return P.filter((z)=>z===V)}function kg(P,V){let z=V.match(Lg),Q=z?.[1],te=z?.[2],ne=z?.[3];if(!Q||!te||!ne||!oe(ne))return[];return ld(P,(ce)=>ce.owner===Q&&ce.repo===te&&ce.ref===ne)}function xg(P,V){if(!q(V))return{ok:!0,specs:[]};let[z,Q]=V.split("/"),te=ld(P,(ce)=>ce.owner===z&&ce.repo===Q);if(new Set(te.map((ce)=>ki(ce)?.ref).filter((ce)=>!!ce)).size<2)return{ok:!0,specs:te};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${V}. Use an explicit ref:`,` cc-safety-net rule remove ${V}#<ref>`],entries:[]}}}function ki(P){try{return A(P)}catch{return null}}function ld(P,V){return P.filter((z)=>{let Q=ki(z);return Q?V(Q):!1})}async function zr(P,V={}){let z=Ci(V);return Sg(P,z,await Vr(P,z,zt()))}function Sg(P,V,z){if(!z.ok)return z;let Q=Pt(P,V),te=[...new Set(j(Q.configPath,Q.filesystemScope))];if(te.length===0)return z;return{ok:!1,errors:te,entries:z.entries}}async function Vr(P,V,z,Q={},te=new Set,ne=new Set){try{let ce=Pt(P,V),he=bi(ce.configTarget);if(!he.ok)return he.result;let ye=he.config,be=V.only?od(ye,V.only):{ok:!0,specs:ye.rules};if(!be.ok)return be.result;let xe=new Set([...V.refresh?be.specs:[],...te]),Ie=(ut)=>Xc(ut,ce.configDir,ce.filesystemScope,z,xe.has(ut),!V.refresh||xe.has(ut)),Xe=await Fg(ye.rules,V.refresh?(ut)=>Ie(ut).then((yt)=>({ok:!0,item:yt})).catch((yt)=>{if(zc(yt))throw yt;return{ok:!1,spec:ut,message:yt instanceof Error?yt.message:String(yt)}}):async(ut)=>({ok:!0,item:await Ie(ut)}),z),et=Xe.filter((ut)=>!ut.ok),Re=Xe.filter((ut)=>ut.ok).map((ut)=>ut.item),at=Re.flatMap((ut)=>Rg(ut,ye.rules)),ct=Re.flatMap((ut)=>Pg(ut,ne,ce)),lt=new Set([...at,...ct].map((ut)=>ut.spec)),pt=[...et,...at,...ct],mt=[],gt=Dg(mt,()=>Re.flatMap((ut)=>lt.has(ut.spec)||pt.length>0&&ne.has(ut.spec)?[]:Eg(ut,ce,Q,mt)));return{ok:pt.length===0,errors:pt.map((ut)=>`Failed to update ${ut.spec}: ${ut.message}`),entries:Re.map(_g),changes:gt}}catch(ce){return Jn(ce)}}function Rg(P,V){if(!S(P.spec))return[];let z=Pe(P.spec),Q=V.filter((te)=>te!==P.spec&&Pe(te).toLowerCase()===z.toLowerCase());if(Q.length===0)return[];return[{ok:!1,spec:P.spec,message:`rulebook name "${z}" is also claimed by ${Q.join(", ")}; rename one of them`}]}function Pg(P,V,z){if(!V.has(P.spec)||!S(P.spec))return[];let Q=I(z.configDir,P.rulebook.name),te=n(i(z.filesystemScope,Q));if(te===null||te===P.content)return[];return[{ok:!1,spec:P.spec,message:`${Q} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Eg(P,V,z,Q){if(!S(P.spec))return[];let te=I(V.configDir,P.rulebook.name),ne=i(V.filesystemScope,te),ce=n(ne);if(ce===P.content)return[];return Q?.push({target:ne,previous:ce}),g(ne,P.content,void 0,z._testAfterPolicyRename),Ag(P,ce)}function Dg(P,V){try{return V()}catch(z){for(let Q of[...P].reverse()){if(Q.previous===null){N(Q.target);continue}g(Q.target,Q.previous)}throw z}}function Ag(P,V){if(V===null)return[`Vendored ${P.spec} (${P.rulebook.version})`];let z=me(V),Q="problem"in z?null:z.rulebook,te=new Map(Q?.rules.map((ce)=>[ce.name,JSON.stringify(ce)])??[]),ne=new Set(P.rulebook.rules.map((ce)=>ce.name));return[`Updated ${P.spec} (${Q?.version??"unreadable"} -> ${P.rulebook.version})`,...[...ne].filter((ce)=>!te.has(ce)).map((ce)=>` + ${ce}`),...[...te.keys()].filter((ce)=>!ne.has(ce)).map((ce)=>` - ${ce}`),...P.rulebook.rules.filter((ce)=>{let he=te.get(ce.name);return he!==void 0&&he!==JSON.stringify(ce)}).map((ce)=>` ~ ${ce.name}`)]}function _g(P){return{spec:P.spec,name:P.rulebook.name,version:P.rulebook.version,ruleCount:P.rulebook.rules.length}}async function cd(P,V,z={}){return Tg(P,V,Ng(z),zt())}async function Tg(P,V,z,Q,te={}){let ne=null,ce=!1;try{let he=Pt(P,z),ye=n(he.configTarget);ne={target:he.configTarget,content:ye};let be=bi(he.configTarget);if(!be.ok)return be.result;let xe=be.config,Ie=q(V);$g(V,z,Ie);let Xe=Ie?await Qc(V,{ref:z.ref,operation:Q}):null,et=Xe?Ig(Xe,z.rulebooks):[],Re=Xe?et.map((mt)=>Og(xe.rules,Xe,mt)??`${V}#${Xe.ref}/${mt}`):[V],at=Re.filter((mt)=>!xe.rules.includes(mt)),ct=[...xe.rules,...at];if(ct.length>pe)return jg();if(ct.length!==xe.rules.length)ce=!0,Rt(he.configTarget,{version:1,rules:ct,overrides:xe.overrides??{},transparent_wrappers:xe.transparent_wrappers??[]},void 0,te._testAfterPolicyRename);let lt=await Vr(P,z,Q,te,new Set(at),new Set(at));if(!lt.ok)zn(he.configTarget,ye);if(!lt.ok||!Xe)return lt;let pt=et.filter((mt,gt)=>at.includes(Re[gt]??""));return{...lt,add:{source:V,ref:Xe.ref,selected:et,added:pt,alreadyConfigured:et.filter((mt)=>!pt.includes(mt)),commits:at.length>0?[Xe.commit]:[]}}}catch(he){if(ce&&ne)try{zn(ne.target,ne.content)}catch(ye){return Jn(ye)}return Jn(he)}}function $g(P,V,z){if(!z&&V.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!z&&V.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${P}`);if(V.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let Q=V.rulebooks?.filter((te)=>!l.test(te))??[];if(Q.length>0)throw Error(`Invalid rulebook names: ${Q.join(", ")}`)}function Ig(P,V){let z=V?[...new Set(V)]:P.names,Q=z.filter((te)=>!P.names.includes(te));if(Q.length>0)throw Error(`Rulebooks not found in ${P.source} at ${P.ref}: ${Q.join(", ")}
264
264
  Available rulebooks: ${P.names.join(", ")}`);return z}function Og(P,V,z){let Q=`${V.source}#${V.ref}/${z}`;if(P.includes(Q))return Q;let te=`${V.source}#${V.commit}/${z}`;return P.find((ne)=>ne===te)}async function Fg(P,V,z=zt()){if(P.length>pe)throw Error(fe);let Q=[],te=0,ne,ce=Array.from({length:Math.min(P.length,Ur.concurrency)},async()=>{while(!ne){let he=te;if(he>=P.length)return;te++;try{Q[he]=await V(P[he],he,z.controller.signal)}catch(ye){if(!ne)ne={value:ye},te=P.length,z.controller.abort(ye);return}}});if(await Promise.all(ce),ne)throw ne.value;return Q}function jg(){return{ok:!1,errors:[fe],entries:[]}}function Ci(P){return{cwd:P.cwd,userConfigDir:P.userConfigDir,userConfigPath:P.userConfigPath,projectConfigPath:P.projectConfigPath,global:P.global,only:P.only,refresh:P.refresh}}function Ng(P){return{...Ci(P),ref:P.ref,rulebooks:P.rulebooks}}function Mg(P){return{...Ci(P),deleteSource:P.deleteSource}}async function dd(P,V,z={}){try{return await Hg(P,V,Mg(z),{})}catch(Q){return Jn(Q)}}async function Hg(P,V,z,Q){let te=Pt(P,z),ne=m(te.configTarget);if(ne.errors.length>0)return{ok:!1,errors:ne.errors,entries:[]};if(!ne.config)return{ok:!1,errors:[`No config found at ${te.configPath}`],entries:[]};let ce=id(ne.config.rules,V);if(!ce.ok)return ce.result;let he=z.deleteSource?Ug(te.configDir,ce.specs,te.filesystemScope):{ok:!0,dirs:[]};if(!he.ok)return he.result;let ye=n(te.configTarget);if(ye===null)return Jn(Error("Rules config is unavailable."));try{Rt(te.configTarget,{version:1,rules:ne.config.rules.filter((Ie)=>!ce.specs.includes(Ie)),overrides:ne.config.overrides??{},transparent_wrappers:ne.config.transparent_wrappers??[]},void 0,Q._testAfterPolicyRename)}catch(Ie){throw zn(te.configTarget,ye),Ie}let be=await Vr(P,z,zt(),Q);if(!be.ok)return zn(te.configTarget,ye),be;let xe=Gg(he.dirs,Q,te.filesystemScope);if(!xe.ok){zn(te.configTarget,ye);let Ie=await Vr(P,z,zt(),Q);if(!Ie.ok)return{ok:!1,errors:[...xe.result.errors,...Ie.errors],entries:Ie.entries};return xe.result}return be}function Ug(P,V,z){let Q=V.flatMap((he)=>l.test(he)?[]:["--delete-source can only delete local rulebook sources"]),te=V.map((he)=>xi(P,he)),ne=Q.length>0?[]:te.flatMap((he)=>ud(he,z)),ce=[...Q,...ne];return ce.length>0?{ok:!1,result:{ok:!1,errors:ce,entries:[]}}:{ok:!0,dirs:te}}function ud(P,V){let z=Cg(P),Q=i(V,z),te=le(Q);if(!te)return[`Local rulebook source directory not found: ${P}`];let ne=te.find((ce)=>ce.name==="rulebook.json");if(!ne)return[`Local rulebook source directory is missing rulebook.json: ${P}`];if(ne.kind!=="file")throw new r(V.label);if(n(i(V,xi(z,"rulebook.json"))),te.length>1)return[`Local rulebook source directory contains extra files: ${P}. delete manually if you really want to remove the directory.`];return[]}function Gg(P,V,z){let Q=P.flatMap((te)=>{try{if(!le(i(z,te)))return[];let ne=ud(te,z);if(ne.length>0)return ne;return Bg(te,V,z),[]}catch(ne){return[`Failed to delete local rulebook source ${te}: ${ne instanceof Error?ne.message:String(ne)}`]}});return Q.length>0?{ok:!1,result:{ok:!1,errors:Q,entries:[]}}:{ok:!0}}function Bg(P,V,z){if(V._testDeleteLocalSourceDir){V._testDeleteLocalSourceDir(P);return}N(i(z,xi(P,ue))),nt(i(z,P))}function zn(P,V){if(V===null){N(P);return}g(P,V)}function Jn(P){return{ok:!1,errors:[P instanceof Error?P.message:String(P)],entries:[]}}var qg=".safety-net.json",Vg="~/.cc-safety-net/config.json";async function gd(P,V){return[await fd(P,{legacyPath:$s({cwd:V.cwd}),configPath:F(V.cwd),defaultRulebookName:"project-rules",migratedFrom:qg,cleanup:V.cleanup,syncOptions:{cwd:V.cwd}}),await fd(P,{legacyPath:nr(P),configPath:M(P),defaultRulebookName:"user-rules",migratedFrom:Vg,cleanup:V.cleanup,syncOptions:{cwd:V.cwd,global:!0}})].every((Q)=>Q)?0:1}async function fd(P,V){let z=Pt(P,V.syncOptions),Q=i(z.filesystemScope,V.legacyPath),te=n(Q);if(te===null)return console.log(`No legacy config found at ${V.legacyPath}`),!0;let ne=Jg(te);if(!ne.ok){for(let et of ne.errors)console.error(et);return!1}let ce=m(z.configTarget);if(ce.errors.length>0){for(let et of ce.errors)console.error(et);return!1}let he=ce.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},ye=Wg(pd(V.configPath),he.rules,V.defaultRulebookName,V.migratedFrom,z.filesystemScope),be=Jr(pd(V.configPath),ye,"rulebook.json"),xe=i(z.filesystemScope,be),Ie=[md(z.configTarget),md(xe)],Xe=await zg(P,V,z.configTarget,xe,ye,ne.config.rules,he.rules.includes(ye)?he.rules:[...he.rules,ye],he.overrides??{},he.transparent_wrappers??[]);if(!Xe.ok){Zg(Ie);for(let et of Xe.errors)console.error(et);return!1}if(!V.cleanup)return console.log(`Migrated legacy config at ${V.legacyPath}. Legacy file is no longer used.`),!0;if(!Yg(z.configTarget,xe,ye,V.migratedFrom,ne.config.rules))return console.error(`Migration cleanup verification failed for ${V.legacyPath}`),!1;return N(Q),console.log(`Deleted legacy config at ${V.legacyPath}`),!0}async function zg(P,V,z,Q,te,ne,ce,he,ye){try{return Rt(z,{version:1,rules:ce,overrides:he,transparent_wrappers:ye}),Rt(Q,Kg(te,V.migratedFrom,ne)),await zr(P,V.syncOptions)}catch(be){return{ok:!1,errors:[be instanceof Error?be.message:String(be)]}}}function Jg(P){try{let V=JSON.parse(P),z=ro(V);if(z.errors.length>0)return{ok:!1,errors:z.errors};return{ok:!0,config:{version:1,rules:V.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function Wg(P,V,z,Q,te){let ne=V.find((ce)=>Xg(i(te,Jr(P,ce,"rulebook.json")))===Q);if(ne)return ne;if(n(i(te,Jr(P,z,"rulebook.json")))===null)return z;for(let ce=2;;ce++){let he=`${z}-${ce}`;if(n(i(te,Jr(P,he,"rulebook.json")))===null)return he}}function Kg(P,V,z){return{rulebook_version:1,name:P,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:V,allowed_commands:[...new Set(z.map((Q)=>Q.command))],rules:z,tests:z.map((Q)=>({command:[Q.command,Q.subcommand,Q.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:Q.name}))}}function Yg(P,V,z,Q,te){if(!m(P).config?.rules.includes(z))return!1;try{let ce=n(V);if(ce===null)return!1;let he=JSON.parse(ce);return he.migrated_from===Q&&JSON.stringify(he.rules)===JSON.stringify(te)}catch{return!1}}function md(P){return{target:P,content:n(P)}}function Zg(P){for(let V of P){if(V.content===null){N(V.target);continue}g(V.target,V.content)}}function Xg(P){let V=n(P);if(V===null)return null;try{let z=JSON.parse(V);return typeof z.migrated_from==="string"?z.migrated_from:null}catch{return null}}import{mkdir as Qg,readFile as eh,writeFile as th}from"node:fs/promises";import{dirname as nh,join as rh}from"node:path";var oh=86400000,ih=604800000;async function yd(P,V=Date.now()){if(P.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let z=je(P);if(!z)return null;let Q=rh(z,".cc-safety-net","update-check.json"),te=await sh(Q,V);if(!te.lastCheck||V-te.lastCheck>oh){let he=await Wt();if(te.lastCheck=V,he.latestVersion)te.latestVersion=he.latestVersion;if(!await hd(Q,te))return null;if(he.error)return null}let ne=te.latestVersion,ce=wt();if(!ne||!co(ne,ce))return null;if(te.notifiedVersion===ne&&te.notifiedAt!==void 0&&V-te.notifiedAt<ih)return null;if(te.notifiedVersion=ne,te.notifiedAt=V,!await hd(Q,te))return null;return`UPDATE_AVAILABLE: cc-safety-net v${ne} is available (running v${ce}). 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 sh(P,V){let z=await eh(P,"utf8").then((ne)=>JSON.parse(ne)).catch(()=>{return});if(!z||typeof z!=="object"||Array.isArray(z))return{};let Q=z,te=(ne)=>typeof ne==="number"&&Number.isFinite(ne)&&ne<=V?ne:void 0;return{lastCheck:te(Q.lastCheck),latestVersion:typeof Q.latestVersion==="string"?Q.latestVersion:void 0,notifiedVersion:typeof Q.notifiedVersion==="string"?Q.notifiedVersion:void 0,notifiedAt:te(Q.notifiedAt)}}async function hd(P,V){return Qg(nh(P),{recursive:!0,mode:448}).then(()=>th(P,JSON.stringify(V),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as ah,resolve as Si}from"node:path";var vd="CC Safety Net Config",lh="═".repeat(vd.length),ch="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",dh=new Set(["rule.json","rule.lock","cache"]);function bd(P,V={}){try{return uh(P,V)}catch(z){if(z instanceof r)return console.error(z.message),1;throw z}}function uh(P,V){let z=V.cwd??process.cwd(),Q=K(P,{cwd:z}),te=nr(P),ne=ns(z),ce=Si(z,de),he=i(Q.userScope,te),ye=i(Q.projectScope,ne),be=!1,xe=!1,Ie=[],Xe=[],et=ph(i(Q.projectScope,ce));if(mh(),n(Q.userConfigTarget)!==null){let Re=Jt(Q.userConfigTarget);if(Re.errors.push(...j(Q.userConfigPath,Q.userScope)),Ie.push({scope:"User",path:Q.userConfigPath,result:Re,schema:"rules",target:Q.userConfigTarget}),Re.errors.length>0)be=!0}if(n(he)!==null)if(xe=!0,n(Q.userConfigTarget)!==null)Xe.push(Wr("user","cleanup"));else{let Re=oo(he);if(Ie.push({scope:"User",path:te,result:Re,schema:"legacy",inactive:!0,target:he}),Xe.push(Wr("user",Re.errors.length>0?"fix-or-delete":"migrate")),Re.errors.length>0)be=!0}if(n(Q.projectConfigTarget)!==null){let Re=Jt(Q.projectConfigTarget);if(Re.errors.push(...j(Q.projectConfigPath,Q.projectScope)),Ie.push({scope:"Project",path:Si(Q.projectConfigPath),result:Re,schema:"rules",target:Q.projectConfigTarget}),Re.errors.length>0)be=!0;if(n(ye)!==null)xe=!0,Xe.push(Wr("project","cleanup"))}else if(n(ye)!==null){xe=!0,be=!0;let Re=oo(ye);Ie.push({scope:"Project",path:Si(ne),result:Re,schema:"legacy",inactive:!0,target:ye}),Xe.push(Wr("project",Re.errors.length>0?"fix-or-delete":"migrate"))}if(et?.result.errors.length)be=!0;if(Ie.length===0&&!et)return console.log(`
265
265
  No config files found. Using built-in rules only.`),0;for(let Re of Ie)if(Re.inactive)hh(Re.scope,Re.path,Re.result);else if(Re.result.errors.length>0)yh(Re.scope,Re.path,Re.result.errors);else{if(Re.schema==="rules"&&Lh(Re.target))console.log(`
266
266
  Added $schema to ${Re.scope.toLowerCase()} config.`);gh(Re.scope,Re.path,Re.result,Re.schema)}for(let Re of Xe)console.error(`
@@ -5906,5 +5906,5 @@ load().then((loaded) => {
5906
5906
  </body>
5907
5907
  </html>
5908
5908
  `;var Ad='<script id="ccsn-data" type="application/json">';function _d(P){return Dd.replace(Ad,()=>Ad+JSON.stringify({token:P}).replaceAll("<","\\u003c"))}var Zr="kenryu42/cc-safety-net",Xh=`https://github.com/${Zr}`,Ti=1e4,Qh=7,ey="The project draft directory changed; reload the draft before applying.",ty="audit settings are user scope only; remove the audit section from a project proposal";async function Fd(P,V={}){let z=xt({label:"gui",booleans:{noOpen:["--no-open"]}},P),Q=V.log??console.log,te=V.error??console.error;if(z.errors.length>0){for(let ce of z.errors)te(ce);return te("Usage: cc-safety-net gui [--no-open]"),1}let ne=await ny(c,V);if(Q(`CC Safety Net policy GUI: ${ne.url}`),!z.flags.noOpen)try{await(V.openBrowser??fy)(ne.url)}catch(ce){te(`Failed to open browser: ${ce instanceof Error?ce.message:String(ce)}`),te(`Open this URL manually: ${ne.url}`)}if(V.keepAlive===!1)return await ne.close(),0;return await py(ne),0}async function ny(P,V={}){let z=Wh(24).toString("base64url"),Q={dir:null,revision:0},te=Yh((he,ye)=>{ry(P,he,ye,z,V,Q)});await new Promise((he,ye)=>{te.once("error",ye),te.listen(0,"127.0.0.1",()=>{te.off("error",ye),he()})});let ce=`http://127.0.0.1:${te.address().port}`;return{origin:ce,token:z,url:`${ce}/?token=${encodeURIComponent(z)}`,close:()=>uy(te)}}async function ry(P,V,z,Q,te,ne){let ce=P(),he=new URL(V.url??"/","http://127.0.0.1");if(V.method==="GET"&&he.pathname==="/favicon.ico"){z.writeHead(204,{"cache-control":"no-store"}),z.end();return}if(!ly(V,he,Q)){ht(z,403,{error:"Forbidden"});return}if(V.method==="GET"&&he.pathname==="/"){dy(z,_d(Q));return}if(V.method==="GET"&&he.pathname==="/api/policy"){let ye=_c(ce,te),be=E(ce,Ai(te));ht(z,200,{...ye,configState:Ne(be),...be.policyScopes?{projectPolicy:{path:b(te.cwd??process.cwd()),weakenings:be.policyScopes.weakenings}}:{},destructiveCommandRules:U,secretPatterns:Ke,version:wt(),preview:ye.errors.length>0?null:Ae(ye.policy,ce.env)});return}if(V.method==="POST"&&he.pathname==="/api/policy/preview"){let ye=await Kn(V);if(!ye.ok){ht(z,ye.status,{errors:[ye.error]});return}let be=Tc(ce,ye.value);ht(z,be.errors.length>0?400:200,be);return}if(V.method==="POST"&&he.pathname==="/api/policy/explain"){let ye=await Kn(V);if(!ye.ok){ht(z,ye.status,{errors:[ye.error]});return}let be=ye.value;if(be===null||typeof be.command!=="string"){ht(z,400,{errors:["command must be a string"]});return}let xe=qn(be.policy,ce.home);if(xe.length>0){ht(z,400,{errors:xe});return}ht(z,200,sy(ce,be.command,be.policy,te));return}if(V.method==="POST"&&he.pathname==="/api/policy"){let ye=await Kn(V);if(!ye.ok){ht(z,ye.status,{errors:[ye.error]});return}let be=Vt(ce,ye.value,te);ht(z,be.errors.length>0?400:200,be);return}if(V.method==="POST"&&he.pathname==="/api/reset"){ht(z,200,Vt(ce,Z,te));return}if(V.method==="POST"&&he.pathname==="/api/repair"){ht(z,200,$c(ce,te));return}if(V.method==="POST"&&he.pathname==="/api/policy/project/choose-directory"){let ye=await(te.chooseDirectory??Di)();if("path"in ye)ne.dir=ye.path,ne.revision+=1;ht(z,200,{cancelled:"cancelled"in ye,..."error"in ye?{error:ye.error}:{}});return}if(V.method==="GET"&&he.pathname==="/api/policy/project"){let ye=jd(ne,te),be=Td(ye,ce.home),xe=Vn(ce,te);ht(z,200,{path:b(ye),revision:ne.revision,baseline:xe.baseline,userPolicyDiagnostics:xe.diagnostics,projection:be.projection,projectionDiagnostics:be.diagnostics,canPickDirectory:Ei(process.platform,process.env)});return}if(V.method==="POST"&&he.pathname==="/api/policy/project/diff"){let ye=await $d(ce,V,z,ne,te);if(!ye)return;let be=Td(ye.dir,ce.home),xe=Vn(ce,te).baseline,Ie=Y(xe,ae(ye.proposal,ce.home).policy);ht(z,200,{rows:jr(Y(xe,be.projection).policy,Ie.policy,!1),weakenings:Ie.weakenings,existingFileDiagnostics:be.diagnostics});return}if(V.method==="POST"&&he.pathname==="/api/policy/project/apply"){let ye=await $d(ce,V,z,ne,te);if(!ye)return;let be=iy(ye.dir,ye.proposal,ce.home);ht(z,be.errors.length>0?500:200,be);return}if(V.method==="GET"&&he.pathname==="/api/activity"){let ye=ee(ce,te),be=ay(he.searchParams.get("days"),ye);if(be===null){ht(z,400,{error:`days must be an integer between 1 and ${ye}`});return}ht(z,200,Sd(ce,be,te.activityLogsDir));return}if(V.method==="POST"&&he.pathname==="/api/rules/choose-directory"){ht(z,200,await Di());return}if(V.method==="GET"&&he.pathname==="/api/rules"){let ye=J(ce,Ai(te)),be=new Map(ye.rules.map((xe)=>[xe.name,xe]));ht(z,200,{projectPath:te.cwd??process.cwd(),canPickDirectory:Ei(process.platform,process.env),rulebooks:ye.rulebooks.map((xe)=>({source:xe.source,spec:xe.spec,name:xe.name,version:xe.version,rules:xe.rules.flatMap((Ie)=>{let Xe=be.get(Ie);if(!Xe)return[];return[{name:Xe.name,command:Xe.command,subcommand:Xe.subcommand,block_args:Xe.block_args,reason:Xe.reason}]})})),errors:ye.errors,warnings:ye.warnings});return}if(V.method==="GET"&&he.pathname==="/api/star/context"){ht(z,200,await(te.fetchStarContext??(()=>by(ce,{logsDir:te.activityLogsDir})))());return}if(V.method==="POST"&&he.pathname==="/api/star"){let ye=await(te.starRepo??my)();ht(z,200,ye.ok?{ok:!0}:{ok:!1,fallbackUrl:Xh});return}if(V.method==="GET"&&he.pathname==="/api/integrations"){ht(z,200,await(te.fetchIntegrations??(()=>gy(ce)))());return}if(V.method==="GET"&&he.pathname==="/api/health"){ht(z,200,await(te.fetchHealth??yy)());return}if(V.method==="POST"&&(he.pathname==="/api/install"||he.pathname==="/api/uninstall")){let ye=await Kn(V);if(!ye.ok){ht(z,ye.status,{errors:[ye.error]});return}let be=ye.value?.target;if(typeof be!=="string"||!Mt.some((Ie)=>Ie.target===be)){ht(z,400,{error:"unknown target"});return}let xe=he.pathname==="/api/install"?"install":"uninstall";ht(z,200,await(te.runIntegration??vy)(xe,be));return}ht(z,404,{error:"Not found"})}function Ai(P){return{...P,cwd:P.cwd??process.cwd()}}function jd(P,V){return P.dir??V.cwd??process.cwd()}function Td(P,V){let z=b(P),Q=Kh(z)?dn(z):{value:void 0,errors:[]},te=ae(Q.value,V);return{projection:te.policy,diagnostics:[...Q.errors,...te.diagnostics]}}async function $d(P,V,z,Q,te){let ne=jd(Q,te),ce=Q.revision,he=await Kn(V);if(!he.ok)return ht(z,he.status,{errors:[he.error]}),null;let ye=he.value;if(typeof ye?.revision!=="number")return ht(z,400,{errors:["revision must be a number"]}),null;if(ye.revision!==ce)return ht(z,409,{errors:[ey]}),null;let be=oy(ye.proposal,P.home);if(be.length>0)return ht(z,400,{errors:be}),null;return{dir:ne,proposal:ye.proposal}}function oy(P,V){let z=qn(P,V);if(z.length>0)return z;return P?.audit===void 0?[]:[ty]}function iy(P,V,z){let Q=b(P),te=Nr(V,C(V,z));try{return g(i(v(P,"project policy"),Q),`${JSON.stringify(te,null,2)}
5909
- `),{path:Q,errors:[]}}catch(ne){return{path:Q,errors:[ne instanceof Error?ne.message:String(ne)]}}}function sy(P,V,z,Q){let te=C(z,P.home),ne=E(P,Ai(Q)),ce=Ee({rules:ne.policy.rules,transparentWrappers:ne.policy.transparentWrappers,safety:De(te.safety),worktreeMode:te.workflow.worktree_mode,destructiveCommandProtectionEnabled:te.destructive_command_protection.enabled,destructiveCommandRuleOverrides:te.destructive_command_protection.overrides,destructiveCommandAllowPaths:te.destructive_command_protection.allow_paths,secretProtection:{enabled:te.secret_protection.enabled,disabledRules:Oe(te.secret_protection.overrides),denyPaths:te.secret_protection.deny_paths,allowPaths:te.secret_protection.allow_paths}});return Nn(V,{policySnapshot:ce,cwd:Q.cwd,userConfigDir:Q.userConfigDir},P)}function ay(P,V){if(P===null)return Math.min(Qh,V);let z=Number(P);if(!Number.isInteger(z)||z<1||z>V)return null;return z}function ly(P,V,z){if(V.searchParams.get("token")!==z)return!1;if(P.method!=="POST")return!0;return P.headers["x-cc-safety-net-token"]===z}var cy=1048576;async function Kn(P){let V=[],z=0;for await(let Q of P){let te=Q;if(z+=te.byteLength,z>cy)return{ok:!1,status:413,error:"Request body is too large"};V.push(te)}try{return{ok:!0,value:JSON.parse(Buffer.concat(V).toString("utf-8")||"{}")}}catch(Q){return{ok:!1,status:400,error:`Invalid JSON: ${Q instanceof Error?Q.message:String(Q)}`}}}function dy(P,V){P.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),P.end(V)}function ht(P,V,z){P.writeHead(V,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),P.end(JSON.stringify(z))}function uy(P){return new Promise((V,z)=>{P.close((Q)=>Q?z(Q):V())})}function py(P){return new Promise((V)=>{let z=()=>{process.off("SIGINT",Q),process.off("SIGTERM",Q)},Q=()=>{z(),P.close().then(V)};process.once("SIGINT",Q),process.once("SIGTERM",Q)})}function fy(P){let V=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",z=process.platform==="win32"?["/c","start","",P]:[P];return new Promise((Q,te)=>{let ne=Od(V,z,{detached:!0,stdio:"ignore"}),ce=(ye)=>{ne.off("spawn",he),te(ye)},he=()=>{ne.off("error",ce),ne.unref(),Q()};ne.once("error",ce),ne.once("spawn",he)})}async function my(P="gh",V=Ti){return{ok:await _i(P,["api","-X","PUT",`/user/starred/${Zr}`],V)===0}}async function gy(P,V={}){let z=await sr(V.fetcher),Q=hy(P,z);return{targets:$t.map((te)=>{let ne=Q.find((ce)=>ce.platform===te.id);return{target:te.id,label:bt(te.id),version:z.versions[te.id]??null,status:ne?.configured?"active":ne?.detected?"disabled":ne?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:z.version,nodeVersion:z.nodeVersion,platform:z.platform}}}function hy(P,V){return Ln(P,process.cwd(),{ampPluginListOutput:V.ampPluginListOutput,codexPluginListOutput:V.codexPluginListOutput,copilotCliVersion:V.versions["copilot-cli"]})}async function yy(P={}){let V=await(P.checkUpdates??Wt)();return{update:{latestVersion:V.latestVersion??null,updateAvailable:V.updateAvailable}}}var Id=Promise.resolve();function vy(P,V,z={}){let Q=async()=>{let ne=[],{log:ce,error:he}=console;console.log=(...ye)=>ne.push(ye.map(String).join(" ")),console.error=console.log;try{return{ok:await Bn(P,[],{selectTargets:async()=>[V],output:new Zh({write(be,xe,Ie){ne.push(String(be).replace(/\n$/,"")),Ie()}}),...z})===0,output:ne.join(`
5909
+ `),{path:Q,errors:[]}}catch(ne){return{path:Q,errors:[ne instanceof Error?ne.message:String(ne)]}}}function sy(P,V,z,Q){let te=C(z,P.home),ne=E(P,Ai(Q)),ce=Ee({rules:ne.policy.rules,transparentWrappers:ne.policy.transparentWrappers,safety:De(te.safety),worktreeMode:te.workflow.worktree_mode,destructiveCommandProtectionEnabled:te.destructive_command_protection.enabled,destructiveCommandRuleOverrides:te.destructive_command_protection.overrides,destructiveCommandAllowPaths:te.destructive_command_protection.allow_paths,secretProtection:{enabled:te.secret_protection.enabled,disabledRules:Oe(te.secret_protection.overrides),denyPaths:te.secret_protection.deny_paths,allowPaths:te.secret_protection.allow_paths}});return Nn(V,{policySnapshot:ce,cwd:Q.cwd,userConfigDir:Q.userConfigDir},P)}function ay(P,V){if(P===null)return Math.min(Qh,V);let z=Number(P);if(!Number.isInteger(z)||z<1||z>V)return null;return z}function ly(P,V,z){if(V.searchParams.get("token")!==z)return!1;if(P.method!=="POST")return!0;return P.headers["x-cc-safety-net-token"]===z}var cy=1048576;async function Kn(P){let V=[],z=0;for await(let Q of P){let te=Q;if(z+=te.byteLength,z>cy)return{ok:!1,status:413,error:"Request body is too large"};V.push(te)}try{return{ok:!0,value:JSON.parse(Buffer.concat(V).toString("utf-8")||"{}")}}catch(Q){return{ok:!1,status:400,error:`Invalid JSON: ${Q instanceof Error?Q.message:String(Q)}`}}}function dy(P,V){P.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),P.end(V)}function ht(P,V,z){P.writeHead(V,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),P.end(JSON.stringify(z))}function uy(P){return new Promise((V,z)=>{P.close((Q)=>Q?z(Q):V())})}function py(P){return new Promise((V)=>{let z=()=>{process.off("SIGINT",Q),process.off("SIGTERM",Q)},Q=()=>{z(),P.close().then(V)};process.once("SIGINT",Q),process.once("SIGTERM",Q)})}function fy(P){let V=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",z=process.platform==="win32"?["/c","start","",P]:[P];return new Promise((Q,te)=>{let ne=Od(V,z,{detached:!0,stdio:"ignore"}),ce=(ye)=>{ne.off("spawn",he),te(ye)},he=()=>{ne.off("error",ce),ne.unref(),Q()};ne.once("error",ce),ne.once("spawn",he)})}async function my(P="gh",V=Ti){return{ok:await _i(P,["api","-X","PUT",`/user/starred/${Zr}`],V)===0}}async function gy(P,V={}){let z=await sr(V.fetcher),Q=hy(P,z);return{targets:$t.map((te)=>{let ne=Q.find((ce)=>ce.platform===te.id);return{target:te.id,label:vt(te.id),version:z.versions[te.id]??null,status:ne?.configured?"active":ne?.detected?"disabled":ne?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:z.version,nodeVersion:z.nodeVersion,platform:z.platform}}}function hy(P,V){return Ln(P,process.cwd(),{ampPluginListOutput:V.ampPluginListOutput,codexPluginListOutput:V.codexPluginListOutput,copilotCliVersion:V.versions["copilot-cli"]})}async function yy(P={}){let V=await(P.checkUpdates??Wt)();return{update:{latestVersion:V.latestVersion??null,updateAvailable:V.updateAvailable}}}var Id=Promise.resolve();function vy(P,V,z={}){let Q=async()=>{let ne=[],{log:ce,error:he}=console;console.log=(...ye)=>ne.push(ye.map(String).join(" ")),console.error=console.log;try{return{ok:await Bn(P,[],{selectTargets:async()=>[V],output:new Zh({write(be,xe,Ie){ne.push(String(be).replace(/\n$/,"")),Ie()}}),...z})===0,output:ne.join(`
5910
5910
  `)}}finally{console.log=ce,console.error=he}},te=Id.then(Q);return Id=te.then(()=>{return},()=>{return}),te}async function by(P,V={}){let[z,Q,te]=await Promise.all([Ly(V.command),wy(V.fetchRepo),Promise.resolve(tr(P,ee(P),V.logsDir).totalBlocked)]);return{starred:z,starCount:Q,blockedTotal:te}}async function Ly(P="gh",V=Ti){if(await _i(P,["auth","status"],V)!==0)return null;let z=await _i(P,["api",`/user/starred/${Zr}`],V);if(z===0)return!0;if(z===null)return null;return!1}function _i(P,V,z){return new Promise((Q)=>{let te=Od(P,V,{stdio:"ignore",windowsHide:!0}),ne=!1,ce=setTimeout(()=>{te.kill(),he(null)},z),he=(ye)=>{if(ne)return;ne=!0,clearTimeout(ce),Q(ye)};te.once("error",()=>he(null)),te.once("close",he)})}async function wy(P=fetch){try{let V=await P(`https://api.github.com/repos/${Zr}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Ti)});if(!V.ok)return null;let z=await V.json();return typeof z.stargazers_count==="number"?z.stargazers_count:null}catch{return null}}function ky(P){if(P[0]!=="help")return!1;let V=P[1];if(!V)ti(),process.exit(0);if(Mn(V))process.exit(0);console.error(`Unknown command: ${V}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var xy={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),Mn("hook",console.error),process.exit(1)},install:async(P)=>{process.exit(await Bn("install",P))},update:async(P)=>{process.exit(await hi(P))},uninstall:async(P)=>{process.exit(await Bn("uninstall",P))},rule:async(P)=>{process.exit(await kd(c(),P))},policy:async(P)=>{process.exit(await jc(c(),P))},status:async(P)=>{if(Ht(xt({label:"status"},P).errors))process.exit(1);Cd(c())},statusline:async(P)=>{let V=xt({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},P);if(V.errors.length===0&&V.flags.claudeCode){await Pi(c());return}if(Ht(V.errors),!V.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");Mn("statusline",console.error),process.exit(1)},doctor:async(P)=>{let V=Jo(P);if(!V)process.exit(1);let z=await cl(c(),{json:V.json,skipUpdateCheck:V.skipUpdateCheck});process.exit(z)},logs:async(P)=>{process.exit(await Hi(c(),P))},gui:async(P)=>{process.exit(await Fd(P))},explain:async(P)=>{process.exit(await Ll(c(),P))}};async function Cy(P){let V=xt({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},P);if(ky(P))return;let z=P[0],Q=z?er(z):void 0;if(V.help&&Q&&Q.name!=="rule")Mn(Q.name),process.exit(0);if(!z||V.help&&!Q)ti(),process.exit(0);if(V.flags.version)xl(),process.exit(0);if(Q){await xy[Q.name](P.slice(1));return}if(z==="--statusline"){await Pi(c());return}console.error(z.startsWith("-")?`Unknown option: ${z}`:`Unknown command: ${z}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Cy as runCli};