cc-safety-net 2.6.13 → 2.6.15

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,7 +1,7 @@
1
- import{a,s,Me,nt,T,bt,rt,c,n,ot,P,S,me,vt,m,Ie,x,st,l,o,w,i,ae,r,g,he,B,wt,Ct,p,ye,be,Et,M,X,ce,C,kt,I,h,Ae,z,u,O,Q,at,ct,F,E,D,xe,ve,$e,le,d,e,Ue,Oe,je,Se,lt,ut,ue,De,de,Ge,ee,V,He,we,q,dt,K,te,ne,pe,pt,ft,k,A,We,mt,ze,R,Ve,Ne,qe,y,t,re,Ce,b,U,v,N,Rt,Ke,Je,f,j}from"./chunks/index-rdxjms22.js";import{Qe}from"./chunks/index-e25d8rb4.js";import{Ye,ke}from"./chunks/index-ry0wwdk0.js";import{et}from"./chunks/index-z5fwe2yq.js";import"./chunks/index-q29jqk43.js";import{ie,J,tt,H,W}from"./chunks/index-x95aj0ja.js";var cf=["-h","--help"];function mn(_,L){let G=Object.entries(_.booleans??{}),Y=Object.entries(_.values??{}),Z=Object.entries(_.lists??{}),oe=Object.fromEntries(G.map(([Le])=>[Le,!1])),se={},fe=Object.fromEntries(Z.map(([Le])=>[Le,[]])),ge=[],Pe=[],Ee=!1,Re=-1;for(let[Le,_e]of L.entries()){if(Le<=Re)continue;if(_e==="--"){ge.push(...L.slice(Le+1));break}if(cf.includes(_e)){Ee=!0;continue}let Te=G.find(([,Ze])=>Ze.includes(_e));if(Te){oe[Te[0]]=!0;continue}let Be=Y.find(([,Ze])=>Ze.includes(_e));if(Be){let Ze=L[Le+1];if(Ze===void 0||Ze.startsWith("-")){Pe.push(`${_e} requires a value`);continue}se[Be[0]]=Ze,Re=Le+1;continue}let Fe=Z.find(([,Ze])=>Ze.includes(_e));if(Fe){let Ze=L.slice(Le+1),tn=Ze.findIndex((an)=>an.startsWith("-")),on=Ze.slice(0,tn===-1?Ze.length:tn);if(on.length===0){Pe.push(`${_e} requires at least one value`);continue}fe[Fe[0]]=[...fe[Fe[0]]??[],...on],Re=Le+on.length;continue}if(_e.startsWith("-")){Pe.push(`Unknown option for ${_.label}: ${_e}`);continue}if(_.positionals==="tail"){ge.push(...L.slice(Le));break}ge.push(_e)}if(_.positionals!=="list"&&_.positionals!=="tail")Pe.push(...ge.map((Le)=>`Unexpected argument for ${_.label}: ${Le}`));return{flags:oe,values:se,lists:fe,positionals:ge,help:Ee,errors:Pe}}function $n(_){for(let L of _)console.error(L);return _.length>0}import{readdirSync as yf,statSync as Ys,unlinkSync as hf}from"node:fs";import{basename as Zs,dirname as vf,isAbsolute as bf,join as wf,relative as kf,resolve as Cf,sep as xf}from"node:path";var Js=(_)=>{let L=Date.now()-new Date(_).getTime();if(!Number.isFinite(L))return"";let G=Math.floor(L/60000),Y=Math.floor(G/60),Z=Math.floor(Y/24);if(Z>0)return`${Z}d ago`;if(Y>0)return`${Y}h ago`;if(G>0)return`${G}m ago`;return"just now"},Go=(_)=>{let L=(_??"").trim().split(/\s+/).filter((Z)=>Z&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(Z)),G=L[0]?.split("/").pop();if(!G)return null;let Y=L[1];return Y&&/^[a-z][a-z0-9-]*$/.test(Y)?`${G} ${Y}`:G};function Ws(_){let L=(Z)=>`${Z.sessionId}
1
+ import{a,s,Me,nt,T,bt,rt,c,n,ot,P,S,me,vt,m,Ie,v,st,l,o,w,i,ae,r,h,he,B,wt,Ct,p,ye,be,Et,M,X,ce,C,kt,I,y,Ae,z,u,O,Q,at,ct,F,E,D,xe,ve,$e,le,d,e,Ue,Oe,je,Se,lt,ut,ue,De,de,Ge,ee,V,He,we,q,dt,K,te,ne,pe,pt,ft,k,A,We,mt,ze,R,Ve,Ne,qe,b,t,re,Ce,x,U,g,N,Rt,Ke,Je,f,j}from"./chunks/index-qzcqzqbd.js";import{Qe}from"./chunks/index-c58ybc95.js";import{Ye,ke}from"./chunks/index-7s7deste.js";import{et}from"./chunks/index-sxp3v148.js";import"./chunks/index-n7t37q7p.js";import{ie,J,tt,H,W}from"./chunks/index-e3xkx678.js";var cf=["-h","--help"];function mn(_,L){let G=Object.entries(_.booleans??{}),Y=Object.entries(_.values??{}),Z=Object.entries(_.lists??{}),oe=Object.fromEntries(G.map(([Le])=>[Le,!1])),se={},fe=Object.fromEntries(Z.map(([Le])=>[Le,[]])),ge=[],Pe=[],Ee=!1,Re=-1;for(let[Le,_e]of L.entries()){if(Le<=Re)continue;if(_e==="--"){ge.push(...L.slice(Le+1));break}if(cf.includes(_e)){Ee=!0;continue}let Te=G.find(([,Ze])=>Ze.includes(_e));if(Te){oe[Te[0]]=!0;continue}let Be=Y.find(([,Ze])=>Ze.includes(_e));if(Be){let Ze=L[Le+1];if(Ze===void 0||Ze.startsWith("-")){Pe.push(`${_e} requires a value`);continue}se[Be[0]]=Ze,Re=Le+1;continue}let Fe=Z.find(([,Ze])=>Ze.includes(_e));if(Fe){let Ze=L.slice(Le+1),tn=Ze.findIndex((an)=>an.startsWith("-")),on=Ze.slice(0,tn===-1?Ze.length:tn);if(on.length===0){Pe.push(`${_e} requires at least one value`);continue}fe[Fe[0]]=[...fe[Fe[0]]??[],...on],Re=Le+on.length;continue}if(_e.startsWith("-")){Pe.push(`Unknown option for ${_.label}: ${_e}`);continue}if(_.positionals==="tail"){ge.push(...L.slice(Le));break}ge.push(_e)}if(_.positionals!=="list"&&_.positionals!=="tail")Pe.push(...ge.map((Le)=>`Unexpected argument for ${_.label}: ${Le}`));return{flags:oe,values:se,lists:fe,positionals:ge,help:Ee,errors:Pe}}function $n(_){for(let L of _)console.error(L);return _.length>0}import{readdirSync as yf,statSync as Ys,unlinkSync as hf}from"node:fs";import{basename as Zs,dirname as vf,isAbsolute as bf,join as wf,relative as kf,resolve as Cf,sep as xf}from"node:path";var Js=(_)=>{let L=Date.now()-new Date(_).getTime();if(!Number.isFinite(L))return"";let G=Math.floor(L/60000),Y=Math.floor(G/60),Z=Math.floor(Y/24);if(Z>0)return`${Z}d ago`;if(Y>0)return`${Y}h ago`;if(G>0)return`${G}m ago`;return"just now"},Go=(_)=>{let L=(_??"").trim().split(/\s+/).filter((Z)=>Z&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(Z)),G=L[0]?.split("/").pop();if(!G)return null;let Y=L[1];return Y&&/^[a-z][a-z0-9-]*$/.test(Y)?`${G} ${Y}`:G};function Ws(_){let L=(Z)=>`${Z.sessionId}
2
2
  ${Go(Z.segment||Z.command)}`,G=_.filter((Z)=>Z.decision!=="allow"),Y=G.filter((Z)=>Z.sessionId).reduce((Z,oe)=>Z.set(L(oe),(Z.get(L(oe))??0)+1),new Map);return new Set(G.filter((Z)=>Z.failureStage||(Y.get(L(Z))??0)>=2))}import{existsSync as df,readdirSync as uf,readFileSync as pf}from"node:fs";import{join as ff}from"node:path";function Yn(_,L){try{return uf(_,{withFileTypes:!0,encoding:"utf8"}).flatMap((G)=>{let Y=ff(_,G.name);if(G.isDirectory())return Yn(Y,L);if(G.name.endsWith(".jsonl"))return[Y];return[]})}catch{if(L&&df(_))L.count++;return[]}}var mf=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function gf(_){if(!_||typeof _!=="object"||Array.isArray(_))return!1;let L=_;if(typeof L.ts!=="string"||typeof L.command!=="string")return!1;return mf.every((G)=>L[G]===void 0||typeof L[G]==="string")}function Dt(_,L){try{return pf(_,"utf-8").split(`
3
3
  `).filter(Boolean).flatMap((G)=>{try{let Y=JSON.parse(G);if(!gf(Y)){if(L)L.count++;return[]}return[Y]}catch{if(L)L.count++;return[]}})}catch{if(L)L.count++;return[]}}function gn(_){return Array.from(_,(L)=>{let G=L.charCodeAt(0);if(G<=31||G>=127&&G<=159)return`\\x${G.toString(16).padStart(2,"0")}`;return L}).join("")}function Sf(_,L){let G=ie(_),Y=mn({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"]}},L);if($n(Y.errors))return null;if(Y.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(Y.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let Z=Y.values.limit===void 0?20:zs(Y.values.limit);if(Z===null)return console.error("--limit must be a positive number"),null;let oe=Y.values.since===void 0?Math.min(30,G):zs(Y.values.since);if(oe===null||oe>G)return console.error(`--since must be a positive number of days no greater than ${G}`),null;let se={limit:Z,limitExplicit:Y.values.limit!==void 0,since:oe,sinceExplicit:Y.values.since!==void 0,all:Y.flags.all,json:Y.flags.json,suspect:Y.flags.suspect,pruneLegacy:Y.flags.pruneLegacy,dryRun:Y.flags.dryRun,id:Y.values.id,agent:Y.values.agent,rule:Y.values.rule,session:Y.values.session,project:Y.values.project===void 0?void 0:Cf(Y.values.project)};if(se.id&&(se.agent!==void 0||se.rule!==void 0||se.session!==void 0||se.project!==void 0||se.suspect||se.sinceExplicit||se.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(se.pruneLegacy&&(se.id!==void 0||se.agent!==void 0||se.rule!==void 0||se.session!==void 0||se.project!==void 0||se.suspect||se.all||se.sinceExplicit||se.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(se.dryRun&&!se.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return se}async function Xs(_,L,G={}){let Y=Sf(_,L);if(!Y)return 1;let Z=G.logsDir??H(_);if(Y.pruneLegacy)return Pf(Z,Y.json,Y.dryRun);if(!Z)return console.log(Y.json?"[]":Y.id?`No retained audit log entry found for id ${gn(Y.id)}.`:"No audit log entries found."),0;J(_,Z);let oe={count:0},se=Yn(Z,oe).flatMap((Re)=>Dt(Re,oe).map((Le)=>({entry:Le,file:Re})));if(oe.count>0)console.error(`warning: ${oe.count} audit log ${oe.count===1?"source":"sources"} could not be read; these results are incomplete`);if(Y.id)return Tf(se,Y,G.timeZone);let fe=Date.now()-Y.since*24*60*60*1000,ge=se.filter((Re)=>If(Re,Y,Z,fe)),Pe=Y.suspect?Ws(ge.map((Re)=>Re.entry)):null,Ee=(Pe?ge.filter((Re)=>Pe.has(Re.entry)):ge).sort((Re,Le)=>Date.parse(Le.entry.ts)-Date.parse(Re.entry.ts)).slice(0,Y.limit);if(Y.json)return console.log(JSON.stringify(Ee.map((Re)=>Re.entry),null,2)),0;if(Ee.length===0)return console.log("No audit log entries found."),0;for(let Re of Ee)console.log($f(Re.entry,G.timeZone));return 0}function Pf(_,L,G){let Y=_?Rf(_).map((fe)=>wf(_,fe)):[];if(G)return Ef(Y,L);let Z=[],oe=0,se=0;for(let fe of Y){let ge=Ys(fe,{throwIfNoEntry:!1})?.size??0,Pe=_f(fe);if(Pe){Z.push(`${Zs(fe)}: ${Pe}`);continue}oe++,se+=ge}if(L)return console.log(JSON.stringify({removedFiles:oe,removedBytes:se,failedFiles:Z.length})),Z.length===0?0:1;console.log(oe===0&&Z.length===0?"No legacy audit log files found.":`Removed ${oe} legacy audit log ${oe===1?"file":"files"} (${Qs(se)}).`);for(let fe of Z)console.error(`Could not remove ${gn(fe)}`);if(console.log("Nested v2 audit logs were not changed."),oe>0)console.log("This deletion cannot be undone.");return Z.length===0?0:1}function Ef(_,L){let G=_.reduce((Y,Z)=>Y+(Ys(Z,{throwIfNoEntry:!1})?.size??0),0);if(L)return console.log(JSON.stringify({dryRun:!0,files:_.length,bytes:G})),0;if(console.log(_.length===0?"No legacy audit log files found.":`Would remove ${_.length} legacy audit log ${_.length===1?"file":"files"} (${Qs(G)}).`),console.log("Nested v2 audit logs are not included."),_.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Rf(_){try{return yf(_,{withFileTypes:!0}).filter((L)=>L.isFile()&&L.name.endsWith(".jsonl")).map((L)=>L.name)}catch{return[]}}function _f(_){try{return hf(_),null}catch(L){return L instanceof Error?L.message:String(L)}}function Qs(_){let L=["B","KiB","MiB","GiB"],G=Math.min(Math.floor(Math.log2(Math.max(_,1))/10),L.length-1);return`${Math.round(_/1024**G*10)/10} ${L[G]}`}function Tf(_,L,G){let Y=_.filter((oe)=>oe.entry.id===L.id);if(Y.length>1)return console.error(`Multiple audit log entries found for id ${gn(L.id??"")}.`),1;if(L.json)return console.log(JSON.stringify(Y.map((oe)=>oe.entry),null,2)),0;let Z=Y[0];if(!Z)return console.log(`No retained audit log entry found for id ${gn(L.id??"")}.`),0;return console.log(Df(Z.entry,G)),0}function If(_,L,G,Y){if(!L.all&&_.entry.decision==="allow")return!1;if(Date.parse(_.entry.ts)<Y)return!1;if(L.agent!==void 0&&_.entry.agent!==L.agent)return!1;if(L.rule!==void 0&&_.entry.ruleId!==L.rule)return!1;if(L.session!==void 0&&!Af(_,G,L.session))return!1;if(L.project!==void 0&&!Of(_.entry.cwd,L.project))return!1;return!0}function Af(_,L,G){if(_.entry.sessionId===G)return!0;return vf(_.file)===L&&Zs(_.file,".jsonl")===G}function Of(_,L){if(!_)return!1;let G=kf(L,_);return G!==".."&&!G.startsWith(`..${xf}`)&&!bf(G)}function $f(_,L){let G=gn(_.id??"-"),Y=gn(_.decision??"deny"),Z=_.cwd?` [${gn(_.cwd)}]`:"",oe=_.segment||_.command,se=oe===_.command?"":"↳ ",fe=oe.length>50?`${oe.slice(0,50)}…`:oe;return`${G.padEnd(16)} ${gn(ea(_.ts,L))} ${Y.padEnd(5)} ${gn(_.agent??"-").padEnd(15)} ${gn(_.ruleId??"-").padEnd(20)} ${se}${gn(fe)}${Z}`}function Df(_,L){let G=(Z)=>gn(Z===void 0||Z===null||Z===""?"-":Z),Y=_.shape?`${_.agent??"-"} (shape: ${_.shape})`:_.agent??"-";return[`id: ${G(_.id)}`,`ts: ${G(ea(_.ts,L))}`,`decision: ${G(_.decision)}`,`agent: ${G(Y)}`,`level: ${G(_.level)}`,`tool: ${G(_.toolName)}`,`rule: ${G(_.ruleId)}`,`intent: ${G(_.intent)}`,`stage: ${G(_.failureStage)}`,`error: ${G(_.errorCode)}`,`session: ${G(_.sessionId)}`,`cwd: ${G(_.cwd)}`,`version: ${G(_.v)}`,`truncated: ${G(_.truncated===!0?"yes":void 0)}`,`reason: ${G(_.reason)}`,`command: ${G(_.command)}`,`segment: ${G(_.segment)}`].join(`
4
- `)}function ea(_,L){let G=new Date(_);if(Number.isNaN(G.getTime()))return _;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:L}).format(G)}function zs(_){let L=Number(_);return Number.isFinite(L)&&L>0?L:null}var na={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 ta={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 ra={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 Bo=["npx","--offline","--no-install","@deepseek-ai/dsh","--version"],oa=["cursor-agent","--version"],ia=[{id:"antigravity-cli",displayName:"Antigravity CLI",runtime:{flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",runtime:{displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",runtime:{flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",runtime:{flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",runtime:{flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",runtime:{flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",runtime:{flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",runtime:{flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",install:{flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",install:{flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",install:{flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",runtime:{flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"deepseek-harness",displayName:"DeepSeek Harness",install:{flag:"--deepseek-harness",artifactKind:"package",probeCommand:Bo}},{id:"devin",displayName:"Devin CLI",runtime:{flags:["-dv","--devin"],description:"Run as Devin CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--devin",artifactKind:"hook config",probeCommand:["devin","--version"]}},{id:"droid",displayName:"Factory Droid",runtime:{flags:["-fd","--droid"],description:"Run as Factory Droid PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--droid",artifactKind:"hook config",probeCommand:["droid","--version"]}},{id:"amp",displayName:"Amp Code",install:{flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],qo=ia.slice().sort((_,L)=>_.displayName.localeCompare(L.displayName,"en")),Rr=qo.map((_)=>_.id).sort((_,L)=>Number(L==="claude-code")-Number(_==="claude-code")),Qt=qo.filter((_)=>("runtime"in _)).map((_)=>({id:_.id,displayName:"displayName"in _.runtime?_.runtime.displayName:_.displayName,flags:_.runtime.flags,legacyFlags:"legacyFlags"in _.runtime?_.runtime.legacyFlags:[],description:_.runtime.description,legacyTopLevelFlags:_.runtime.legacyTopLevelFlags})),En=qo.map((_)=>({id:_.id,..._.install})),Nf=Object.fromEntries(ia.map((_)=>[_.id,_.displayName]));function cn(_){return Nf[_]}var Lf=Qt.map((_)=>({flags:_.flags.join(", "),description:_.description})),jf=Qt.flatMap((_)=>_.flags.map((L)=>`cc-safety-net hook ${L}`)),sa={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Lf,{flags:"-h, --help",description:"Show this help"}],examples:jf};var aa={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...En.map((_)=>({flags:_.flag,description:`Install ${cn(_.id)} ${_.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...En.map((_)=>`cc-safety-net install ${_.flag}`)]},la={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...En.map((_)=>({flags:_.flag,description:`Uninstall ${cn(_.id)} ${_.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...En.map((_)=>`cc-safety-net uninstall ${_.flag}`)]},ca={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 da={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 _r={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 Vo=[{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"}],Ko=["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"],Nt={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:"tool add <name...> [--cwd-arg <name>] [--project]",description:"Analyze community shell tools (user scope by default)"},{usage:"tool remove <name...> [--project]",description:"Stop analyzing declared tools"},{usage:"tool list",description:"List declared command tools in both scopes"},{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"},{flags:"--project",description:"Use project-scope rule config with rule tool"},{flags:"--cwd-arg",argument:"<name>",description:"Name the working-directory argument with rule tool add"},...Vo.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","cc-safety-net rule tool add ops_bash","cc-safety-net rule tool add ops_run_background --cwd-arg cwd --project",...Ko,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var ua={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 pa={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 Tr=[ua,na,da,ta,Nt,_r,aa,ca,la,sa,ra,pa];function Hf(_){return _.aliases??[]}function Ir(_){let L=_.toLowerCase();return Tr.find((G)=>G.name.toLowerCase()===L||Hf(G).some((Y)=>Y.toLowerCase()===L))}import{existsSync as Ah}from"node:fs";import{basename as Ff}from"node:path";function Ar(_,L=7,G=H(_)){let Y=Date.now()-L*24*60*60*1000,Z=[],oe=new Set,se=0,fe,ge,Pe,Ee;if(G)J(_,G);let Re={count:0},Le=G?Yn(G,Re):[];for(let Te of Le)for(let Be of Dt(Te,Re)){if(Be.decision==="allow")continue;let Fe=new Date(Be.ts).getTime();if(Fe>=Y){if(se++,oe.add(Be.sessionId??Ff(Te,".jsonl")),ge===void 0||Fe<=ge)fe=Be.ts,ge=Fe;if(Ee===void 0||Fe>Ee)Pe=Be.ts,Ee=Fe;Mf(Z,Be,Fe)}}let _e=Z.map((Te)=>({timestamp:Te.ts,command:Te.command,reason:Te.reason,relativeTime:Js(new Date(Te.ts))}));return{totalBlocked:se,sessionCount:oe.size,recentEntries:_e,oldestEntry:fe,newestEntry:Pe,unreadable:Re.count}}function Mf(_,L,G){let Y=_.findIndex((Z)=>G>new Date(Z.ts).getTime());if(Y===-1){if(_.length<3)_.push(L);return}if(_.splice(Y,0,L),_.length>3)_.pop()}import{dirname as Xf}from"node:path";import{dirname as Uf,join as Gf,resolve as Bf}from"node:path";var qf="config.json";function bn(_,L,G,Y){g(Vf(_),`${JSON.stringify(L,null,2)}
4
+ `)}function ea(_,L){let G=new Date(_);if(Number.isNaN(G.getTime()))return _;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:L}).format(G)}function zs(_){let L=Number(_);return Number.isFinite(L)&&L>0?L:null}var na={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 ta={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 ra={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 Bo=["npx","--offline","--no-install","@deepseek-ai/dsh","--version"],oa=["cursor-agent","--version"],ia=[{id:"antigravity-cli",displayName:"Antigravity CLI",runtime:{flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",runtime:{displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",runtime:{flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",runtime:{flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",runtime:{flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",runtime:{flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",runtime:{flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",runtime:{flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",install:{flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",install:{flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",install:{flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",runtime:{flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"deepseek-harness",displayName:"DeepSeek Harness",install:{flag:"--deepseek-harness",artifactKind:"package",probeCommand:Bo}},{id:"devin",displayName:"Devin CLI",runtime:{flags:["-dv","--devin"],description:"Run as Devin CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--devin",artifactKind:"hook config",probeCommand:["devin","--version"]}},{id:"droid",displayName:"Factory Droid",runtime:{flags:["-fd","--droid"],description:"Run as Factory Droid PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--droid",artifactKind:"hook config",probeCommand:["droid","--version"]}},{id:"amp",displayName:"Amp Code",install:{flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],qo=ia.slice().sort((_,L)=>_.displayName.localeCompare(L.displayName,"en")),Rr=qo.map((_)=>_.id).sort((_,L)=>Number(L==="claude-code")-Number(_==="claude-code")),Qt=qo.filter((_)=>("runtime"in _)).map((_)=>({id:_.id,displayName:"displayName"in _.runtime?_.runtime.displayName:_.displayName,flags:_.runtime.flags,legacyFlags:"legacyFlags"in _.runtime?_.runtime.legacyFlags:[],description:_.runtime.description,legacyTopLevelFlags:_.runtime.legacyTopLevelFlags})),En=qo.map((_)=>({id:_.id,..._.install})),Nf=Object.fromEntries(ia.map((_)=>[_.id,_.displayName]));function cn(_){return Nf[_]}var Lf=Qt.map((_)=>({flags:_.flags.join(", "),description:_.description})),jf=Qt.flatMap((_)=>_.flags.map((L)=>`cc-safety-net hook ${L}`)),sa={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Lf,{flags:"-h, --help",description:"Show this help"}],examples:jf};var aa={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...En.map((_)=>({flags:_.flag,description:`Install ${cn(_.id)} ${_.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...En.map((_)=>`cc-safety-net install ${_.flag}`)]},la={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...En.map((_)=>({flags:_.flag,description:`Uninstall ${cn(_.id)} ${_.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...En.map((_)=>`cc-safety-net uninstall ${_.flag}`)]},ca={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 da={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 _r={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 Vo=[{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"}],Ko=["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"],Nt={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:"tool add <name...> [--cwd-arg <name>] [--project]",description:"Analyze community shell tools (user scope by default)"},{usage:"tool remove <name...> [--project]",description:"Stop analyzing declared tools"},{usage:"tool list",description:"List declared command tools in both scopes"},{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"},{flags:"--project",description:"Use project-scope rule config with rule tool"},{flags:"--cwd-arg",argument:"<name>",description:"Name the working-directory argument with rule tool add"},...Vo.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","cc-safety-net rule tool add ops_bash","cc-safety-net rule tool add ops_run_background --cwd-arg cwd --project",...Ko,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var ua={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 pa={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 Tr=[ua,na,da,ta,Nt,_r,aa,ca,la,sa,ra,pa];function Hf(_){return _.aliases??[]}function Ir(_){let L=_.toLowerCase();return Tr.find((G)=>G.name.toLowerCase()===L||Hf(G).some((Y)=>Y.toLowerCase()===L))}import{existsSync as Ah}from"node:fs";import{basename as Ff}from"node:path";function Ar(_,L=7,G=H(_)){let Y=Date.now()-L*24*60*60*1000,Z=[],oe=new Set,se=0,fe,ge,Pe,Ee;if(G)J(_,G);let Re={count:0},Le=G?Yn(G,Re):[];for(let Te of Le)for(let Be of Dt(Te,Re)){if(Be.decision==="allow")continue;let Fe=new Date(Be.ts).getTime();if(Fe>=Y){if(se++,oe.add(Be.sessionId??Ff(Te,".jsonl")),ge===void 0||Fe<=ge)fe=Be.ts,ge=Fe;if(Ee===void 0||Fe>Ee)Pe=Be.ts,Ee=Fe;Mf(Z,Be,Fe)}}let _e=Z.map((Te)=>({timestamp:Te.ts,command:Te.command,reason:Te.reason,relativeTime:Js(new Date(Te.ts))}));return{totalBlocked:se,sessionCount:oe.size,recentEntries:_e,oldestEntry:fe,newestEntry:Pe,unreadable:Re.count}}function Mf(_,L,G){let Y=_.findIndex((Z)=>G>new Date(Z.ts).getTime());if(Y===-1){if(_.length<3)_.push(L);return}if(_.splice(Y,0,L),_.length>3)_.pop()}import{dirname as Xf}from"node:path";import{dirname as Uf,join as Gf,resolve as Bf}from"node:path";var qf="config.json";function bn(_,L,G,Y){h(Vf(_),`${JSON.stringify(L,null,2)}
5
5
  `,G,Y)}function Vf(_){return typeof _==="string"?ae(_):_}function Wo(_){return{errors:ue(Jf(_),": "," "),ruleNames:new Set(Ge(_).map((L)=>L.toLowerCase()))}}var Kf="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",fa="must match pattern (letters, numbers, hyphens, underscores)";function Jf(_){if(!ma(_))return[e([],"Config must be an object")];return[..._.version===1?[]:[e(["version"],"must be 1")],...Wf(_.rules)]}function Wf(_){if(_===void 0)return[];if(!Array.isArray(_))return[e(["rules"],"must be an array")];return[..._.flatMap((L,G)=>ma(L)?zf(L,["rules",G]):[e(["rules",G],"must be an object")]),...Ue(_)]}function zf(_,L){return[...Jo(_.name,[...L,"name"],"required string",p,Kf),...Jo(_.command,[...L,"command"],"required string",E,fa),..._.subcommand===void 0?[]:Jo(_.subcommand,[...L,"subcommand"],"must be a string if provided",E,fa),...Yf(_.block_args,[...L,"block_args"]),...Zf(_.reason,[...L,"reason"]),..._.intent===void 0||De(_.intent)?[]:[e([...L,"intent"],Oe)]]}function Jo(_,L,G,Y,Z){if(typeof _!=="string")return[e(L,G)];return Y.test(_)?[]:[e(L,Z)]}function Yf(_,L){if(!Array.isArray(_))return[e(L,"required array")];if(_.length===0)return[e(L,"must have at least one element")];return _.flatMap((G,Y)=>{if(typeof G!=="string")return[e([...L,Y],"must be a string")];return G===""?[e([...L,Y],"must not be empty")]:[]})}function Zf(_,L){if(typeof _!=="string")return[e(L,"required string")];if(_==="")return[e(L,"must not be empty")];return _.length>D?[e(L,`must be at most ${D} characters`)]:[]}function ma(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}function zo(_){let L=ga(_);if(!L.ok)return L.result;return Wo(L.parsed)}function ga(_){let L=[],G=new Set;try{let Y=typeof _==="string"?ae(_):_,Z=r(Y);if(Z===null)return L.push(`File not found: ${Y.path}`),{ok:!1,result:{errors:L,ruleNames:G}};if(!Z.trim())return L.push("Config file is empty"),{ok:!1,result:{errors:L,ruleNames:G}};return{ok:!0,parsed:JSON.parse(Z)}}catch(Y){if(Y instanceof o)return L.push(Y.message),{ok:!1,result:{errors:L,ruleNames:G}};let Z=Y instanceof Error?Y.message:String(Y);return L.push(Y instanceof SyntaxError?"Invalid JSON":Z),{ok:!1,result:{errors:L,ruleNames:G}}}}function Lt(_){return Bf(_,".safety-net.json")}function Un(_){let L=ga(_);if(!L.ok)return L.result;let G=lt(L.parsed);return{errors:G.errors,ruleNames:G.sources}}function jt(_,L={}){return Gf(Uf(Ae(_,L)),qf)}function ya(_,L,G){let Y;try{if(r(L)===null)return{path:_,exists:!1,valid:!1,ruleCount:0};Y=Un(L),Y.errors.push(...V(_,G))}catch(Z){if(!(Z instanceof o))throw Z;Y={errors:[Z.message],ruleNames:new Set}}return{path:_,exists:!0,valid:Y.errors.length===0,ruleCount:Y.ruleNames.size,...Y.errors.length>0?{errors:Y.errors}:{}}}function Qf(_,L){return{source:L,name:_.name,command:_.command,subcommand:_.subcommand,blockArgs:[..._.block_args],reason:_.reason}}function ha(_,L){let G=z(_),Y=I(L),Z=Xf(G),oe=ee(_,{cwd:L,userConfigPath:G,projectConfigPath:Y,userConfigDir:Z}),se=Q(_,{cwd:L,userConfigPath:G,projectConfigPath:Y,userConfigDir:Z}),fe=new Map(oe.rulebooks.flatMap((ge)=>ge.rules.map((Pe)=>[Pe,ge.source])));return{userConfig:ya(G,se.userConfigTarget,se.userScope),projectConfig:ya(Y,se.projectConfigTarget,se.projectScope),effectiveRules:oe.rules.map((ge)=>Qf(ge,fe.get(ge.name)??"project"))}}var em=[{flag:n.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:n.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:n.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:n.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:n.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:n.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:n.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:n.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"},{flag:n.projectTightenOnly,description:"Ignore project policy settings that weaken the user policy",defaultBehavior:"off"}];function va(_){return[...em.map((L)=>({name:L.flag.name,value:me(L.flag,_.env),isSet:vt(L.flag,_.env),legacyName:L.flag.legacyName,legacyValue:L.flag.legacyName?_.env.get(L.flag.legacyName):void 0,legacyIsSet:L.flag.legacyName?_.env.get(L.flag.legacyName)!==void 0:void 0,description:L.description,defaultBehavior:L.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:_.env.get("CC_SAFETY_NET_HOME"),isSet:_.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ba={error:0,warning:1,info:2},nm=["policy","config","audit"];function tm(_){return _.map((L)=>{if(L==="ownership")return"is not owned by the current user";if(L==="permissions")return"has unsafe permissions";if(L==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var rm=[{derive:(_)=>_.hooks.length>0&&_.hooks.every((L)=>!L.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:(_)=>_.hooks.filter((L)=>L.inspectionStatus==="failed").map((L)=>{let G=cn(L.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${G} inspection failed`,detail:`Doctor could not verify the ${G} integration configuration.`,fixHint:`Correct the reported ${G} configuration error, then run \`cc-safety-net doctor\` again.`,integration:L.platform}})},{derive:(_)=>_.userConfig.exists&&!_.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:_.userConfig.path}]:[]},{derive:(_)=>_.projectConfig.exists&&!_.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:_.projectConfig.path}]:[]},{derive:(_)=>_.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${_.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:(_)=>_.v2Leftovers&&_.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: ${_.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(_)=>_.legacyConfigs&&_.legacyConfigs.length>0?[{checkId:"config.legacy-ignored",severity:"warning",title:"Legacy inline rule configs are ignored",detail:`CC Safety Net no longer loads these files, so their rules enforce nothing: ${_.legacyConfigs.join(", ")}.`,fixHint:"Run `cc-safety-net rule migrate` to convert them (add `--cleanup` to delete each file once it is converted), then rerun doctor."}]:[]},{derive:(_)=>{let L=_.environment.find((G)=>G.name==="CC_SAFETY_NET_AUDIT_SCOPE");return ot(L?.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."}]:[]}},...nm.map((_)=>({derive:(L)=>L.posture.directories.filter((G)=>G.kind===_&&G.status==="unsafe").map((G)=>({checkId:`posture.${_}-directory-unsafe`,severity:"error",title:`${_[0]?.toUpperCase()}${_.slice(1)} directory is unsafe`,detail:`The ${_} directory ${tm(G.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...G.path?{path:G.path}:{}}))})),{derive:(_)=>{let L=[..._.effectiveSafety.weakenedRuleOverrides].sort();return L.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: ${L.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${L.join(", ")}.`}]:[]}}];function wa(_){return rm.flatMap((L,G)=>L.derive(_).map((Y,Z)=>({finding:Y,catalogOrder:G,occurrence:Z}))).sort((L,G)=>ba[L.finding.severity]-ba[G.finding.severity]||L.catalogOrder-G.catalogOrder||L.occurrence-G.occurrence).map((L)=>L.finding)}function Dn(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var om=(_)=>Dn()?`\x1B[32m${_}\x1B[0m`:_,im=(_)=>Dn()?`\x1B[33m${_}\x1B[0m`:_,sm=(_)=>Dn()?`\x1B[34m${_}\x1B[0m`:_,am=(_)=>Dn()?`\x1B[36m${_}\x1B[0m`:_,lm=(_)=>Dn()?`\x1B[31m${_}\x1B[0m`:_,cm=(_)=>Dn()?`\x1B[2m${_}\x1B[0m`:_,dm=(_)=>Dn()?`\x1B[1m${_}\x1B[0m`:_,en={green:om,yellow:im,blue:sm,cyan:am,red:lm,dim:cm,bold:dm},um="\x1B[0m",pm=[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 fm(_){let L=_;return()=>(L=(L*1664525+1013904223)%4294967296,L/4294967296)}function mm(_){let L=[...pm],G=fm(_);for(let Y=L.length-1;Y>0;Y--){let Z=Math.floor(G()*(Y+1)),oe=L[Y];L[Y]=L[Z],L[Z]=oe}return L}function gm(_,L=0){if(!Dn())return"";let G=mm(L);return`\x1B[38;5;${G[_%G.length]}m`}function ka(_,L,G=0){if(!Dn())return`"${_}"`;return`${gm(L,G)}"${_}"${um}`}function Or(_){return _==="default"?"built-in default":`${_} policy`}var ym=new RegExp("\x1B\\[[0-9;]*m","g"),Yo=(_)=>_.replace(ym,"").length;function Zn(_){let L=(_.headers??_.rows[0]??[]).map((se,fe)=>{let ge=Math.max(..._.rows.map((Pe)=>Yo(Pe[fe]??"")));return Math.max(Yo(se),ge)}),G=(se,fe)=>se+" ".repeat(Math.max(0,fe-Yo(se))),Y=(se,fe)=>fe[0]+L.map((ge)=>se.repeat(ge+2)).join(fe[1])+fe[2],Z=(se)=>`│ ${se.map((fe,ge)=>G(fe,L[ge]??0)).join(" │ ")} │`,oe=_.headers?[` ${Z(_.headers)}`,` ${Y("─",["├","┼","┤"])}`]:[];return[` ${Y("─",["┌","┬","┐"])}`,...oe,..._.rows.map((se)=>` ${Z(se)}`),` ${Y("─",["└","┴","┘"])}`].join(`
6
6
  `)}function Ca(_){let L=[];L.push("Hook Integration"),L.push(hm(_));let G=[],Y=[];for(let Z of _){let oe=cn(Z.platform);if(Z.errors&&Z.errors.length>0)for(let se of Z.errors)if(Z.configured)G.push({platform:oe,message:se});else Y.push({platform:oe,message:se})}for(let Z of G)L.push(` Warning (${Z.platform}): ${Z.message}`);for(let Z of Y)L.push(en.red(` Error (${Z.platform}): ${Z.message}`));return L.join(`
7
7
  `)}function hm(_){let L=["Platform","Discovery","Configuration","Inspection"],G=_.map((Y)=>{let Z=cn(Y.platform);if(Y.inspectionStatus==="not-inspected"){let ge=en.dim("Not inspected");return[Z,ge,ge,ge]}let oe=Y.detected?en.green("Detected"):Y.inspectionStatus==="failed"?en.red("Unknown"):en.dim("Not detected"),se=Y.configured?en.green("Configured"):Y.detected?en.yellow("Not configured"):Y.inspectionStatus==="failed"?en.red("Unknown"):en.dim("Not applicable"),fe=Y.inspectionStatus==="verified"?en.green("Verified"):Y.inspectionStatus==="failed"?en.red("Failed"):en.dim("Not applicable");return[Z,oe,se,fe]});return Zn({headers:L,rows:G})}function xa(_){let G=["Guard Engine Verification",` Synthetic self-test: ${_.failed>0?en.red(`${_.passed}/${_.total} FAIL`):en.green(`${_.passed}/${_.total} passed`)}`],Y=_.results.filter((Z)=>!Z.passed);if(Y.length>0){G.push(""),G.push(en.red(" Failures:"));for(let Z of Y)G.push(en.red(` • ${Z.description}`)),G.push(en.red(` expected ${Z.expected}, got ${Z.actual}`))}return G.join(`
@@ -18,12 +18,12 @@ ${Go(Z.segment||Z.command)}`,G=_.filter((Z)=>Z.decision!=="allow"),Y=G.filter((Z
18
18
  `)}function $r(_){return Zn({rows:_})}function Ia(_){let L=[];return L.push("System Info"),L.push(Cm(_)),L.join(`
19
19
  `)}function Cm(_){let L=["Component","Version"],G=(oe)=>{if(oe===null)return en.dim("not found");return oe},Z=[{label:"cc-safety-net",value:_.version},...Rr.map((oe)=>({label:cn(oe),value:_.versions[oe]??null})),{label:"Node.js",value:_.nodeVersion},{label:"npm",value:_.npmVersion},{label:"Bun",value:_.bunVersion},{label:"Platform",value:_.platform}].map((oe)=>[oe.label,G(oe.value)]);return Zn({headers:L,rows:Z})}function Aa(_){if(_.findings.length===0)return en.green(`
20
20
  No findings from inspected doctor facts.`);let L={error:_.findings.filter((oe)=>oe.severity==="error").length,warning:_.findings.filter((oe)=>oe.severity==="warning").length,info:_.findings.filter((oe)=>oe.severity==="info").length},G=["error","warning","info"].filter((oe)=>L[oe]>0).map((oe)=>`${L[oe]} ${oe}`),Y=_.findings.length===1?"finding":"findings",Z=`
21
- ${_.findings.length} ${Y}: ${G.join(", ")}.`;if(L.error>0)return en.red(Z);if(L.warning>0)return en.yellow(Z);return en.blue(Z)}import{lstatSync as xm}from"node:fs";import{dirname as Zo}from"node:path";function Xo(_,L){try{let G=xm(L);if(G.isSymbolicLink())return{kind:_,path:L,status:"unsafe",issues:["symlink"]};if(!G.isDirectory())return{kind:_,path:L,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:_,path:L,status:"unknown",issues:[]};let Y=[...G.uid!==process.getuid()?["ownership"]:[],...(G.mode&18)!==0?["permissions"]:[]];return{kind:_,path:L,status:Y.length>0?"unsafe":"safe",issues:Y}}catch(G){if(typeof G==="object"&&G!==null&&"code"in G&&G.code==="ENOENT")return{kind:_,path:L,status:"not-applicable",issues:[]};return{kind:_,path:L,status:"unknown",issues:[]}}}function Oa(_,L){let G=H(_);return{directories:[Xo("policy",Zo(Zo(L))),Xo("config",Zo(L)),...G?[Xo("audit",G)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as Sm}from"node:child_process";import{existsSync as $a}from"node:fs";import{delimiter as Pm,extname as Em,join as Rm}from"node:path";import{stripVTControlCharacters as Da}from"node:util";var La="2.6.13",_m=5000,Tm="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function pn(){return La}function Qo(_,L){let G=_[L];if(G)return G;let Y=Object.keys(_).find((Z)=>Z.toLowerCase()===L.toLowerCase()&&!!_[Z]);return Y?_[Y]:G}function Im(_){return(Qo(_,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((L)=>L.length>0)}function Am(_,L){let G=Em(_)?[_]:[...Im(L).map((Y)=>`${_}${Y}`),_];if(_.includes("/")||_.includes("\\"))return G.find((Y)=>$a(Y))??_;return(Qo(L,"PATH")??"").split(Pm).flatMap((Y)=>G.map((Z)=>Rm(Y,Z))).find((Y)=>$a(Y))??_}function Na(_){if(!/[\s"&|<>^]/.test(_))return _;return`"${_.replace(/"/g,'""')}"`}function Xn(_,L){let[G,...Y]=_,Z=L[Tm]==="win32"?"win32":process.platform;if(!G||Z!=="win32")return{cmd:G??"",args:Y};let oe=Am(G,L);if(!/\.(?:bat|cmd)$/i.test(oe))return{cmd:oe,args:Y};return{cmd:Qo(L,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Na(oe),...Y.map(Na)].join(" ")]}}var Ht=async(_,L=_m)=>{let G=await Om(_,{timeoutMs:L});if(G.code!==0)return null;return Da(G.stdout).trim()||Da(G.stderr).trim()||null};function Om(_,L){let[G,...Y]=_;if(!G)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((Z)=>{try{let oe=Xn([G,...Y],process.env),se=Sm(oe.cmd,oe.args,{stdio:["ignore","pipe","pipe"]}),fe=!1,ge="",Pe="";se.stdout.on("data",(Le)=>{ge+=Le.toString()}),se.stderr.on("data",(Le)=>{Pe+=Le.toString()});let Ee=(Le)=>{if(fe)return;fe=!0,clearTimeout(Re),Z(Le)},Re=setTimeout(()=>{se.kill(),Ee({code:null,stdout:ge,stderr:Pe})},L.timeoutMs);se.on("close",(Le)=>{Ee({code:Le,stdout:ge,stderr:Pe})}),se.on("error",()=>{Ee({code:null,stdout:ge,stderr:Pe})})}catch{Z({code:null,stdout:"",stderr:""})}})}function Dr(_){if(!_)return null;let L=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(_);if(L)return L[1]??null;let G=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(_);if(G)return G[1]??null;return _.split(`
21
+ ${_.findings.length} ${Y}: ${G.join(", ")}.`;if(L.error>0)return en.red(Z);if(L.warning>0)return en.yellow(Z);return en.blue(Z)}import{lstatSync as xm}from"node:fs";import{dirname as Zo}from"node:path";function Xo(_,L){try{let G=xm(L);if(G.isSymbolicLink())return{kind:_,path:L,status:"unsafe",issues:["symlink"]};if(!G.isDirectory())return{kind:_,path:L,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:_,path:L,status:"unknown",issues:[]};let Y=[...G.uid!==process.getuid()?["ownership"]:[],...(G.mode&18)!==0?["permissions"]:[]];return{kind:_,path:L,status:Y.length>0?"unsafe":"safe",issues:Y}}catch(G){if(typeof G==="object"&&G!==null&&"code"in G&&G.code==="ENOENT")return{kind:_,path:L,status:"not-applicable",issues:[]};return{kind:_,path:L,status:"unknown",issues:[]}}}function Oa(_,L){let G=H(_);return{directories:[Xo("policy",Zo(Zo(L))),Xo("config",Zo(L)),...G?[Xo("audit",G)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as Sm}from"node:child_process";import{existsSync as $a}from"node:fs";import{delimiter as Pm,extname as Em,join as Rm}from"node:path";import{stripVTControlCharacters as Da}from"node:util";var La="2.6.15",_m=5000,Tm="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function pn(){return La}function Qo(_,L){let G=_[L];if(G)return G;let Y=Object.keys(_).find((Z)=>Z.toLowerCase()===L.toLowerCase()&&!!_[Z]);return Y?_[Y]:G}function Im(_){return(Qo(_,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((L)=>L.length>0)}function Am(_,L){let G=Em(_)?[_]:[...Im(L).map((Y)=>`${_}${Y}`),_];if(_.includes("/")||_.includes("\\"))return G.find((Y)=>$a(Y))??_;return(Qo(L,"PATH")??"").split(Pm).flatMap((Y)=>G.map((Z)=>Rm(Y,Z))).find((Y)=>$a(Y))??_}function Na(_){if(!/[\s"&|<>^]/.test(_))return _;return`"${_.replace(/"/g,'""')}"`}function Xn(_,L){let[G,...Y]=_,Z=L[Tm]==="win32"?"win32":process.platform;if(!G||Z!=="win32")return{cmd:G??"",args:Y};let oe=Am(G,L);if(!/\.(?:bat|cmd)$/i.test(oe))return{cmd:oe,args:Y};return{cmd:Qo(L,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Na(oe),...Y.map(Na)].join(" ")]}}var Ht=async(_,L=_m)=>{let G=await Om(_,{timeoutMs:L});if(G.code!==0)return null;return Da(G.stdout).trim()||Da(G.stderr).trim()||null};function Om(_,L){let[G,...Y]=_;if(!G)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((Z)=>{try{let oe=Xn([G,...Y],process.env),se=Sm(oe.cmd,oe.args,{stdio:["ignore","pipe","pipe"]}),fe=!1,ge="",Pe="";se.stdout.on("data",(Le)=>{ge+=Le.toString()}),se.stderr.on("data",(Le)=>{Pe+=Le.toString()});let Ee=(Le)=>{if(fe)return;fe=!0,clearTimeout(Re),Z(Le)},Re=setTimeout(()=>{se.kill(),Ee({code:null,stdout:ge,stderr:Pe})},L.timeoutMs);se.on("close",(Le)=>{Ee({code:Le,stdout:ge,stderr:Pe})}),se.on("error",()=>{Ee({code:null,stdout:ge,stderr:Pe})})}catch{Z({code:null,stdout:"",stderr:""})}})}function Dr(_){if(!_)return null;let L=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(_);if(L)return L[1]??null;let G=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(_);if(G)return G[1]??null;return _.split(`
22
22
  `)[0]?.trim()||null}async function Nr(_,L=Ht,G=process.cwd()){let Y=Promise.all(En.map(async(Re)=>[Re.id,Dr(await L([...Re.probeCommand]))])),[Z,oe,se,fe,ge,Pe,Ee]=await Promise.all([Y,Y.then(async(Re)=>{let Le=Re.find(([Be])=>Be==="opencode")?.[1];if(!Le?.startsWith("2.")||!_(Le))return null;let _e=["--param",`location[directory]=${G}`],Te=["opencode","api","integration.list",..._e];return await L(Te,30000),L(["opencode","api","plugin.list",..._e],30000)}),L(["codex","plugin","list"],30000),L(["amp","plugins","list"],30000),L(["node","--version"]),L(["npm","--version"]),L(["bun","--version"])]);return{version:La,versions:Object.fromEntries(Z),codexPluginListOutput:se,ampPluginListOutput:fe,openCodePluginListOutput:oe,nodeVersion:Dr(ge),npmVersion:Dr(Pe),bunVersion:Dr(Ee),platform:`${process.platform} ${process.arch}`}}function ei(_,L){if(L==="dev")return!1;let G=_.split(".").map(Number),Y=L.split(".").map(Number),[Z=0,oe=0,se=0]=G,[fe=0,ge=0,Pe=0]=Y;if(Z!==fe)return Z>fe;if(oe!==ge)return oe>ge;return se>Pe}async function Gn(){let _=pn(),L=new AbortController,G=setTimeout(()=>L.abort(),3000);try{let Y=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:L.signal});if(!Y.ok)return{currentVersion:_,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${Y.status}`};let Z=await Y.json(),oe=ei(Z.version,_);return{currentVersion:_,latestVersion:Z.version,updateAvailable:oe}}catch(Y){return{currentVersion:_,latestVersion:null,updateAvailable:!1,error:Y instanceof Error?Y.message:"Network error"}}finally{clearTimeout(G)}}import*as qa from"node:readline";var Ma=(_)=>`\x1B[${_}B`,$m=(_)=>`\x1B[${_}A`;var ja=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function Dm(_){return new Promise((L)=>setTimeout(L,_))}function Nm(_,L,G){if(!G)return L(_);if(G.aborted)return Promise.resolve();return new Promise((Y,Z)=>{let oe=()=>G.removeEventListener("abort",se),se=()=>{oe(),Y()};G.addEventListener("abort",se,{once:!0}),L(_).then(()=>{oe(),Y()},(fe)=>{oe(),Z(fe)})})}function Lr(_){return Math.max(0,Math.min(1,_))}function Ft(_){return Math.max(0,Math.min(255,Math.round(_)))}function ni(_){return _<=0.0031308?12.92*_:1.055*_**0.4166666666666667-0.055}function Lm(_,L,G){let Y=G*Math.PI/180,Z=L*Math.cos(Y),oe=L*Math.sin(Y),se=(_+0.3963377774*Z+0.2158037573*oe)**3,fe=(_-0.1055613458*Z-0.0638541728*oe)**3,ge=(_-0.0894841775*Z-1.291485548*oe)**3;return{blue:Ft(ni(Lr(-0.0041960863*se-0.7034186147*fe+1.707614701*ge))*255),green:Ft(ni(Lr(-1.2684380046*se+2.6097574011*fe-0.3413193965*ge))*255),red:Ft(ni(Lr(4.0767416621*se-3.3077115913*fe+0.2309699292*ge))*255)}}function ti(_,L){let G=(L*_*180/Math.PI%360+360)%360;return Lm(0.72,0.15,G)}function Ua(_,L=0.1){let G=ti(L,_);return`\x1B[38;2;${G.red};${G.green};${G.blue}m`}function jm(_,L){return{blue:Ft(_.blue+(255-_.blue)*L),green:Ft(_.green+(255-_.green)*L),red:Ft(_.red+(255-_.red)*L)}}function Ga(_,L,G){let Y=Math.imul(_+2654435769,2246822507)^Math.imul(L+3266489909,668265263)^Math.imul(G+374761393,2654435761),Z=Y^Y>>>15,oe=Math.imul(Z,739982445),se=oe^oe>>>12,fe=Math.imul(se,695872825);return((fe^fe>>>15)>>>0)/4294967296}function Hm(_,L,G){let Y=Math.floor(Ga(_,L,G)*ja.length);return ja[Y]??"░"}function Ha(_){let L=Lr(_);return L*L*L*(L*(L*6-15)+10)}function Fm(_){if(_.length===0)return"";let L=[],G=!1,Y="";for(let Z of _){let oe=`${Z.red};${Z.green};${Z.blue}`;if(Z.bold!==G)L.push(Z.bold?"\x1B[1m":"\x1B[22m"),G=Z.bold;if(oe!==Y)L.push(`\x1B[38;2;${oe}m`),Y=oe;L.push(Z.character)}return`${L.join("")}\x1B[22m\x1B[39m`}function Mm(_,L,G,Y,Z){return _.map((oe,se)=>({...ti(G,Y+L+se/Z),bold:!1,character:oe}))}function Um(_,L,G,Y,Z,oe,se,fe){let ge=Math.max(1,Y*0.75),Pe=Math.min(1,G/ge),Ee=Z*Ha(Pe),Re=Math.max(0,(G-ge)/Math.max(1,Y-ge)),Le=(1-Ha(G/Y))*fe*2,_e=0.35*Math.max(0,1-Re*2),Te=Pe>=1,Be=Math.min(_.length,Math.ceil(Ee+2+1));return _.slice(0,Be).map((Fe,Ze)=>{let tn=ti(oe,se+L+Ze/fe+Le),on=Ze+Ga(L,Ze,7919)*2-1;if(on>Ee+2)return{...tn,bold:!1,character:" "};let an=Ee-on,nn=0.8*Math.exp(-(an*an)/12.5),sn=Math.min(0.9,nn+_e),Sn=!Te&&on>Ee-4;return{...jm(tn,sn),bold:sn>0.3,character:Sn?Hm(L,Ze,G):Fe}})}function Fa(_){return`\x1B[?2026h${_.map((L,G)=>`\x1B8${G>0?Ma(G):""}${Fm(L)}`).join("")}\x1B[?2026l`}async function ri(_,L={}){if(!_)return;let G=L.output??process.stdout,Y=L.sleep??Dm,Z=L.seed??0,oe=_.split(`
23
23
  `).map((Ee)=>Array.from(Ee)),se=Math.max(...oe.map((Ee)=>Ee.length)),fe=12000*oe.filter((Ee)=>Ee.length>0).length/40,ge=se>0?Math.max(1,Math.ceil(fe/16.666666666666668)):0,Pe=ge>0?fe/ge:0;G.write(`\x1B[?25l${oe.length>1?`${`
24
24
  `.repeat(oe.length-1)}${$m(oe.length-1)}`:""}\x1B7`);try{for(let Ee=1;Ee<=ge;Ee+=1){if(L.signal?.aborted)break;G.write(Fa(oe.map((Re,Le)=>Um(Re,Le,Ee,ge,se,0.1,Z,3)))),await Nm(Pe,Y,L.signal)}}finally{if(G.write(Fa(oe.map((Ee,Re)=>Mm(Ee,Re,0.1,Z,3)))),G.write("\x1B8"),oe.length>1)G.write(Ma(oe.length-1));G.write(`
25
25
  \x1B[0m\x1B[?25h`)}}var Ba=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
- `);function Gm(_){return Boolean(_.isTTY)}async function er(_={}){let L=_.output??process.stdout;if(!Gm(L))return;let G=_.input??process.stdin,Y={output:L,seed:_.seed??Math.random()*8192,sleep:_.sleep};if(!G.isTTY||typeof G.setRawMode!=="function"){await ri(Ba,Y);return}let Z=new AbortController,oe=G.readableFlowing===!0,se=G.isRaw===!0,fe=!1,ge=(Pe,Ee)=>{if(Ee.ctrl&&Ee.name==="c")fe=!0;if(fe||Ee.name==="return"||Ee.name==="enter")Z.abort()};qa.emitKeypressEvents(G),G.on("keypress",ge),G.setRawMode(!0),G.resume();try{await ri(Ba,{...Y,signal:Z.signal})}finally{if(G.off("keypress",ge),G.setRawMode(se),!oe)G.pause()}if(!fe)return;if(_.onInterrupt){_.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Km}from"node:crypto";import{existsSync as Ka}from"node:fs";import{dirname as jr,join as Ja}from"node:path";import{dirname as Va,join as Bm}from"node:path";var qm="rule.lock";function Vm(_){return Bm(Va(_),qm)}function hn(_,L){let G=L.global?L.userConfigPath??z(_,L):L.projectConfigPath??I(L.cwd??process.cwd()),Y=L.global?at(_,L):ct(G,L.cwd??process.cwd()),Z=Vm(G);return{configDir:Va(G),configPath:G,lockPath:Z,filesystemScope:Y,configTarget:i(Y,G),lockTarget:i(Y,Z)}}var Jm="`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.",Wm="cache",zm="rulebooks";function Wa(_,L={}){let G=hn(_,L),Y=i(G.filesystemScope,Ya(G.configDir)),Z=r(G.lockTarget);if(console.log(Jm),Z===null&&!Ka(Y.path))return console.log(`No v2 lock or cache leftovers found in ${jr(G.configDir)}; nothing to migrate.`),0;let oe=eg(Z),se=d(G.configTarget);if(!se.config&&(r(G.configTarget)!==null||oe.size>0))return console.error(`Cannot migrate: the rules config in ${jr(G.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let fe=se.config?.rules??[];for(let ge of fe.flatMap((Pe)=>Ym(Pe,oe,G,Y,L.global===!0)))console.log(ge);return B(G.lockTarget),wt(Y),console.log(`Removed the v2 lock and cache under ${jr(G.configDir)}.`),0}function za(_,L){return[...new Set([{cwd:L},{cwd:L,global:!0}].flatMap((G)=>{let Y=hn(_,G);return[Y.lockPath,Ya(Y.configDir)]}))].filter((G)=>Ka(G))}function Ym(_,L,G,Y,Z){if(!C(_))return[];let oe=M(_).name,se=i(G.filesystemScope,F(G.configDir,oe)),fe=r(se);if(fe!==null&&Zm(fe,oe))return[];let ge=L.get(_),Pe=ge?Xm(ge,oe,Y.path,G.filesystemScope):null;if(Pe===null)return[`Could not migrate ${_} from the v2 cache. Run \`cc-safety-net rule update ${_}${Z?" --global":""}\` to vendor it.`];if(g(se,Pe),fe!==null)return[`Restored ${_} from the v2 cache over an invalid file.`];return[`Vendored ${_} from the v2 cache.`]}function Zm(_,L){let G=we(_);return!("problem"in G)&&G.rulebook.name===L}function Xm(_,L,G,Y){let Z=Ja(G,zm,`${Qm(_)}--${_.digest.replace("sha256:","").slice(0,12)}`,ye),oe=r(i(Y,Z));if(oe===null||rg(oe)!==_.digest)return null;let se=we(oe);if("problem"in se||se.rulebook.name!==L)return null;return oe}function Ya(_){return Ja(jr(_),Wm)}function Qm(_){return([_.owner,_.repo,_.display_ref,_.name].every((Y)=>typeof Y==="string"&&Y!=="")?`${_.owner}/${_.repo}#${_.display_ref}/${_.name}`:_.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function eg(_){let L=_===null?null:tg(_),G=Za(L)&&Array.isArray(L.rulebooks)?L.rulebooks:[];return new Map(G.filter(ng).map((Y)=>[Y.spec,Y]))}function ng(_){return Za(_)&&typeof _.spec==="string"&&typeof _.digest==="string"}function Za(_){return!!_&&typeof _==="object"}function tg(_){try{return JSON.parse(_)}catch{return null}}function rg(_){return`sha256:${Km("sha256").update(_).digest("hex")}`}var Xa="\r\x1B[2K",og="\x1B[?25l",ig="\x1B[39m",sg="\x1B[?25h",ag=100,lg=0.55,cg=80,Qa=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function dg(_){return new Promise((L)=>setTimeout(L,_))}async function Hr(_,L={}){let G=L.output??process.stdout;if(!G.isTTY)return _;let Y=L.sleep??dg,Z=!1,oe=_.then((fe)=>(Z=!0,fe),(fe)=>{throw Z=!0,fe});if(await Promise.race([oe.then(()=>!0),Y(ag).then(()=>!1)]))return oe;G.write(og);try{for(let fe=0;!Z;fe+=1)G.write(`${Xa}${Ua(fe*lg)}${Qa[fe%Qa.length]}${ig} ${L.loadingMessage??"Loading…"}`),await Promise.race([oe,Y(cg)]);return await oe}finally{G.write(`${Xa}${sg}`)}}async function nr(_,L,G,Y={}){let Z=L();if(_)await G();if(_&&Z.ready)await Hr(Z.ready,Y);return Z.finish()}import{stripVTControlCharacters as ug}from"node:util";var Fr="amp plugins list",pg=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function el(_){if(!_.ampPluginListOutput)return{platform:"amp",status:"n/a"};let L=ug(_.ampPluginListOutput).split(`
26
+ `);function Gm(_){return Boolean(_.isTTY)}async function er(_={}){let L=_.output??process.stdout;if(!Gm(L))return;let G=_.input??process.stdin,Y={output:L,seed:_.seed??Math.random()*8192,sleep:_.sleep};if(!G.isTTY||typeof G.setRawMode!=="function"){await ri(Ba,Y);return}let Z=new AbortController,oe=G.readableFlowing===!0,se=G.isRaw===!0,fe=!1,ge=(Pe,Ee)=>{if(Ee.ctrl&&Ee.name==="c")fe=!0;if(fe||Ee.name==="return"||Ee.name==="enter")Z.abort()};qa.emitKeypressEvents(G),G.on("keypress",ge),G.setRawMode(!0),G.resume();try{await ri(Ba,{...Y,signal:Z.signal})}finally{if(G.off("keypress",ge),G.setRawMode(se),!oe)G.pause()}if(!fe)return;if(_.onInterrupt){_.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Km}from"node:crypto";import{existsSync as Ka}from"node:fs";import{dirname as jr,join as Ja}from"node:path";import{dirname as Va,join as Bm}from"node:path";var qm="rule.lock";function Vm(_){return Bm(Va(_),qm)}function hn(_,L){let G=L.global?L.userConfigPath??z(_,L):L.projectConfigPath??I(L.cwd??process.cwd()),Y=L.global?at(_,L):ct(G,L.cwd??process.cwd()),Z=Vm(G);return{configDir:Va(G),configPath:G,lockPath:Z,filesystemScope:Y,configTarget:i(Y,G),lockTarget:i(Y,Z)}}var Jm="`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.",Wm="cache",zm="rulebooks";function Wa(_,L={}){let G=hn(_,L),Y=i(G.filesystemScope,Ya(G.configDir)),Z=r(G.lockTarget);if(console.log(Jm),Z===null&&!Ka(Y.path))return console.log(`No v2 lock or cache leftovers found in ${jr(G.configDir)}; nothing to migrate.`),0;let oe=eg(Z),se=d(G.configTarget);if(!se.config&&(r(G.configTarget)!==null||oe.size>0))return console.error(`Cannot migrate: the rules config in ${jr(G.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let fe=se.config?.rules??[];for(let ge of fe.flatMap((Pe)=>Ym(Pe,oe,G,Y,L.global===!0)))console.log(ge);return B(G.lockTarget),wt(Y),console.log(`Removed the v2 lock and cache under ${jr(G.configDir)}.`),0}function za(_,L){return[...new Set([{cwd:L},{cwd:L,global:!0}].flatMap((G)=>{let Y=hn(_,G);return[Y.lockPath,Ya(Y.configDir)]}))].filter((G)=>Ka(G))}function Ym(_,L,G,Y,Z){if(!C(_))return[];let oe=M(_).name,se=i(G.filesystemScope,F(G.configDir,oe)),fe=r(se);if(fe!==null&&Zm(fe,oe))return[];let ge=L.get(_),Pe=ge?Xm(ge,oe,Y.path,G.filesystemScope):null;if(Pe===null)return[`Could not migrate ${_} from the v2 cache. Run \`cc-safety-net rule update ${_}${Z?" --global":""}\` to vendor it.`];if(h(se,Pe),fe!==null)return[`Restored ${_} from the v2 cache over an invalid file.`];return[`Vendored ${_} from the v2 cache.`]}function Zm(_,L){let G=we(_);return!("problem"in G)&&G.rulebook.name===L}function Xm(_,L,G,Y){let Z=Ja(G,zm,`${Qm(_)}--${_.digest.replace("sha256:","").slice(0,12)}`,ye),oe=r(i(Y,Z));if(oe===null||rg(oe)!==_.digest)return null;let se=we(oe);if("problem"in se||se.rulebook.name!==L)return null;return oe}function Ya(_){return Ja(jr(_),Wm)}function Qm(_){return([_.owner,_.repo,_.display_ref,_.name].every((Y)=>typeof Y==="string"&&Y!=="")?`${_.owner}/${_.repo}#${_.display_ref}/${_.name}`:_.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function eg(_){let L=_===null?null:tg(_),G=Za(L)&&Array.isArray(L.rulebooks)?L.rulebooks:[];return new Map(G.filter(ng).map((Y)=>[Y.spec,Y]))}function ng(_){return Za(_)&&typeof _.spec==="string"&&typeof _.digest==="string"}function Za(_){return!!_&&typeof _==="object"}function tg(_){try{return JSON.parse(_)}catch{return null}}function rg(_){return`sha256:${Km("sha256").update(_).digest("hex")}`}var Xa="\r\x1B[2K",og="\x1B[?25l",ig="\x1B[39m",sg="\x1B[?25h",ag=100,lg=0.55,cg=80,Qa=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function dg(_){return new Promise((L)=>setTimeout(L,_))}async function Hr(_,L={}){let G=L.output??process.stdout;if(!G.isTTY)return _;let Y=L.sleep??dg,Z=!1,oe=_.then((fe)=>(Z=!0,fe),(fe)=>{throw Z=!0,fe});if(await Promise.race([oe.then(()=>!0),Y(ag).then(()=>!1)]))return oe;G.write(og);try{for(let fe=0;!Z;fe+=1)G.write(`${Xa}${Ua(fe*lg)}${Qa[fe%Qa.length]}${ig} ${L.loadingMessage??"Loading…"}`),await Promise.race([oe,Y(cg)]);return await oe}finally{G.write(`${Xa}${sg}`)}}async function nr(_,L,G,Y={}){let Z=L();if(_)await G();if(_&&Z.ready)await Hr(Z.ready,Y);return Z.finish()}import{stripVTControlCharacters as ug}from"node:util";var Fr="amp plugins list",pg=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function el(_){if(!_.ampPluginListOutput)return{platform:"amp",status:"n/a"};let L=ug(_.ampPluginListOutput).split(`
27
27
  `).map((G)=>pg.exec(G)?.[1]).find((G)=>G!==void 0);if(!L)return{platform:"amp",status:"n/a"};if(L!=="active")return{platform:"amp",status:"disabled",method:Fr,configPath:Fr,errors:[`Amp personal plugin cc-safety-net is ${L}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:Fr,configPath:Fr}}import{existsSync as bg,readFileSync as wg}from"node:fs";import{isAbsolute as tS,join as vg}from"node:path";function tr(_){return vg(_,".gemini","config","hooks.json")}var tl=new Map([["run_command","auto"]]),rl="manage_task";var kg=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Cg(_){if(!_||typeof _!=="object"||Array.isArray(_))return[];return Object.values(_).flatMap((L)=>{if(!L||typeof L!=="object"||Array.isArray(L))return[];let G=L,Y=G.PreToolUse;if(!Array.isArray(Y))return[];return Y.flatMap((Z)=>{if(!Z||typeof Z!=="object"||Array.isArray(Z))return[];let oe=Z.hooks;if(!Array.isArray(oe))return[];return oe.flatMap((se)=>{if(!se||typeof se!=="object"||Array.isArray(se))return[];let fe=se.command;if(typeof fe!=="string"||!kg.test(fe))return[];return[{command:fe,enabled:G.enabled!==!1}]})})})}function ol(_){let L=tr(_.environment.home);if(!bg(L))return{platform:"antigravity-cli",status:"n/a",configPath:L};let G;try{G=Cg(JSON.parse(wg(L,"utf-8")))}catch(Y){return{platform:"antigravity-cli",status:"n/a",configPath:L,errors:[`Failed to parse Antigravity hooks config ${L}: ${Y instanceof Error?Y.message:String(Y)}`]}}if(G.some((Y)=>Y.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:L};if(G.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:L};return{platform:"antigravity-cli",status:"n/a",configPath:L}}import{existsSync as Rg}from"node:fs";import{join as Ln}from"node:path";import{existsSync as xg,lstatSync as Sg,readFileSync as Pg}from"node:fs";import{join as Eg}from"node:path";function vn(_,L=(G)=>G){if(!xg(_))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(L(Pg(_,"utf-8")))}}catch{return{kind:"unreadable"}}}function Nn(_,L){if(_==="~")return L;if(_.startsWith("~/")||_.startsWith("~\\"))return Eg(L,_.slice(2));return _}function dn(_){try{return Sg(_)}catch{return}}function Br(_,L){let G=dn(L);if(!G)return{platform:_,status:"n/a",configPath:L};if(!G.isSymbolicLink()&&G.isDirectory())return;return{platform:_,status:"n/a",configPath:L,errors:[`${L} is a symlink or not a directory; move or remove it before installing`]}}function Xe(_,L){return typeof _==="object"&&_!==null?_[L]:void 0}var qr="cc-safety-net@cc-marketplace";function Vr(_){return _.env.get("CLAUDE_CONFIG_DIR")||Ln(_.home,".claude")}function il(_){return Ln(_.env.get("CLAUDE_CODE_PLUGIN_CACHE_DIR")||Ln(Vr(_),"plugins"),"installed_plugins.json")}function sl(_,L){let G=Xe(Xe(_,"plugins"),L);return Array.isArray(G)&&G.length>0}function Kr(_,L){let G=vn(il(_));return G.kind==="ok"&&sl(G.value,L)}function ii(_){return al(il(_),Ln(Vr(_),"settings.json"))}function al(_,L){let G=vn(_);if(G.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(G.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!sl(G.value,qr))return{platform:"claude-code",status:"n/a"};let Y=vn(L);if(Y.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(Y.kind==="ok"&&Xe(Xe(Y.value,"enabledPlugins"),qr)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:L,errors:[`${qr} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:_}}function ll(_){let L=Ln(_.home,".claude"),G=Ln(L,"plugins","installed_plugins.json");if(al(G,Ln(L,"settings.json")).status!=="configured")return;let Y=vn(G),Z=Y.kind==="ok"?Xe(Xe(Y.value,"plugins"),qr):void 0,oe=(Array.isArray(Z)?Z:[]).filter((Pe)=>Xe(Pe,"scope")==="user").map((Pe)=>Xe(Pe,"installPath")).find((Pe)=>typeof Pe==="string");if(!oe)return;let se=Ln(oe,".cursor-plugin","plugin.json"),fe=vn(se),ge=fe.kind==="ok"?Xe(fe.value,"hooks"):void 0;return typeof ge==="string"&&Rg(Ln(oe,ge))?se:void 0}function cl(_){return ii(_.environment)}var dl="Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it.";function ul(_){if(!_.codexPluginListOutput)return{platform:"codex",status:"n/a"};let L=_.codexPluginListOutput.split(`
28
28
  `).find((G)=>G.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!L)return{platform:"codex",status:"n/a"};if(!L.includes("installed,"))return{platform:"codex",status:"n/a"};if(!L.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",errors:["Codex runs only trusted hooks, and doctor cannot check trust. Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."]}}import{existsSync as Yr,readdirSync as _g,readFileSync as Tg}from"node:fs";import{join as wn}from"node:path";function yn(_){let L="",G=0,Y=!1,Z=!1,oe=-1;while(G<_.length){let se=_[G],fe=_[G+1];if(Z){L+=se,Z=!1,G++;continue}if(se==='"'&&!Y){Y=!0,oe=-1,L+=se,G++;continue}if(se==='"'&&Y){Y=!1,L+=se,G++;continue}if(se==="\\"&&Y){Z=!0,L+=se,G++;continue}if(Y){L+=se,G++;continue}if(se==="/"&&fe==="/"){while(G<_.length&&_[G]!==`
29
29
  `)G++;continue}if(se==="/"&&fe==="*"){G+=2;while(G<_.length-1){if(_[G]==="*"&&_[G+1]==="/"){G+=2;break}G++}continue}if(se===","){oe=L.length,L+=se,G++;continue}if(se==="}"||se==="]"){if(oe!==-1){let ge=L.slice(oe+1);if(/^\s*$/.test(ge))L=L.slice(0,oe)+ge}oe=-1,L+=se,G++;continue}if(!/\s/.test(se))oe=-1;L+=se,G++}return L}function fl(_,L,G){let Y=L+1,Z=!1;while(Y<_.length){if(Z){Z=!1,Y++;continue}if(_[Y]==="\\"){Z=!0,Y++;continue}if(_[Y]==='"')return Y+1;Y++}throw Error(G)}function ai(_,L,G){let Y=_[L],Z=Y==="["?"]":"}",oe=0,se=L;while(se<_.length){let fe=G.skipComment?.(_,se)??se;if(fe!==se){se=fe;continue}if(_[se]==='"'){se=fl(_,se,G.stringError);continue}if(_[se]===Y)oe++;if(_[se]===Z){if(oe--,oe===0)return se}se++}throw Error(G.bracketError)}function ml(_,L){let G=_.lastIndexOf(`
@@ -226,8 +226,8 @@ def register(ctx):
226
226
  `)[0]}`}function hh(_){if(!_)return[];try{let L=Xe(JSON.parse(_),"data");return Array.isArray(L)?L:[]}catch{return[]}}async function Wi(_=1){let L=await fn(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s|\scc-safety-net@latest\s*$/m.test(L)||_===mh)return L;return await new Promise((G)=>setTimeout(G,gh)),Wi(_+1)}async function vh(_){let L=In(Gc(_),"node_modules",pr),G=In(L,"package.json");if(!go(G))throw Error(`The OpenCode plugin cache at ${L} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${St}\` for details.`);let Y=Xe(JSON.parse(zi(G,"utf-8")),"main");if(typeof Y!=="string")throw Error(`The cached OpenCode plugin at ${L} declares no "main" entry.`);let Z=In(L,Y);if(typeof(await import(fh(Z).href))[Mc]==="function")return;throw Error(`The cached OpenCode plugin at ${Z} does not export a callable ${Mc}, so OpenCode would load nothing and fail open.`)}function ns(_,L){try{return JSON.parse(yn(_))}catch(G){if(G instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${L}: ${G.message}`);throw G}}function yo(_){let L=typeof _==="string"?_:Xe(_,"package");return typeof L==="string"&&(L===pr||L.startsWith(`${pr}@`))}function ts(_){return["plugin","plugins"].some((L)=>{let G=Xe(_,L);return Array.isArray(G)&&G.some(yo)})}function bh(_,L){let Y=["plugin","plugins"].flatMap((Z)=>{let oe=yl(_,Z,yh);if(!oe)return[];let se=[],fe=0,ge=oe.start+1,Pe=_.slice(oe.start+1,oe.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let Ee of Pe){if(Ee[0].startsWith("//")||Ee[0].startsWith("/*"))continue;let Re=oe.start+1+Ee.index;if(fe===0)ge=Re;if(Ee[0]==="{"||Ee[0]==="[")fe++;if(Ee[0]==="}"||Ee[0]==="]")fe--;if(fe!==0||Ee[0]===",")continue;let Le=Re+Ee[0].length;if(yo(JSON.parse(yn(_.slice(ge,Le)))))se.push({start:ge,end:Le})}return se}).sort((Z,oe)=>Z.start-oe.start).reverse().reduce((Z,oe)=>{let se=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(Z.slice(oe.end));if(se?.[0].includes("/")){let fe=oe.end+se[0].length-1;return Z.slice(0,oe.start)+Z.slice(oe.end,fe)+Z.slice(fe+1)}return gl(Z,oe)},_);return ns(Y,L),Y}function Jc(_){Bc(_);let L=Qi(_),G=L.find((oe)=>go(oe)),Y=[],Z=[];for(let oe of L){if(!go(oe))continue;try{let se=zi(oe,"utf-8");if(!ts(ns(se,oe)))continue;ln(oe,bh(se,oe)),Z.push(oe)}catch(se){Y.push(se instanceof Error?se.message:String(se))}}if(Y.length>0)throw Error(Y.join(`
227
227
  `));return{path:Z[0]??G??In(Zi(_),Yi[0]),alreadyInstalled:Z.length>0}}function Jt(_){let L=[];for(let G of _.openCodeVersion?.startsWith("2.")?Xi(_.environment):Qi(_.environment))if(wh(G))try{let Y=kh(G,"utf-8"),Z=yn(Y),oe=JSON.parse(Z);if(ts(oe)){let se=es(_.openCodePluginListOutput);if(se)return{platform:"opencode",status:"disabled",method:"opencode api plugin.list",configPath:G,errors:[...L,se]};return{platform:"opencode",status:"configured",method:"plugin array",configPath:G,errors:L.length>0?L:void 0}}}catch(Y){L.push(`Failed to parse ${Ch(G)}: ${Y instanceof Error?Y.message:String(Y)}`)}return{platform:"opencode",status:"n/a",errors:L.length>0?L:void 0}}import{join as Wc}from"node:path";var Yc="dist/pi/index.js",zc=new Set([Yc,"index.js"]),xh=/[*?[\]{}]/;function rs(_){let L=_.env.get("PI_CODING_AGENT_DIR");return Wc(L?Nn(L,_.home):Wc(_.home,".pi","agent"),"settings.json")}function os(_){if(typeof _!=="string")return!1;return _==="npm:cc-safety-net"||_.startsWith("npm:cc-safety-net@")}function Sh(_){if(!Array.isArray(_)||_.length===0)return!1;if(!_.every((Y)=>typeof Y==="string"))return!1;let L=(Y)=>_.some((Z)=>Z.startsWith(Y)&&Z.slice(1).replace(/^\.[/\\]/,"")===Yc);if(L("-"))return!1;if(L("+"))return!0;let G=_.filter((Y)=>!/^[-+!]/.test(Y));return(G.length===0||G.some((Y)=>zc.has(Y)))&&!_.some((Y)=>Y.startsWith("!")&&(zc.has(Y.slice(1))||xh.test(Y)))}function Zc(_){let L=rs(_.environment),G=vn(L);if(G.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(G.kind==="missing")return{platform:"pi",status:"n/a"};let Y=Xe(G.value,"packages");if(!Array.isArray(Y))return{platform:"pi",status:"n/a"};let Z=Y.find((se)=>os(typeof se==="string"?se:Xe(se,"source")));if(Z===void 0)return{platform:"pi",status:"n/a"};let oe=Xe(Z,"extensions");if(oe!==void 0&&!Sh(oe))return{platform:"pi",status:"disabled",method:"package config",configPath:L,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:L}}var Ph={amp:el,"antigravity-cli":ol,"claude-code":cl,codex:ul,"copilot-cli":Tl,cursor:Hl,"deepseek-harness":Ml,devin:Wl,droid:tc,"gemini-cli":rc,"grok-build":fc,"hermes-agent":Pc,"kimi-code":po,openclaw:Fc,opencode:Jt,pi:Zc};function Wt(_,L,G){let Y={...G,cwd:L,environment:_};return Rr.map((Z)=>Eh(Ph[Z](Y)))}function Eh(_){if(_.status==="not-inspected")return{platform:_.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:_.platform,detected:_.status!=="n/a",configured:_.status==="configured",inspectionStatus:_.status!=="n/a"?"verified":_.errors&&_.errors.length>0?"failed":"not-applicable",method:_.method,configPath:_.configPath,configPaths:_.configPaths,errors:_.errors}}import{join as Rh}from"node:path";var _h=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}]),Th=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),commandTools:Object.freeze([]),safety:Object.freeze({level:"standard"}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),Ih={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 Xc(_){let L=Rh(_.tmpdir,"cc-safety-net-self-test"),G=_h.map((Y)=>{let Z=W(_,l("self-test",{command:Y.command},{kind:"command",shell:"auto"},{configCwd:L,executionCwd:L},Y.command),{guard:{dependencies:{loadPolicySnapshot:()=>Th,getModes:()=>Ih,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),oe=Y.expectBlocked?"blocked":"allowed",se=Z.decision.kind==="deny"?"blocked":"allowed";return{command:Y.command,description:Y.description,expected:oe,actual:se,passed:oe===se,reason:Z.decision.kind==="deny"?Z.decision.reason:void 0,ruleId:Z.decision.kind==="deny"?Z.decision.ruleId:void 0}});return{passed:G.filter((Y)=>Y.passed).length,failed:G.filter((Y)=>!Y.passed).length,total:G.length,results:G}}function is(_){let L=mn({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},_);if($n(L.errors))return null;return{json:L.flags.json,skipUpdateCheck:L.flags.skipUpdateCheck}}async function Qc(_,L={}){let G=await nr(!L.json,()=>{let Y=Oh(_,L);return{ready:Y,finish:()=>Y}},()=>er(),{loadingMessage:"Checking system status…"});if(L.json)console.log(JSON.stringify(G,null,2));else $h(G);return G.engineSelfTest.failed>0||G.findings.some((Y)=>Y.severity==="error")?1:0}async function Oh(_,L){let G=L.cwd??process.cwd(),Y=await Nr((Fe)=>Jt({environment:_,cwd:G,openCodeVersion:Fe}).status!=="n/a",void 0,G),Z=Wt(_,G,{ampPluginListOutput:Y.ampPluginListOutput,codexPluginListOutput:Y.codexPluginListOutput,copilotCliVersion:Y.versions["copilot-cli"],openCodeVersion:Y.versions.opencode,openCodePluginListOutput:Y.openCodePluginListOutput}),oe=ha(_,G),se=va(_),fe=R(_,{cwd:G}),ge=fe.policy,Pe=P(ge,_.env),Ee=K(ge,Pe.capabilities),Re=Ar(_,7),Le=za(_,G),_e=[Lt(G),jt(_)].filter((Fe)=>Ah(Fe)),Te=L.skipUpdateCheck?{currentVersion:pn(),latestVersion:null,updateAvailable:!1}:await Gn(),Be={hooks:Z,engineSelfTest:Xc(_),userConfig:oe.userConfig,projectConfig:oe.projectConfig,configState:Ve(fe),effectiveRules:oe.effectiveRules,environment:se,effectiveSafety:{selectedPreset:ge.safety.level,level:Pe.effectiveLevel,capabilities:Pe.capabilities,ruleOverrides:ge.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(Ee).filter(([,Fe])=>Fe.source==="rule_override"&&Fe.override==="off"&&Fe.inheritedEnabled&&Fe.changesInherited).map(([Fe])=>Fe),ruleCounts:{stored:Object.keys(ge.destructiveCommandRuleOverrides).length,effective:Object.values(Ee).filter((Fe)=>Fe.changesInherited).length},...fe.policyScopes?{policyScopes:fe.policyScopes}:{}},...Le.length>0?{v2Leftovers:Le}:{},..._e.length>0?{legacyConfigs:_e}:{},posture:Oa(_,oe.userConfig.path),activity:Re,update:Te,system:Y};return{...Be,findings:wa(Be)}}function $h(_){console.log(),console.log(Ca(_.hooks)),console.log(),console.log(xa(_.engineSelfTest)),console.log(),console.log(Sa(_)),console.log(),console.log(Pa(_.environment)),console.log(),console.log(Ea(_)),console.log(),console.log(Ra(_.findings)),console.log(),console.log(_a(_.activity)),console.log(),console.log(Ia(_.system)),console.log(),console.log(Ta(_.update)),console.log(Aa(_))}import{existsSync as Dh}from"node:fs";var Nh=/^[A-Za-z0-9_@%+=:,./-]+$/,ed="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function ss(_){let L=mn({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},_);if($n(L.errors))return console.error(ed),console.error("Pass -- before a command that starts with dashes."),null;if(L.values.cwd!==void 0&&!Dh(L.values.cwd))return console.error(`Error: --cwd path does not exist: ${L.values.cwd}`),null;let G=L.positionals.length===1?L.positionals[0]:L.positionals.map((Y)=>Nh.test(Y)?Y:`'${Y.replaceAll("'","'\\''")}'`).join(" ");if(!G)return console.error("Error: No command provided"),console.error(ed),null;return{json:L.flags.json,cwd:L.values.cwd,command:G}}function nd(_){if(_)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 td(_,L){let Y=L-18;return[`${_.dtl}${_.dh.repeat(L)}${_.dtr}`,`${_.dv} Command Analysis${" ".repeat(Y)}${_.dv}`,`${_.dbl}${_.dh.repeat(L)}${_.dbr}`]}function as(_){return JSON.stringify(_)}function rd(_,L=0){return`[${_.map((Y,Z)=>ka(Y,Z,L)).join(",")}]`}function fr(_,L,G=70){let Y=_.split(" "),Z=[],oe="";for(let se of Y)if(oe&&oe.length+se.length+1>G)Z.push(oe),oe=se;else oe=oe?`${oe} ${se}`:se;if(oe)Z.push(oe);return Z.map((se,fe)=>fe===0?se:`${L}${se}`)}function od(_,L,G){let Y=[];switch(_.type){case"parse":return null;case"env-strip":return Y.push(""),Y.push(`STEP ${L} ${G.h} Strip environment variables`),Y.push(` Removed: ${_.envVars.map((Z)=>`${Z}=<redacted>`).join(", ")}`),Y.push(` Tokens: ${as(_.output)}`),{lines:Y,incrementStep:!0};case"leading-tokens-stripped":return Y.push(""),Y.push(`STEP ${L} ${G.h} Strip wrappers`),Y.push(` Removed: ${_.removed.join(", ")}`),Y.push(` Tokens: ${as(_.output)}`),{lines:Y,incrementStep:!0};case"shell-wrapper":return Y.push(""),Y.push(`STEP ${L} ${G.h} Detect shell wrapper`),Y.push(` Wrapper: ${_.wrapper} -c`),Y.push(` Inner: ${_.innerCommand}`),{lines:Y,incrementStep:!0};case"interpreter":{if(Y.push(""),Y.push(`STEP ${L} ${G.h} Detect interpreter`),Y.push(` Interpreter: ${_.interpreter}`),Y.push(` Code: ${_.codeArg}`),_.paranoidBlocked)Y.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:Y,incrementStep:!0}}case"busybox":return Y.push(""),Y.push(`STEP ${L} ${G.h} Busybox wrapper`),Y.push(` Subcommand: ${_.subcommand}`),{lines:Y,incrementStep:!0};case"transparent-wrapper":return Y.push(""),Y.push(`STEP ${L} ${G.h} Transparent wrapper`),Y.push(` Wrapper: ${_.wrapper}`),Y.push(` Tokens: ${as(_.output)}`),{lines:Y,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(Y.push(""),Y.push(`STEP ${L} ${G.h} Match rules`),Y.push(` Rule: ${_.rule}()`),_.matched)Y.push(" Result: MATCHED");else Y.push(" Result: No match");return{lines:Y,incrementStep:!0}}case"worktree-relaxation":return Y.push(""),Y.push(`STEP ${L} ${G.h} Worktree relaxation`),Y.push(` Mode: ${n.worktree.name}`),Y.push(` Git cwd: ${_.gitCwd}`),Y.push(" Result: Allowed local discard in linked worktree"),{lines:Y,incrementStep:!0};case"temp-root-relaxation":return Y.push(""),Y.push(`STEP ${L} ${G.h} Temp-root relaxation`),Y.push(` Git cwd: ${_.gitCwd}`),Y.push(" Result: Allowed git discard in a temp-root repository"),{lines:Y,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(_.embeddedCommandFound)return Y.push(""),Y.push(`STEP ${L} ${G.h} Fallback scan`),Y.push(` Found: ${_.embeddedCommandFound}`),{lines:Y,incrementStep:!0};return null}case"custom-rules-check":{if(_.rulesChecked){if(Y.push(""),Y.push(`STEP ${L} ${G.h} Custom rules`),_.matched)Y.push(" Result: MATCHED");else Y.push(" Result: No match");return{lines:Y,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(_.matched)return Y.push(""),Y.push(`STEP ${L} ${G.h} Dangerous text check`),Y.push(` Token: ${_.token}`),Y.push(" Result: MATCHED"),{lines:Y,incrementStep:!0};return null}case"strict-unparseable":return Y.push(""),Y.push(`STEP ${L} ${G.h} Strict mode check`),Y.push(` Command: ${_.rawCommand}`),Y.push(" Result: ✗ UNPARSEABLE"),{lines:Y,incrementStep:!0};case"segment-skipped":return null;case"error":return Y.push(""),Y.push(`ERROR: ${_.message}`),{lines:Y,incrementStep:!1};default:return _}}function ls(_,L){let G=nd(L?.asciiOnly??!1),Y=58,Z=[],oe=1;Z.push(...td(G,58)),Z.push("");let se=_.trace.steps.find((Te)=>Te.type==="error");if(se&&se.type==="error"){Z.push("ERROR"),Z.push(` ${se.message}`),Z.push(""),Z.push("RESULT"),Z.push(` Status: ${_.result==="blocked"?en.red("BLOCKED"):en.green("ALLOWED")}`),Z.push(""),Z.push("CONFIG");let Te=_.configSource??"none";return Z.push(` Path: ${Te}`),Z.join(`
228
228
  `)}let fe=_.trace.steps.find((Te)=>Te.type==="parse");if(fe&&fe.type==="parse"){Z.push("INPUT"),Z.push(` ${fe.input}`),Z.push(""),Z.push(`STEP ${oe} ${G.h} Split shell commands`),oe++;for(let Te=0;Te<fe.segments.length;Te++){let Be=fe.segments[Te];if(Be){let Fe=Math.random();Z.push(` Segment ${Te+1}: ${rd(Be,Fe)}`)}}}let ge=_.trace.segments,Pe=ge.length>1;for(let Te of ge){if(Pe){Z.push("");let tn="";if(fe&&fe.type==="parse"){let Uo=fe.segments[Te.index];if(Uo)tn=Uo.join(" ")}let on=54,an=tn,nn=` Segment ${Te.index+1}: `,sn=" ";if(tn){if(nn.length+tn.length+sn.length>on){let lf=on-nn.length-sn.length;an=`${tn.substring(0,lf-1)}…`}}let Sn=tn?`${nn}${an}${sn}`:` Segment ${Te.index+1} `,sf=tn?`${nn}${en.cyan(an)}${sn}`:Sn,Vs=58-Sn.length,Ks=Math.floor(Vs/2),af=Vs-Ks;Z.push(`${G.sh.repeat(Ks)}${sf}${G.sh.repeat(af)}`)}if(Te.steps.find((tn)=>tn.type==="segment-skipped")){Z.push(""),Z.push(" (skipped — prior segment blocked)");continue}let Fe=!1,Ze=!1;for(let tn of Te.steps){let on=od(tn,oe,G);if(on){if(Ze=!0,tn.type==="recurse"){Z.push("");let an=" RECURSING ",nn=58-an.length-4;Z.push(` ${G.tl}${G.h}${an}${G.h.repeat(nn)}`),Z.push(` ${G.v}`),Fe=!0;continue}for(let an of on.lines)if(Fe)Z.push(` ${G.v} ${an}`);else Z.push(an);if(on.incrementStep)oe++}}if(Fe)Z.push(` ${G.v}`),Z.push(` ${G.bl}${G.h.repeat(56)}`);if(!Ze)Z.push(""),Z.push(` ${en.green("✓")} Allowed (no matching rules)`)}if(Z.push(""),Z.push("RESULT"),_.result==="blocked"){if(Z.push(` Status: ${en.red("BLOCKED")}`),_.customRule){if(Z.push(` Rule: ${_.customRule.id}`),_.customRule.rulebook)Z.push(` Rulebook: ${_.customRule.rulebook.name} ${_.customRule.rulebook.version}`);if(_.customRule.source)Z.push(` Source: ${_.customRule.source}`);if(_.customRule.override)Z.push(` Override: reason ${_.customRule.override.reason}`)}if(_.reason){let Te=fr(_.reason," ");Z.push(` Reason: ${Te[0]}`);for(let Be=1;Be<Te.length;Be++)Z.push(Te[Be]??"")}}else Z.push(` Status: ${en.green("ALLOWED")}`);Z.push(""),Z.push("CONFIG");let Ee=_.configSource??"none",Re=_.configValid?"":" (invalid)";Z.push(` Path: ${Ee}${Re}`);let Le=_.safetyPresetScope;Z.push(` Safety preset: ${_.selectedPreset??"standard"}${Le?` (${Or(Le)})`:""}`),Z.push(` Effective capabilities: ${_.effectiveLevel}`);let _e=Object.entries(_.destructiveCommandRuleOverrides??{});if(Z.push(` Rule customizations: ${_e.length}`),_.ruleActivation)Z.push(` Rule activation: ${_.ruleActivation.id} — ${_.ruleActivation.enabled?"on":"off"} via ${_.ruleActivation.source}`);return Z.join(`
229
- `)}function cs(_){return JSON.stringify(_,null,2)}import{resolve as Fh}from"node:path";var id=512,sd={maxTextLength:2048,maxListLength:128,maxObjectProperties:128,maxDepth:16},Lh=["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 ps(_){let L=0,G={allocateSegment(){return L++},getNextSegmentIndex(){return L},branch(){let Y=_.fork(),Z=ps(Y);return{trace:Z,adopt(){_.replaceSegmentEvents(Y.finish().events),L=Z.getNextSegmentIndex()}}},recordGlobal(Y){_.record({scope:"global",step:Y})},recordSegment(Y,Z=G.currentSegmentIndex){if(Z===void 0)return;_.record({scope:"segment",segmentIndex:Z,step:Y})}};return G}function fs(_=new Set){let L=[];return{record(G){if(L.length>=id)return;ho(G.step,_,sd),L.push({...G,step:ds(G.step,sd,_)})},fork(){return fs(_)},replaceSegmentEvents(G){L.splice(0,L.length,...[...L.filter((Y)=>Y.scope==="global"),...G].slice(0,id))},finish(){return{events:L}}}}function ho(_,L,G,Y=0,Z=new WeakSet){if(typeof _==="string"){let fe=_.slice(0,G.maxTextLength);if(!rt(fe))return;for(let ge of bt(fe))for(let Pe of ge.match(/[^\s"'()$]+/g)??[])L.add(ad(Pe));return}if(!_||typeof _!=="object"||Y>=G.maxDepth||Z.has(_))return;if(Z.add(_),Array.isArray(_)){let fe=Math.min(_.length,G.maxListLength);for(let ge=0;ge<fe;ge++)ho(_[ge],L,G,Y+1,Z);return}let oe=0,se=new Set;for(let fe in _){if(!Object.hasOwn(_,fe))continue;if(oe>=G.maxObjectProperties)break;oe++,ho(fe,L,G);let ge=us(fe,G,L);if(se.has(ge))continue;se.add(ge),ho(_[fe],L,G,Y+1,Z)}}function ds(_,L,G,Y=0,Z=new WeakSet){if(typeof _==="string")return us(_,L,G);if(!_||typeof _!=="object")return _;if(Y>=L.maxDepth)return;if(Z.has(_))return;if(Z.add(_),Array.isArray(_)){let fe=[],ge=Math.min(_.length,L.maxListLength);for(let Pe=0;Pe<ge;Pe++)fe.push(ds(_[Pe],L,G,Y+1,Z));return fe}let oe={},se=0;for(let fe in _){if(!Object.hasOwn(_,fe))continue;if(se>=L.maxObjectProperties)break;se++;let ge=us(fe,L,G);if(Object.hasOwn(oe,ge))continue;Object.defineProperty(oe,ge,{value:ds(_[fe],L,G,Y+1,Z),enumerable:!0,configurable:!0,writable:!0})}return oe}function us(_,L,G){let Y=_.slice(0,L.maxTextLength),Z=rt(Y)?nt(Y):Y,oe=G.size>0?Hh(Z,G):Z;return(jh(oe)?Me(oe):oe).slice(0,L.maxTextLength)}function jh(_){return _.includes("PRIVATE KEY")||_.includes("://")||_.includes("eyJ")||_.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(_)||_.length>=14&&Lh.some((L)=>_.includes(L))||_.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(_)}function Hh(_,L){return _.replace(/[^\s"'()$]+/g,(G)=>L.has(ad(G))?"<redacted>":G)}function ad(_){let L=2166136261,G=2166136261;for(let Y=0;Y<_.length;Y++)L=Math.imul(L^_.charCodeAt(Y),16777619),G=Math.imul(G^_.charCodeAt(_.length-Y-1),16777619);return`${L>>>0}:${G>>>0}:${_.length}`}function mr(_,L={},G){let Y=Fh(L.cwd??process.cwd()),Z=L.policySnapshot??R(G,{cwd:Y,userConfigDir:L.userConfigDir}),oe=P(Z.policy,G.env),se=qe({policySnapshot:Z,effectiveCapabilities:oe.capabilities,worktreeMode:oe.worktreeMode}),fe={effectiveLevel:se.effectiveLevel,selectedPreset:Z.policy.safety.level,...Z.policyScopes?{safetyPresetScope:Z.policyScopes.levelScope}:{},effectiveCapabilities:se.effectiveCapabilities,destructiveCommandRuleOverrides:Z.policy.destructiveCommandRuleOverrides},{configSource:ge,configValid:Pe}=Uh(G,{cwd:Y,userConfigDir:L.userConfigDir});if(!_||!_.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:ge,configValid:Pe,...fe};let Ee=y(_,"auto");if(Ee.status==="limited")throw new b;let Re=Ee.dialect==="powershell"?y(_,"posix"):Ee,Le=Rt(Re),_e=fs(),Te=ps(_e);Te.recordGlobal({type:"parse",input:_,segments:Le.map((Sn)=>[...Sn])});let Be=l("Bash",{command:_},{kind:"command",shell:"auto"},{configCwd:Y,executionCwd:Y},_),Fe=j(Be,{environment:G,trace:Te,dependencies:{loadPolicySnapshot:()=>Z}}),Ze=Fe.decision.kind==="deny"?Fe.decision:null;if(Ze&&(Fe.stage==="policy-protection"||Fe.stage==="secret-protection"))return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Mh(Ze),matched:!0,reason:Ze.reason}]}]},result:"blocked",reason:T(Ze.reason),segment:T(ld(Ze,_)),ruleId:T(Ze.ruleId),configSource:ge,configValid:Pe,...fe};let tn=Te.getNextSegmentIndex();if(Ze&&tn>0&&tn<Le.length)Te.recordSegment({type:"segment-skipped",index:tn,reason:"prior-segment-blocked"},tn);let on=_e.finish(),an=Ze?.ruleId??Gh(Be,Z,oe,G),nn=q.find((Sn)=>Sn.id===an&&Sn.activationCapability),sn=nn?se.policy.effectiveDestructiveCommandRules[nn.id]:void 0;return{trace:qh(on),result:Ze?"blocked":"allowed",reason:Ze?T(Ze.reason):void 0,segment:Ze?T(ld(Ze,_)):void 0,ruleId:Ze?T(Ze.ruleId):void 0,customRule:Bh(Vh(Ze?.ruleId,Z)),configSource:ge,configValid:Pe,...fe,...nn&&sn?{ruleActivation:{id:nn.id,...sn}}:{}}}function ld(_,L){return _.evidence?.segment??L}function Mh(_){if(_.reason===Je)return"policy-protection:findPolicyConfigMutationTargetInSemanticFacts";if(_.reason===Ke)return"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts";if(_.reason===v)return"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts";return"secret-protection:findSensitiveTargetInSemanticFacts"}function Uh(_,L){let G=I(L.cwd),Y=z(_,L),Z=Q(_,{cwd:L.cwd,userConfigDir:L.userConfigDir});try{if(r(Z.projectConfigTarget)!==null){if(Un(Z.projectConfigTarget).errors.length===0)return{configSource:G,configValid:!0};return{configSource:G,configValid:!1}}}catch(oe){if(oe instanceof o)return{configSource:G,configValid:!1};throw oe}try{if(r(Z.userConfigTarget)!==null){let oe=Un(Z.userConfigTarget);return{configSource:Y,configValid:oe.errors.length===0}}return{configSource:null,configValid:!0}}catch(oe){if(oe instanceof o)return{configSource:Y,configValid:!1};throw oe}}function Gh(_,L,G,Y){let Z=L.policy,oe=Ne({...Z,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...Z.destructiveCommandRuleOverrides,...Object.fromEntries(q.flatMap((fe)=>fe.activationCapability?[[fe.id,"on"]]:[]))}},L.state==="degraded"?{diagnostics:L.diagnostics,reason:L.reason}:void 0),se=j(_,{environment:Y,dependencies:{loadPolicySnapshot:()=>oe,getModes:()=>({...G,strict:!0,paranoidRm:!0,paranoidInterpreters:!0,capabilities:{fail_closed:{...G.capabilities.fail_closed,enabled:!0},paranoid_rm:{...G.capabilities.paranoid_rm,enabled:!0},paranoid_interpreters:{...G.capabilities.paranoid_interpreters,enabled:!0}}}),findSensitiveTarget:()=>null}});return se.decision.kind==="deny"?se.decision.ruleId:void 0}function Bh(_){if(!_)return;return{id:T(_.id),..._.rulebook?{rulebook:{name:T(_.rulebook.name),version:T(_.rulebook.version)}}:{},..._.source?{source:T(_.source)}:{},..._.override?{override:{type:"reason",reason:T(_.override.reason)}}:{}}}function qh(_){let L=_.events.flatMap((Y)=>Y.scope==="global"?[Y.step]:[]),G=new Map;for(let Y of _.events){if(Y.scope!=="segment")continue;let Z=G.get(Y.segmentIndex)??{index:Y.segmentIndex,steps:[]};Z.steps.push(Y.step),G.set(Y.segmentIndex,Z)}return{steps:L,segments:[...G.values()]}}function Vh(_,L){let G=_?.replace(/^custom\./,"");if(!G||!L.policy.rules.some((Y)=>Y.name===G))return;return L.ruleMetadata[G]??Object.freeze({id:G})}function cd(_){return new Promise((L)=>{process.stdout.write(`${_}
230
- `,()=>L())})}async function dd(_,L){let G=ss(L);if(!G)return 1;try{let Y=mr(G.command,{cwd:G.cwd},_),Z=!!process.env.NO_COLOR||!process.stdout.isTTY;return await cd(G.json?cs(Y):ls(Y,{asciiOnly:Z})),0}catch(Y){let Z=Kh(Y instanceof f?Y.cause:Y);if(Z===void 0)throw Y;if(G.json)return await cd(JSON.stringify({error:Z})),1;return console.error(Z),1}}function Kh(_){if(_ instanceof b)return _.message;if(_ instanceof U)return _.message;if(_ instanceof m)return _.message;if(_ instanceof s&&a[_.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var ud="2.6.13",Rn=" ",Pt="cc-safety-net";function pd(_){return _.argument?`${_.flags} ${_.argument}`:_.flags}function Jh(_){return Math.max(..._.map((L)=>pd(L).length))}function Wh(_){return Math.max(..._.map((L)=>L.usage.length))}function zh(_){return Math.max(..._.map((L)=>`${Pt} ${L.usage}`.length))}function Yh(_,L){let G=`${Pt} ${_.usage}`;return`${Rn}${G.padEnd(L+2)}${_.description}`}function An(_,L){return`${Rn}${_.padEnd(Math.max(40,_.length+2))}${L}`}function zt(_,L=console.log){let G=[];if(G.push(`${Pt} ${_.name}`),G.push(""),G.push(`${Rn}${_.description}`),G.push(""),G.push("USAGE:"),G.push(`${Rn}${Pt} ${_.usage}`),G.push(""),_.subcommands&&_.subcommands.length>0){G.push("SUBCOMMANDS:");let Y=Wh(_.subcommands);for(let Z of _.subcommands)G.push(`${Rn}${Z.usage.padEnd(Y+2)}${Z.description}`);G.push("")}if(_.options.length>0){G.push("OPTIONS:");let Y=Jh(_.options);for(let Z of _.options){let oe=pd(Z),se=Z.default?`${Z.description} (default: ${Z.default})`:Z.description;G.push(`${Rn}${oe.padEnd(Y+2)}${se}`)}G.push("")}if(_.examples&&_.examples.length>0){G.push("EXAMPLES:");for(let Y of _.examples)G.push(`${Rn}${Y}`)}L(G.join(`
229
+ `)}function cs(_){return JSON.stringify(_,null,2)}import{resolve as Fh}from"node:path";var id=512,sd={maxTextLength:2048,maxListLength:128,maxObjectProperties:128,maxDepth:16},Lh=["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 ps(_){let L=0,G={allocateSegment(){return L++},getNextSegmentIndex(){return L},branch(){let Y=_.fork(),Z=ps(Y);return{trace:Z,adopt(){_.replaceSegmentEvents(Y.finish().events),L=Z.getNextSegmentIndex()}}},recordGlobal(Y){_.record({scope:"global",step:Y})},recordSegment(Y,Z=G.currentSegmentIndex){if(Z===void 0)return;_.record({scope:"segment",segmentIndex:Z,step:Y})}};return G}function fs(_=new Set){let L=[];return{record(G){if(L.length>=id)return;ho(G.step,_,sd),L.push({...G,step:ds(G.step,sd,_)})},fork(){return fs(_)},replaceSegmentEvents(G){L.splice(0,L.length,...[...L.filter((Y)=>Y.scope==="global"),...G].slice(0,id))},finish(){return{events:L}}}}function ho(_,L,G,Y=0,Z=new WeakSet){if(typeof _==="string"){let fe=_.slice(0,G.maxTextLength);if(!rt(fe))return;for(let ge of bt(fe))for(let Pe of ge.match(/[^\s"'()$]+/g)??[])L.add(ad(Pe));return}if(!_||typeof _!=="object"||Y>=G.maxDepth||Z.has(_))return;if(Z.add(_),Array.isArray(_)){let fe=Math.min(_.length,G.maxListLength);for(let ge=0;ge<fe;ge++)ho(_[ge],L,G,Y+1,Z);return}let oe=0,se=new Set;for(let fe in _){if(!Object.hasOwn(_,fe))continue;if(oe>=G.maxObjectProperties)break;oe++,ho(fe,L,G);let ge=us(fe,G,L);if(se.has(ge))continue;se.add(ge),ho(_[fe],L,G,Y+1,Z)}}function ds(_,L,G,Y=0,Z=new WeakSet){if(typeof _==="string")return us(_,L,G);if(!_||typeof _!=="object")return _;if(Y>=L.maxDepth)return;if(Z.has(_))return;if(Z.add(_),Array.isArray(_)){let fe=[],ge=Math.min(_.length,L.maxListLength);for(let Pe=0;Pe<ge;Pe++)fe.push(ds(_[Pe],L,G,Y+1,Z));return fe}let oe={},se=0;for(let fe in _){if(!Object.hasOwn(_,fe))continue;if(se>=L.maxObjectProperties)break;se++;let ge=us(fe,L,G);if(Object.hasOwn(oe,ge))continue;Object.defineProperty(oe,ge,{value:ds(_[fe],L,G,Y+1,Z),enumerable:!0,configurable:!0,writable:!0})}return oe}function us(_,L,G){let Y=_.slice(0,L.maxTextLength),Z=rt(Y)?nt(Y):Y,oe=G.size>0?Hh(Z,G):Z;return(jh(oe)?Me(oe):oe).slice(0,L.maxTextLength)}function jh(_){return _.includes("PRIVATE KEY")||_.includes("://")||_.includes("eyJ")||_.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(_)||_.length>=14&&Lh.some((L)=>_.includes(L))||_.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(_)}function Hh(_,L){return _.replace(/[^\s"'()$]+/g,(G)=>L.has(ad(G))?"<redacted>":G)}function ad(_){let L=2166136261,G=2166136261;for(let Y=0;Y<_.length;Y++)L=Math.imul(L^_.charCodeAt(Y),16777619),G=Math.imul(G^_.charCodeAt(_.length-Y-1),16777619);return`${L>>>0}:${G>>>0}:${_.length}`}function mr(_,L={},G){let Y=Fh(L.cwd??process.cwd()),Z=L.policySnapshot??R(G,{cwd:Y,userConfigDir:L.userConfigDir}),oe=P(Z.policy,G.env),se=qe({policySnapshot:Z,effectiveCapabilities:oe.capabilities,worktreeMode:oe.worktreeMode}),fe={effectiveLevel:se.effectiveLevel,selectedPreset:Z.policy.safety.level,...Z.policyScopes?{safetyPresetScope:Z.policyScopes.levelScope}:{},effectiveCapabilities:se.effectiveCapabilities,destructiveCommandRuleOverrides:Z.policy.destructiveCommandRuleOverrides},{configSource:ge,configValid:Pe}=Uh(G,{cwd:Y,userConfigDir:L.userConfigDir});if(!_||!_.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:ge,configValid:Pe,...fe};let Ee=b(_,"auto");if(Ee.status==="limited")throw new x;let Re=Ee.dialect==="powershell"?b(_,"posix"):Ee,Le=Rt(Re),_e=fs(),Te=ps(_e);Te.recordGlobal({type:"parse",input:_,segments:Le.map((Sn)=>[...Sn])});let Be=l("Bash",{command:_},{kind:"command",shell:"auto"},{configCwd:Y,executionCwd:Y},_),Fe=j(Be,{environment:G,trace:Te,dependencies:{loadPolicySnapshot:()=>Z}}),Ze=Fe.decision.kind==="deny"?Fe.decision:null;if(Ze&&(Fe.stage==="policy-protection"||Fe.stage==="secret-protection"))return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Mh(Ze),matched:!0,reason:Ze.reason}]}]},result:"blocked",reason:T(Ze.reason),segment:T(ld(Ze,_)),ruleId:T(Ze.ruleId),configSource:ge,configValid:Pe,...fe};let tn=Te.getNextSegmentIndex();if(Ze&&tn>0&&tn<Le.length)Te.recordSegment({type:"segment-skipped",index:tn,reason:"prior-segment-blocked"},tn);let on=_e.finish(),an=Ze?.ruleId??Gh(Be,Z,oe,G),nn=q.find((Sn)=>Sn.id===an&&Sn.activationCapability),sn=nn?se.policy.effectiveDestructiveCommandRules[nn.id]:void 0;return{trace:qh(on),result:Ze?"blocked":"allowed",reason:Ze?T(Ze.reason):void 0,segment:Ze?T(ld(Ze,_)):void 0,ruleId:Ze?T(Ze.ruleId):void 0,customRule:Bh(Vh(Ze?.ruleId,Z)),configSource:ge,configValid:Pe,...fe,...nn&&sn?{ruleActivation:{id:nn.id,...sn}}:{}}}function ld(_,L){return _.evidence?.segment??L}function Mh(_){if(_.reason===Je)return"policy-protection:findPolicyConfigMutationTargetInSemanticFacts";if(_.reason===Ke)return"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts";if(_.reason===g)return"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts";return"secret-protection:findSensitiveTargetInSemanticFacts"}function Uh(_,L){let G=I(L.cwd),Y=z(_,L),Z=Q(_,{cwd:L.cwd,userConfigDir:L.userConfigDir});try{if(r(Z.projectConfigTarget)!==null){if(Un(Z.projectConfigTarget).errors.length===0)return{configSource:G,configValid:!0};return{configSource:G,configValid:!1}}}catch(oe){if(oe instanceof o)return{configSource:G,configValid:!1};throw oe}try{if(r(Z.userConfigTarget)!==null){let oe=Un(Z.userConfigTarget);return{configSource:Y,configValid:oe.errors.length===0}}return{configSource:null,configValid:!0}}catch(oe){if(oe instanceof o)return{configSource:Y,configValid:!1};throw oe}}function Gh(_,L,G,Y){let Z=L.policy,oe=Ne({...Z,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...Z.destructiveCommandRuleOverrides,...Object.fromEntries(q.flatMap((fe)=>fe.activationCapability?[[fe.id,"on"]]:[]))}},L.state==="degraded"?{diagnostics:L.diagnostics,reason:L.reason}:void 0),se=j(_,{environment:Y,dependencies:{loadPolicySnapshot:()=>oe,getModes:()=>({...G,strict:!0,paranoidRm:!0,paranoidInterpreters:!0,capabilities:{fail_closed:{...G.capabilities.fail_closed,enabled:!0},paranoid_rm:{...G.capabilities.paranoid_rm,enabled:!0},paranoid_interpreters:{...G.capabilities.paranoid_interpreters,enabled:!0}}}),findSensitiveTarget:()=>null}});return se.decision.kind==="deny"?se.decision.ruleId:void 0}function Bh(_){if(!_)return;return{id:T(_.id),..._.rulebook?{rulebook:{name:T(_.rulebook.name),version:T(_.rulebook.version)}}:{},..._.source?{source:T(_.source)}:{},..._.override?{override:{type:"reason",reason:T(_.override.reason)}}:{}}}function qh(_){let L=_.events.flatMap((Y)=>Y.scope==="global"?[Y.step]:[]),G=new Map;for(let Y of _.events){if(Y.scope!=="segment")continue;let Z=G.get(Y.segmentIndex)??{index:Y.segmentIndex,steps:[]};Z.steps.push(Y.step),G.set(Y.segmentIndex,Z)}return{steps:L,segments:[...G.values()]}}function Vh(_,L){let G=_?.replace(/^custom\./,"");if(!G||!L.policy.rules.some((Y)=>Y.name===G))return;return L.ruleMetadata[G]??Object.freeze({id:G})}function cd(_){return new Promise((L)=>{process.stdout.write(`${_}
230
+ `,()=>L())})}async function dd(_,L){let G=ss(L);if(!G)return 1;try{let Y=mr(G.command,{cwd:G.cwd},_),Z=!!process.env.NO_COLOR||!process.stdout.isTTY;return await cd(G.json?cs(Y):ls(Y,{asciiOnly:Z})),0}catch(Y){let Z=Kh(Y instanceof f?Y.cause:Y);if(Z===void 0)throw Y;if(G.json)return await cd(JSON.stringify({error:Z})),1;return console.error(Z),1}}function Kh(_){if(_ instanceof x)return _.message;if(_ instanceof U)return _.message;if(_ instanceof m)return _.message;if(_ instanceof s&&a[_.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var ud="2.6.15",Rn=" ",Pt="cc-safety-net";function pd(_){return _.argument?`${_.flags} ${_.argument}`:_.flags}function Jh(_){return Math.max(..._.map((L)=>pd(L).length))}function Wh(_){return Math.max(..._.map((L)=>L.usage.length))}function zh(_){return Math.max(..._.map((L)=>`${Pt} ${L.usage}`.length))}function Yh(_,L){let G=`${Pt} ${_.usage}`;return`${Rn}${G.padEnd(L+2)}${_.description}`}function An(_,L){return`${Rn}${_.padEnd(Math.max(40,_.length+2))}${L}`}function zt(_,L=console.log){let G=[];if(G.push(`${Pt} ${_.name}`),G.push(""),G.push(`${Rn}${_.description}`),G.push(""),G.push("USAGE:"),G.push(`${Rn}${Pt} ${_.usage}`),G.push(""),_.subcommands&&_.subcommands.length>0){G.push("SUBCOMMANDS:");let Y=Wh(_.subcommands);for(let Z of _.subcommands)G.push(`${Rn}${Z.usage.padEnd(Y+2)}${Z.description}`);G.push("")}if(_.options.length>0){G.push("OPTIONS:");let Y=Jh(_.options);for(let Z of _.options){let oe=pd(Z),se=Z.default?`${Z.description} (default: ${Z.default})`:Z.description;G.push(`${Rn}${oe.padEnd(Y+2)}${se}`)}G.push("")}if(_.examples&&_.examples.length>0){G.push("EXAMPLES:");for(let Y of _.examples)G.push(`${Rn}${Y}`)}L(G.join(`
231
231
  `))}function ms(){let _=zh(Tr),L=[];L.push(`${Pt} v${ud}`),L.push(""),L.push("Blocks destructive commands and secret access."),L.push(""),L.push("COMMANDS:");for(let G of Tr)L.push(Yh(G,_));L.push(""),L.push("GLOBAL OPTIONS:"),L.push(`${Rn}-h, --help Show help (use with command for command-specific help)`),L.push(`${Rn}-V, --version Show version`),L.push(""),L.push("HELP:"),L.push(`${Rn}${Pt} help <command> Show help for a specific command`),L.push(`${Rn}${Pt} <command> --help Show help for a specific command`),L.push(""),L.push("ENVIRONMENT VARIABLES:"),L.push(An(`${n.level.name}=standard|strict|paranoid`,"Set session safety level")),L.push(An(`${n.worktree.name}=1`,"Allow local git discards in linked worktrees")),L.push(An(`${n.debug.name}=1`,"Print diagnostic messages to stderr")),L.push(An(`${n.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),L.push(An(`${n.projectTightenOnly.name}=1`,"Ignore project policy settings that weaken the user policy")),L.push(An("CC_SAFETY_NET_HOME","Override rule config home directory")),L.push(""),L.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),L.push(An(`${n.strict.name}=1`,"Force safety.overrides.fail_closed on")),L.push(An(`${n.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),L.push(An(`${n.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),L.push(An(`${n.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),L.push(""),L.push("Documentation: https://ccsafetynet.com/docs"),console.log(L.join(`
232
232
  `))}function fd(){console.log(ud)}function gr(_,L=console.log){let G=Ir(_);if(!G)return!1;if(G.name.toLowerCase()!==_.toLowerCase())return!1;return zt(G,L),!0}import{existsSync as Po,readFileSync as bu}from"node:fs";import{join as So}from"node:path";import*as Vn from"node:readline";function Zh(_){return _==="install"?"Install":"Uninstall"}function Xh(_){return _==="install"?"Installing":"Uninstalling"}function Qh(_){return _==="install"?"into":"from"}function yd(_){return _?.available===!0}function ev(_,L){let G=new Set(L);return _.filter((Y)=>G.has(Y.target)).map((Y)=>Y.target)}function md(_,L,G){if(_.every((Y)=>!Y.available))return L;return Array.from({length:_.length},(Y,Z)=>Z+1).map((Y)=>(L+Y*G+_.length)%_.length).find((Y)=>yd(_[Y]))}function nv(_,L,G){if(G.ctrl&&G.name==="c")return"interrupt";if(G.name==="escape"||L==="q")return"abort";if(_==="install"&&(L==="u"||L==="U"))return"update";if(G.name==="up"||L==="k")return"up";if(G.name==="down"||L==="j")return"down";if(G.name==="space"||L===" ")return"toggle";if(G.name==="return"||G.name==="enter")return"confirm";return null}function tv(_){return{cursor:_.findIndex((L)=>L.available),selected:[]}}function rv(_,L,G){if(G==="confirm"||G==="update"||G==="abort"||G==="interrupt")return{state:_,done:G};if(G==="up")return{state:{..._,cursor:md(L,_.cursor,-1)}};if(G==="down")return{state:{..._,cursor:md(L,_.cursor,1)}};let Y=L[_.cursor];if(!yd(Y))return{state:_};let Z=_.selected.includes(Y.target)?_.selected.filter((oe)=>oe!==Y.target):ev(L,[..._.selected,Y.target]);return{state:{..._,selected:Z}}}var hd="◉",vd="◯",bd=">",wd=" ";function ov(_,L,G){return["",`${Zh(_)} CC Safety Net ${Qh(_)}:`,"",...L.map((Y,Z)=>{let oe=G.selected.includes(Y.target),se=Z===G.cursor,fe=oe?hd:vd,ge=se?bd:wd,Pe=Y.available?"":` (${Y.unavailableReason??"not installed"})`,Ee=`${fe} ${Y.label}${Pe}`,Re=!Y.available?en.dim(Ee):oe?en.green(Ee):se?en.bold(Ee):Ee;return`${ge} ${Re}`}),"",_==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":L.some((Y)=>Y.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${_}. q/Esc: close`].join(`
233
233
  `)}var gd=["global-hook","plugin"];function iv(_,L,G={}){let Y=G.color!==!1?en.bold:(oe)=>oe;return["","Install the Kimi Code integration as:","",...[`Global hook — ${L?"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((oe,se)=>{let fe=se===_,ge=`${fe?hd:vd} ${oe}`;return`${fe?bd:wd} ${fe?Y(ge):ge}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
@@ -277,9 +277,9 @@ Update available: cc-safety-net ${_e.currentVersion} → ${_e.latestVersion}. Up
277
277
  `)}),0}catch(Y){return console.error(br(Y)),1}}function br(_){let L=_ instanceof Error?_.message:String(_),G=typeof _==="object"&&_!==null&&"code"in _?_.code:null;if(G==="EACCES"||G==="EPERM")return`${L}
278
278
  Check file permissions for the target config file and parent directory.`;if(G==="ENOENT")return`${L}
279
279
  Check that the target config path and parent directory exist.`;if(G==="ENOTDIR")return`${L}
280
- Check that every parent path component is a directory.`;return L}import{mkdirSync as fb}from"node:fs";import{dirname as mb}from"node:path";import{createInterface as gb}from"node:readline";import{existsSync as Iu,readFileSync as lb}from"node:fs";function Ot(_,L){let G=ft(_,L);return{policy:G.policy,errors:ue(ut(G.issues,pt,(Y)=>Y.kind==="custom")," "," ")}}function kr(_,L){return Ot(_,L).errors}function Tu(_,L){return{"safety.level":_.safety.level,...Is("safety.overrides",_.safety.overrides),"workflow.worktree_mode":String(_.workflow.worktree_mode),"destructive_command_protection.enabled":String(_.destructive_command_protection.enabled),...Is("destructive_command_protection.overrides",_.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":As(_.destructive_command_protection.allow_paths),"secret_protection.enabled":String(_.secret_protection.enabled),...Is("secret_protection.overrides",_.secret_protection.overrides),"secret_protection.deny_paths":As(_.secret_protection.deny_paths),"secret_protection.allow_paths":As(_.secret_protection.allow_paths),...L?{"audit.retention_days":String(_.audit.retention_days)}:{}}}function Eo(_,L,G){let Y=Tu(_,G),Z=Tu(L,G);return[...new Set([...Object.keys(Y),...Object.keys(Z)])].flatMap((oe)=>Y[oe]===Z[oe]?[]:[{field:oe,before:Y[oe],after:Z[oe]}])}function Cr(_,L){let G=u(_,L);if(!Iu(G))return{baseline:k(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,_.home),diagnostics:[]};let Y=$t(G),Z=Ot(Y.value,_.home);return{baseline:Z.policy,diagnostics:Y.errors.length>0?Y.errors:Z.errors}}function $t(_){if(!Iu(_))return{errors:[`${_}: file not found`]};try{return{value:JSON.parse(lb(_,"utf-8")),errors:[]}}catch(L){let G=L instanceof Error?L.message:String(L);return{errors:[`${_}: ${L instanceof SyntaxError?`Invalid JSON: ${G}`:G}`]}}}function Ro(_,L){let G=cb(_)?_:{};return{version:L.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((Y)=>G[Y]!==void 0).map((Y)=>[Y,G[Y]]))}}function Is(_,L){return Object.fromEntries(Object.entries(L).flatMap(([G,Y])=>Y===void 0?[]:[[`${_}.${G}`,String(Y)]]))}function As(_){return _.length===0?"(none)":_.join(", ")}function cb(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}import{chmodSync as db,existsSync as Au,mkdirSync as ub,readFileSync as Ou}from"node:fs";import{dirname as pb}from"node:path";function $u(_,L={}){let G=u(_,L);if(!Au(G))return{path:G,exists:!1,raw:"",policy:A(),errors:[]};let Y=Ou(G,"utf-8");if(!Y.trim())return{path:G,exists:!0,raw:Y,policy:A(),errors:["Config file is empty"]};try{let Z=Ot(JSON.parse(Y),_.home);return{path:G,exists:!0,raw:Y,policy:Z.policy,errors:Z.errors}}catch(Z){return{path:G,exists:!0,raw:Y,policy:A(),errors:[`Invalid JSON: ${Z instanceof Error?Z.message:String(Z)}`]}}}function Fn(_,L,G={}){let Y=u(_,G),Z=Ot(L,_.home);if(Z.errors.length>0)return{path:Y,policy:A(),errors:Z.errors};let oe=Z.policy;return ub(pb(Y),{recursive:!0,mode:448}),g(ae(Y),`${JSON.stringify(oe,null,2)}
281
- `,384),db(Y,384),{path:Y,policy:oe,errors:[]}}function Du(_,L){let G=Ot(L,_.home);if(G.errors.length>0)return{errors:G.errors};return{preview:We(G.policy,_.env),errors:[]}}function Nu(_,L={}){let G=u(_,L);if(!Au(G))return Fn(_,ne,L);let Y=Ou(G,"utf-8");if(!Y.trim())return Fn(_,ne,L);try{return Fn(_,k(JSON.parse(Y),_.home),L)}catch{return Fn(_,ne,L)}}var Lu=new Set(["check","apply"]),ju="(unset)";async function Fu(_,L,G={}){let Y=mn({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},L),Z=Y.positionals[0],oe=[...Y.errors,...Z&&!Lu.has(Z)?[`Unknown policy subcommand: ${Z}`]:[],...Z&&Lu.has(Z)&&!Y.positionals[1]?[`policy ${Z} requires a file`]:[],...Y.positionals.slice(2).map((Be)=>`Unexpected policy argument: ${Be}`)];if(oe.length>0){for(let Be of oe)console.error(Be);return 1}let se=Y.positionals[1];if(!Z||!se)return zt(_r,console.error),1;let fe=G.cwd??process.cwd(),ge=Y.flags.global?u(_):h(fe);if(!Y.flags.global&&O(_,{cwd:fe}))return console.error(`${ge} is the user policy, not a project policy; use --global for the user scope, or run from a project directory`),1;let Pe=$t(se),Ee=[...Pe.errors,...kr(Pe.value,_.home).map((Be)=>`${se}: ${Be}`),...!Y.flags.global&&vb(Pe.value)&&Pe.value.audit!==void 0?[`${se}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(Ee.length>0){for(let Be of Ee)console.error(Be);return 1}let Re=k(Pe.value,_.home);if(console.log(`Scope: ${Y.flags.global?"user":"project"} (${ge})`),console.log(`Proposal: ${se}`),Y.flags.global)Hu(k($t(ge).value,_.home),Re,!0);if(!Y.flags.global){let Be=Cr(_).baseline;console.log("Effective policy (user + project merged):"),Hu(te(Be,pe($t(ge).value,_.home).policy).policy,te(Be,pe(Pe.value,_.home).policy).policy,!1)}if(Z==="check")return 0;let Le=G.input??process.stdin,_e=G.output??process.stdout;if(!Le.isTTY||!_e.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${se}${Y.flags.global?" --global":""}`),1;if(!await yb(`Apply this policy to ${ge}? [y/N] `,Le,_e))return console.log("Cancelled; nothing was written."),0;return hb(_,ge,Pe.value,Re,Y.flags.global),console.log(`Policy applied: ${ge}`),0}function yb(_,L,G){let Y=gb({input:L,output:G,terminal:!1});return new Promise((Z)=>{Y.once("close",()=>Z(!1)),Y.question(_,(oe)=>{Z(/^y(es)?$/i.test(oe.trim())),Y.close()})})}function hb(_,L,G,Y,Z){if(Z){Fn(_,Y);return}fb(mb(L),{recursive:!0}),bn(L,Ro(G,Y))}function Hu(_,L,G){let Y=Eo(_,L,G);if(Y.length===0){console.log("No changes.");return}console.log(`Changes (${Y.length}):`);for(let Z of Y)console.log(` ${Z.field}: ${Z.before??ju} -> ${Z.after??ju}`)}function vb(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}import{join as Ow}from"node:path";var Mu="# 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- `caffeinate`, `exec`, `nice`, `nohup`, `setsid`, `stdbuf`, `time`, and `timeout` are built-in transparent wrappers and need no configuration. Configure only other 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- `command_tools`: Optional array of shell tools that a plugin adds to an agent and that CC Safety Net does not know. Each entry is a tool name such as `\"ops_bash\"`, or `{ \"name\": \"ops_run_background\", \"cwd\": \"cwd\" }` when the tool takes its working directory in a named argument (otherwise `workdir`, `cwd`, or `working_directory` is read). A call to a declared tool with a non-empty string `command` is analyzed like a built-in shell command. User and project lists merge; the user entry wins a name declared in both.\n- Built-in shell and file tools are already analyzed and cannot be declared; `rule verify` reports one declared by hand.\n- Use `cc-safety-net rule tool add ops_bash ops_run_background` to declare tools in the user config, or add `--project` for the project config.\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 _o(_,L){if(!_.ok){Ku(_);return}Bu(_,L)}function Gu(_,L,G){if(_.ok)console.log(G);if(!_.add){_o(_,`Added rulebook source: ${L}`);return}if(!_.ok){Ku(_);return}if(_.add.added.length>0)console.log(`Added ${_.add.added.length} ${_.add.added.length===1?"rulebook":"rulebooks"} from ${_.add.source} at ${_.add.ref}:`),_.add.added.forEach((Y)=>{console.log(` - ${Y}`)});if(_.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${_.add.source} at ${_.add.ref}: ${_.add.alreadyConfigured.join(", ")}`);if(_.add.commits.length>0)console.log(`Vendored at ${_.add.commits.map((Y)=>Y.slice(0,7)).join(", ")}.`);Bu(_,"Rule config updated.")}function Bu(_,L){for(let G of _.changes??[])console.log(G);console.log(L),console.log(""),bb(_.entries)}function bb(_){if(_.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${_.length}):`);for(let L of _)console.log(` - ${L.name} ${L.version} (${wb(L.ruleCount)})`),console.log(` Source: ${L.spec}`)}function wb(_){return`${_} ${_===1?"rule":"rules"}`}function qu(_){Wn("Active sources",_.rulebooks,(L)=>[`[${L.source}] ${L.name} ${L.version}`,` Source: ${L.spec}`]),Wn("Active rules",_.rules,(L)=>[`[${Cb(_,L.name)}] ${L.name}`,...kb(L),` Reason: ${L.reason}`]),Wn("Disabled rules",Uu(_,"off"),(L)=>[L.key]),Wn("Reason overrides",Uu(_,"reason"),(L)=>[L.key,` Reason: ${L.value.reason}`]),Wn("Transparent wrappers",_.transparent_wrappers,(L)=>[L]),Wn("Issues",_.errors,(L)=>[L]),Wn("Warnings",_.warnings,(L)=>[L])}function Vu(_){Wn("Command tools",_,(L)=>typeof L.tool==="string"?[`[${L.scope}] ${L.tool}`]:[`[${L.scope}] ${L.tool.name}`,...L.tool.cwd===void 0?[]:[` Cwd argument: ${L.tool.cwd}`]])}function Wn(_,L,G){if(L.length===0){console.log(`${_}: (none)`);return}console.log(`${_} (${L.length}):`);for(let Y of L){let[Z,...oe]=G(Y);console.log(` - ${Z}`);for(let se of oe)console.log(` ${se}`)}}function kb(_){if(!_.match)return[` Command: ${_.subcommand?`${_.command} ${_.subcommand}`:_.command}`,` Block args: ${_.block_args.join(", ")}`];return[` Command: ${[_.command,..._.match.command_path].join(" ")}`,..._.match.any_args?[` Any args: ${_.match.any_args.join(", ")}`]:[],..._.match.exclude_args?[` Exclude args: ${_.match.exclude_args.join(", ")}`]:[]]}function Cb(_,L){return _.rulebooks.find((G)=>G.rules.includes(L))?.source??"project"}function Uu(_,L){return Object.entries({..._.userConfig?.overrides,..._.projectConfig?.overrides}).filter((G)=>{if(L==="off")return G[1]==="off";return!!G[1]&&typeof G[1]==="object"}).map(([G,Y])=>({key:G,value:Y}))}function Ku(_){for(let L of _.errors)console.error(L)}import{dirname as gp,join as Lo}from"node:path";import{join as Ns,resolve as Db}from"node:path";function xr(_){let L=d(_);if(L.errors.length>0)return{ok:!1,result:{ok:!1,errors:L.errors,entries:[]}};return{ok:!0,config:L.config??le}}function Ju(_){bn(_,le)}function Wu(_){bn(_,{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 Oo}from"node:path";var xb="custom.";function To(_){if(_.rulebook_version!==2)return[];let L=_.rules.map((G)=>({name:G.name,command:G.command,block_args:[],match:G.match,reason:G.reason,intent:G.intent}));return(_.tests??[]).flatMap((G,Y)=>{let Z=Os(y(G.command));if(Z.length===0)return[`tests[${Y}]: could not parse fixture command: ${G.command}`];let oe=Z.reduce((se,fe)=>se??N(fe,L)?.id.slice(xb.length),void 0);if(G.expect==="blocked"){if(oe===G.rule)return[];let se=oe?`"${oe}" matched first`:"no rule matched";return[`tests[${Y}]: expected "${G.rule}" to block "${G.command}" but ${se}`]}return oe?[`tests[${Y}]: expected "${G.command}" to be allowed but "${oe}" matched`]:[]})}function Os(_){return _.nodes.flatMap((L)=>{if(L.kind==="group"||L.kind==="function")return Os(L.body);if(L.kind!=="command")return[];let G=Ce(re(L.dialect,L.words)).words.map(t);return[...G.length>0?[G]:[],...L.nested.flatMap((Y)=>Os(Y))]})}var Io=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Ao(_={}){return{requests:0,responseBytes:0,maxRequests:_.maxRequests??Io.maxRequests,maxResponseBytes:_.maxResponseBytes??Io.maxResponseBytes}}function Mn(_){return{controller:new AbortController,budget:Ao(),resolveUrl:_}}function zu(_){return _ instanceof Error&&_.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Yu(_){if(_.requests>=_.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");_.requests++}function Zu(_,L){if(L>_.maxResponseBytes-_.responseBytes)throw _.responseBytes+=L,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");_.responseBytes+=L}var ep=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Xu(_,L,G=w(Oo(Oo(L)),"rules policy"),Y=Mn()){if(C(_))return Rb(_,Y);return Eb(_,L,G)}async function np(_,L,G,Y,Z,oe){if(!C(_))return Xu(_,L,G,Y);let se=Z?null:Sb(_,L,G);if(se)return se;if(!Z&&!oe)throw Error(`${_} is not vendored; run rule update ${_} to vendor it`);return Xu(_,L,G,Y)}function Sb(_,L,G=w(Oo(Oo(L)),"rules policy")){let Y=M(_),Z=F(L,Y.name),oe=r(i(G,Z));if(oe===null)return null;let se=de($s(oe,`Invalid rulebook ${Z}.`));if(se.name!==Y.name)throw Error(`rulebook name "${se.name}" in ${Z} must match "${Y.name}"`);return{spec:_,rulebook:se,content:oe}}async function tp(_,L={}){if(!X(_))throw Error(`Invalid GitHub repository source: ${_}`);let[G,Y]=_.split("/");if(!G||!Y)throw Error(`Invalid GitHub repository source: ${_}`);if(L.ref!==void 0&&!ce(L.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${L.ref}`);let Z=L.operation??Mn(),oe=L.ref??await Pb(G,Y,_,Z),se=await op(G,Y,oe,_,Z),fe=await $o(`https://api.github.com/repos/${G}/${Y}/git/trees/${se}?recursive=1`,"tree",Z),ge=fe.response;if(!ge.ok)throw Error(`Failed to inspect ${_}: GitHub tree returned ${ge.status}`);let Pe=JSON.parse(fe.content);if(!Array.isArray(Pe?.tree))throw Error(`Failed to inspect ${_}: unexpected GitHub tree response`);let Ee=Pe.tree,Re=[...new Set(Ee.flatMap((Le)=>{if(!Le||typeof Le!=="object")return[];let _e=Le;if(_e.type!=="blob"||typeof _e.path!=="string")return[];let Te=_e.path.match(Et);return Te?.[1]?[Te[1]]:[]}))].sort();if(Re.length===0)throw Error(`No rulebooks found in ${_} under ${be}/`);return{source:_,owner:G,repo:Y,ref:oe,commit:se,names:Re}}async function Pb(_,L,G,Y){let Z=await $o(`https://api.github.com/repos/${_}/${L}`,"metadata",Y),oe=Z.response;if(!oe.ok)throw Error(`Failed to inspect ${G}: GitHub returned ${oe.status}`);let fe=JSON.parse(Z.content)?.default_branch;if(typeof fe!=="string"||fe==="")throw Error(`Failed to inspect ${G}: missing default branch`);if(!ce(fe))throw Error(`GitHub returned an invalid default branch: ${fe}`);return fe}function Eb(_,L,G){kt(_);let Y=F(L,_),Z=r(i(G,Y));if(Z===null)throw Error(`Rulebook source not found: ${_}`);let oe=rp($s(Z,"Invalid local rulebook source."));if(oe.name!==_)throw Error(`rulebook name "${oe.name}" must match local source "${_}"`);return{spec:_,rulebook:oe,content:Z}}async function Rb(_,L){let G=M(_),Y=await op(G.owner,G.repo,G.ref,_,L),Z=await $o(`https://raw.githubusercontent.com/${G.owner}/${G.repo}/${Y}/${G.path}`,"raw",L),oe=Z.response;if(!oe.ok)throw Error(`Failed to fetch ${_}: GitHub raw returned ${oe.status}`);let se=Z.content,fe=rp($s(se,"Invalid GitHub rulebook response."));if(fe.name!==G.name)throw Error(`rulebook name "${fe.name}" must match GitHub source "${G.name}"`);return{spec:_,rulebook:fe,content:se}}function rp(_){let L=de(_),G=To(L);if(G.length>0)throw Error(G.join("; "));return L}function $s(_,L){try{return JSON.parse(_)}catch{throw Error(L)}}async function op(_,L,G,Y,Z){let oe=await $o(`https://api.github.com/repos/${_}/${L}/commits/${encodeURIComponent(G)}`,"commit",Z),se=oe.response;if(!se.ok)throw Error(`Failed to resolve ${Y}: GitHub returned ${se.status}`);let fe=JSON.parse(oe.content);if(typeof fe?.sha!=="string"||fe.sha==="")throw Error(`Failed to resolve commit for ${Y}`);return fe.sha}async function _b(_,L,G={}){if(G.signal?.aborted)throw G.signal.reason;let Y=G.budget??Ao(),Z=new AbortController,oe=()=>Z.abort(G.signal?.reason);G.signal?.addEventListener("abort",oe,{once:!0});let se=!1,fe=setTimeout(()=>{if(Z.signal.aborted)return;se=!0,Z.abort()},G.timeoutMs??ep.timeoutMs);try{if(G.signal?.aborted)throw G.signal.reason;Yu(Y);let ge=await fetch(_,{signal:Z.signal,redirect:"error"});if(!ge.ok)return ip(ge),{response:ge,content:""};return{response:ge,content:await Tb(ge,L,Y,()=>Z.abort())}}catch(ge){if(se)throw Error("GitHub request timed out",{cause:ge});if(G.signal?.aborted)throw G.signal.reason;throw ge}finally{clearTimeout(fe),G.signal?.removeEventListener("abort",oe)}}function $o(_,L,G){return _b(G.resolveUrl?.(_)??_,L,{budget:G.budget,signal:G.controller.signal})}async function Tb(_,L,G=Ao(),Y){let Z=ep[`${L}Bytes`],oe=Number(_.headers.get("content-length"));if(Number.isFinite(oe)&&oe>Z)throw ip(_),Error(`GitHub ${L} response exceeds ${Z} bytes`);if(!_.body)return"";let se=_.body.getReader(),fe=[],ge=0;while(!0){let Pe=await se.read();if(Pe.done)break;try{Zu(G,Pe.value.byteLength)}catch(Ee){throw Y?.(),Qu(se),Ee}if(ge+=Pe.value.byteLength,ge>Z)throw Y?.(),Qu(se),Error(`GitHub ${L} response exceeds ${Z} bytes`);fe.push(Buffer.from(Pe.value))}return Buffer.concat(fe,ge).toString("utf-8")}function ip(_){if(!_.body)return;sp(()=>_.body?.cancel())}function Qu(_){sp(()=>_.cancel())}function sp(_){try{Promise.resolve(_()).catch(()=>{})}catch{}}var Ib=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function ap(_,L){let G=dp(_.rules,L);if(G.length>0)return{ok:!0,specs:G};return cp(_.rules,L)}function lp(_,L){let G=dp(_,L);if(G.length>0)return{ok:!0,specs:G};let Y=Ob(_,L);if(Y.length>0)return{ok:!0,specs:Y};let Z=$b(_,L);if(!Z.ok)return Z;if(Z.specs.length>0)return{ok:!0,specs:Z.specs};return cp(_,L)}function cp(_,L){let G=_.filter((Y)=>Ds(Y)?.name===L);if(G.length===1)return{ok:!0,specs:G};return Ab(L,G)}function Ab(_,L){return{ok:!1,result:{ok:!1,errors:L.length===0?[`No configured rulebook matches ${_}`]:[`Ambiguous rulebook match ${_}: ${L.join(", ")}`],entries:[]}}}function dp(_,L){return _.filter((G)=>G===L)}function Ob(_,L){let G=L.match(Ib),Y=G?.[1],Z=G?.[2],oe=G?.[3];if(!Y||!Z||!oe||!ce(oe))return[];return up(_,(se)=>se.owner===Y&&se.repo===Z&&se.ref===oe)}function $b(_,L){if(!X(L))return{ok:!0,specs:[]};let[G,Y]=L.split("/"),Z=up(_,(se)=>se.owner===G&&se.repo===Y);if(new Set(Z.map((se)=>Ds(se)?.ref).filter((se)=>!!se)).size<2)return{ok:!0,specs:Z};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${L}. Use an explicit ref:`,` cc-safety-net rule remove ${L}#<ref>`],entries:[]}}}function Ds(_){try{return M(_)}catch{return null}}function up(_,L){return _.filter((G)=>{let Y=Ds(G);return Y?L(Y):!1})}async function No(_,L={}){return Nb(_,L,await Do(_,L,Mn()))}function Nb(_,L,G){if(!G.ok)return G;let Y=hn(_,L),Z=[...new Set(V(Y.configPath,Y.filesystemScope))];if(Z.length===0)return G;return{ok:!1,errors:Z,entries:G.entries}}async function Do(_,L,G,Y={},Z=new Set,oe=new Set){try{let se=hn(_,L),fe=xr(se.configTarget);if(!fe.ok)return fe.result;let ge=fe.config,Pe=L.only?ap(ge,L.only):{ok:!0,specs:ge.rules};if(!Pe.ok)return Pe.result;let Ee=new Set([...L.refresh?Pe.specs:[],...Z]),Re=(nn)=>np(nn,se.configDir,se.filesystemScope,G,Ee.has(nn),!L.refresh||Ee.has(nn)),Le=await Vb(ge.rules,L.refresh?(nn)=>Re(nn).then((sn)=>({ok:!0,item:sn})).catch((sn)=>{if(zu(sn))throw sn;return{ok:!1,spec:nn,message:sn instanceof Error?sn.message:String(sn)}}):async(nn)=>({ok:!0,item:await Re(nn)}),G),_e=Le.filter((nn)=>!nn.ok),Te=Le.filter((nn)=>nn.ok).map((nn)=>nn.item),Be=Te.flatMap((nn)=>Lb(nn,ge.rules)),Fe=Te.flatMap((nn)=>jb(nn,oe,se)),Ze=new Set([...Be,...Fe].map((nn)=>nn.spec)),tn=[..._e,...Be,...Fe],on=[],an=Fb(on,()=>Te.flatMap((nn)=>Ze.has(nn.spec)||tn.length>0&&oe.has(nn.spec)?[]:Hb(nn,se,Y,on)));return{ok:tn.length===0,errors:tn.map((nn)=>`Failed to update ${nn.spec}: ${nn.message}`),entries:Te.map(Ub),changes:an}}catch(se){return Pr(se)}}function Lb(_,L){if(!C(_.spec))return[];let G=He(_.spec),Y=L.filter((Z)=>Z!==_.spec&&He(Z).toLowerCase()===G.toLowerCase());if(Y.length===0)return[];return[{ok:!1,spec:_.spec,message:`rulebook name "${G}" is also claimed by ${Y.join(", ")}; rename one of them`}]}function jb(_,L,G){if(!L.has(_.spec)||!C(_.spec))return[];let Y=F(G.configDir,_.rulebook.name),Z=r(i(G.filesystemScope,Y));if(Z===null||Z===_.content)return[];return[{ok:!1,spec:_.spec,message:`${Y} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Hb(_,L,G,Y){if(!C(_.spec))return[];let Z=F(L.configDir,_.rulebook.name),oe=i(L.filesystemScope,Z),se=r(oe);if(se===_.content)return[];return Y?.push({target:oe,previous:se}),g(oe,_.content,void 0,G._testAfterPolicyRename),Mb(_,se)}function Fb(_,L){try{return L()}catch(G){for(let Y of[..._].reverse()){if(Y.previous===null){B(Y.target);continue}g(Y.target,Y.previous)}throw G}}function Mb(_,L){if(L===null)return[`Vendored ${_.spec} (${_.rulebook.version})`];let G=we(L),Y="problem"in G?null:G.rulebook,Z=new Map(Y?.rules.map((se)=>[se.name,JSON.stringify(se)])??[]),oe=new Set(_.rulebook.rules.map((se)=>se.name));return[`Updated ${_.spec} (${Y?.version??"unreadable"} -> ${_.rulebook.version})`,...[...oe].filter((se)=>!Z.has(se)).map((se)=>` + ${se}`),...[...Z.keys()].filter((se)=>!oe.has(se)).map((se)=>` - ${se}`),..._.rulebook.rules.filter((se)=>{let fe=Z.get(se.name);return fe!==void 0&&fe!==JSON.stringify(se)}).map((se)=>` ~ ${se.name}`)]}function Ub(_){return{spec:_.spec,name:_.rulebook.name,version:_.rulebook.version,ruleCount:_.rulebook.rules.length}}async function pp(_,L,G={}){return Gb(_,L,G,Mn())}async function Gb(_,L,G,Y,Z={}){let oe=null,se=!1;try{let fe=hn(_,G),ge=r(fe.configTarget);oe={target:fe.configTarget,content:ge};let Pe=xr(fe.configTarget);if(!Pe.ok)return Pe.result;let Ee=Pe.config,Re=X(L)?await tp(L,{ref:G.ref,operation:Y}):null,Le=Re?Bb(Re,G.rulebooks):[],_e=Re?Le.map((tn)=>qb(Ee.rules,Re,tn)??`${L}#${Re.ref}/${tn}`):[L],Te=_e.filter((tn)=>!Ee.rules.includes(tn)),Be=[...Ee.rules,...Te];if(Be.length>xe)return Kb();if(Be.length!==Ee.rules.length)se=!0,bn(fe.configTarget,{...Ee,rules:Be},void 0,Z._testAfterPolicyRename);let Fe=await Do(_,G,Y,Z,new Set(Te),new Set(Te));if(!Fe.ok)Sr(fe.configTarget,ge);if(!Fe.ok||!Re)return Fe;let Ze=Le.filter((tn,on)=>Te.includes(_e[on]??""));return{...Fe,add:{source:L,ref:Re.ref,selected:Le,added:Ze,alreadyConfigured:Le.filter((tn)=>!Ze.includes(tn)),commits:Te.length>0?[Re.commit]:[]}}}catch(fe){if(se&&oe)try{Sr(oe.target,oe.content)}catch(ge){return Pr(ge)}return Pr(fe)}}function Bb(_,L){let G=L?[...new Set(L)]:_.names,Y=G.filter((Z)=>!_.names.includes(Z));if(Y.length>0)throw Error(`Rulebooks not found in ${_.source} at ${_.ref}: ${Y.join(", ")}
282
- Available rulebooks: ${_.names.join(", ")}`);return G}function qb(_,L,G){let Y=`${L.source}#${L.ref}/${G}`;if(_.includes(Y))return Y;let Z=`${L.source}#${L.commit}/${G}`;return _.find((oe)=>oe===Z)}async function Vb(_,L,G=Mn()){if(_.length>xe)throw Error(ve);let Y=[],Z=0,oe,se=Array.from({length:Math.min(_.length,Io.concurrency)},async()=>{while(!oe){let fe=Z;if(fe>=_.length)return;Z++;try{Y[fe]=await L(_[fe],fe,G.controller.signal)}catch(ge){if(!oe)oe={value:ge},Z=_.length,G.controller.abort(ge);return}}});if(await Promise.all(se),oe)throw oe.value;return Y}function Kb(){return{ok:!1,errors:[ve],entries:[]}}async function fp(_,L,G={}){try{return await Jb(_,L,G,{})}catch(Y){return Pr(Y)}}async function Jb(_,L,G,Y){let Z=hn(_,G),oe=d(Z.configTarget);if(oe.errors.length>0)return{ok:!1,errors:oe.errors,entries:[]};if(!oe.config)return{ok:!1,errors:[`No config found at ${Z.configPath}`],entries:[]};let se=lp(oe.config.rules,L);if(!se.ok)return se.result;let fe=G.deleteSource?Wb(Z.configDir,se.specs,Z.filesystemScope):{ok:!0,dirs:[]};if(!fe.ok)return fe.result;let ge=r(Z.configTarget);if(ge===null)return Pr(Error("Rules config is unavailable."));try{bn(Z.configTarget,{...oe.config,rules:oe.config.rules.filter((Re)=>!se.specs.includes(Re))},void 0,Y._testAfterPolicyRename)}catch(Re){throw Sr(Z.configTarget,ge),Re}let Pe=await Do(_,G,Mn(),Y);if(!Pe.ok)return Sr(Z.configTarget,ge),Pe;let Ee=zb(fe.dirs,Y,Z.filesystemScope);if(!Ee.ok){Sr(Z.configTarget,ge);let Re=await Do(_,G,Mn(),Y);if(!Re.ok)return{ok:!1,errors:[...Ee.result.errors,...Re.errors],entries:Re.entries};return Ee.result}return Pe}function Wb(_,L,G){let Y=L.flatMap((fe)=>p.test(fe)?[]:["--delete-source can only delete local rulebook sources"]),Z=L.map((fe)=>Ns(_,fe)),oe=Y.length>0?[]:Z.flatMap((fe)=>mp(fe,G)),se=[...Y,...oe];return se.length>0?{ok:!1,result:{ok:!1,errors:se,entries:[]}}:{ok:!0,dirs:Z}}function mp(_,L){let G=Db(_),Y=i(L,G),Z=he(Y);if(!Z)return[`Local rulebook source directory not found: ${_}`];let oe=Z.find((se)=>se.name==="rulebook.json");if(!oe)return[`Local rulebook source directory is missing rulebook.json: ${_}`];if(oe.kind!=="file")throw new o(L.label);if(r(i(L,Ns(G,"rulebook.json"))),Z.length>1)return[`Local rulebook source directory contains extra files: ${_}. delete manually if you really want to remove the directory.`];return[]}function zb(_,L,G){let Y=_.flatMap((Z)=>{try{if(!he(i(G,Z)))return[];let oe=mp(Z,G);if(oe.length>0)return oe;return Yb(Z,L,G),[]}catch(oe){return[`Failed to delete local rulebook source ${Z}: ${oe instanceof Error?oe.message:String(oe)}`]}});return Y.length>0?{ok:!1,result:{ok:!1,errors:Y,entries:[]}}:{ok:!0}}function Yb(_,L,G){if(L._testDeleteLocalSourceDir){L._testDeleteLocalSourceDir(_);return}B(i(G,Ns(_,ye))),Ct(i(G,_))}function Sr(_,L){if(L===null){B(_);return}g(_,L)}function Pr(_){return{ok:!1,errors:[_ instanceof Error?_.message:String(_)],entries:[]}}var Zb=".safety-net.json",Xb="~/.cc-safety-net/config.json";async function vp(_,L){let G=O(_,{cwd:L.cwd});if(G)console.log(`Skipped the project scope: ${I(L.cwd)} is the user rule config, not a project rule config`);return[G||await yp(_,{legacyPath:Lt(L.cwd),configPath:I(L.cwd),defaultRulebookName:"project-rules",migratedFrom:Zb,cleanup:L.cleanup,syncOptions:{cwd:L.cwd}}),await yp(_,{legacyPath:jt(_),configPath:z(_),defaultRulebookName:"user-rules",migratedFrom:Xb,cleanup:L.cleanup,syncOptions:{cwd:L.cwd,global:!0}})].every((Z)=>Z)?0:1}async function yp(_,L){let G=hn(_,L.syncOptions),Y=i(G.filesystemScope,L.legacyPath),Z=r(Y);if(Z===null)return console.log(`No legacy config found at ${L.legacyPath}`),!0;let oe=ew(Z);if(!oe.ok){for(let _e of oe.errors)console.error(_e);return!1}let se=d(G.configTarget);if(se.errors.length>0){for(let _e of se.errors)console.error(_e);return!1}let fe=se.config??le,ge=nw(gp(L.configPath),fe.rules,L.defaultRulebookName,L.migratedFrom,G.filesystemScope),Pe=Lo(gp(L.configPath),ge,"rulebook.json"),Ee=i(G.filesystemScope,Pe),Re=[hp(G.configTarget),hp(Ee)],Le=await Qb(_,L,G.configTarget,Ee,ge,oe.config.rules,{...fe,rules:fe.rules.includes(ge)?fe.rules:[...fe.rules,ge]});if(!Le.ok){ow(Re);for(let _e of Le.errors)console.error(_e);return!1}if(!L.cleanup)return console.log(`Migrated legacy config at ${L.legacyPath}. Legacy file is no longer used.`),!0;if(!rw(G.configTarget,Ee,ge,L.migratedFrom,oe.config.rules))return console.error(`Migration cleanup verification failed for ${L.legacyPath}`),!1;return B(Y),console.log(`Deleted legacy config at ${L.legacyPath}`),!0}async function Qb(_,L,G,Y,Z,oe,se){try{return bn(G,se),bn(Y,tw(Z,L.migratedFrom,oe)),await No(_,L.syncOptions)}catch(fe){return{ok:!1,errors:[fe instanceof Error?fe.message:String(fe)]}}}function ew(_){try{let L=JSON.parse(_),G=Wo(L);if(G.errors.length>0)return{ok:!1,errors:G.errors};return{ok:!0,config:{version:1,rules:L.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function nw(_,L,G,Y,Z){let oe=L.find((se)=>iw(i(Z,Lo(_,se,"rulebook.json")))===Y);if(oe)return oe;if(r(i(Z,Lo(_,G,"rulebook.json")))===null)return G;for(let se=2;;se++){let fe=`${G}-${se}`;if(r(i(Z,Lo(_,fe,"rulebook.json")))===null)return fe}}function tw(_,L,G){return{rulebook_version:1,name:_,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:L,allowed_commands:[...new Set(G.map((Y)=>Y.command))],rules:G,tests:G.map((Y)=>({command:[Y.command,Y.subcommand,Y.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:Y.name}))}}function rw(_,L,G,Y,Z){if(!d(_).config?.rules.includes(G))return!1;try{let se=r(L);if(se===null)return!1;let fe=JSON.parse(se);return fe.migrated_from===Y&&JSON.stringify(fe.rules)===JSON.stringify(Z)}catch{return!1}}function hp(_){return{target:_,content:r(_)}}function ow(_){for(let L of _){if(L.content===null){B(L.target);continue}g(L.target,L.content)}}function iw(_){let L=r(_);if(L===null)return null;try{let G=JSON.parse(L);return typeof G.migrated_from==="string"?G.migrated_from:null}catch{return null}}import{mkdir as sw,readFile as aw,writeFile as lw}from"node:fs/promises";import{dirname as cw,join as dw}from"node:path";var uw=86400000,pw=604800000;async function wp(_,L=Date.now()){if(_.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let G=tt(_);if(!G)return null;let Y=dw(G,".cc-safety-net","update-check.json"),Z=await fw(Y,L);if(!Z.lastCheck||L-Z.lastCheck>uw){let fe=await Gn();if(Z.lastCheck=L,fe.latestVersion)Z.latestVersion=fe.latestVersion;if(!await bp(Y,Z))return null;if(fe.error)return null}let oe=Z.latestVersion,se=pn();if(!oe||!ei(oe,se))return null;if(Z.notifiedVersion===oe&&Z.notifiedAt!==void 0&&L-Z.notifiedAt<pw)return null;if(Z.notifiedVersion=oe,Z.notifiedAt=L,!await bp(Y,Z))return null;return`UPDATE_AVAILABLE: cc-safety-net v${oe} is available (running v${se}). 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 fw(_,L){let G=await aw(_,"utf8").then((oe)=>JSON.parse(oe)).catch(()=>{return});if(!G||typeof G!=="object"||Array.isArray(G))return{};let Y=G,Z=(oe)=>typeof oe==="number"&&Number.isFinite(oe)&&oe<=L?oe:void 0;return{lastCheck:Z(Y.lastCheck),latestVersion:typeof Y.latestVersion==="string"?Y.latestVersion:void 0,notifiedVersion:typeof Y.notifiedVersion==="string"?Y.notifiedVersion:void 0,notifiedAt:Z(Y.notifiedAt)}}async function bp(_,L){return sw(cw(_),{recursive:!0,mode:448}).then(()=>lw(_,JSON.stringify(L),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as vw,resolve as Hs}from"node:path";var kp=new Map([["Bash","posix"],["PowerShell","powershell"],["Monitor","posix"]]);var Cp=new Map([["Bash","auto"]]);var xp=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);var Sp=new Map([["Shell","auto"]]);var Pp=new Map([["exec","auto"]]),Ep="write_to_process";var Rp=new Map([["Execute","auto"]]);var _p=new Map([["run_shell_command","auto"]]);var Tp=new Map([["run_terminal_command","auto"],["run_terminal_cmd","auto"],["monitor","auto"],["bash","auto"],["Shell","auto"]]);var Ip=new Map([["terminal","posix"]]);var Ap=new Map([["Bash","posix"]]);var Op="exec";var yw=[["antigravity-cli",[...tl.keys(),rl]],["claude-code",[...kp.keys()]],["codex",[...Cp.keys()]],["copilot-cli",[...xp.keys()]],["cursor",[...Sp.keys()]],["deepseek-harness",[...et.keys()]],["devin",[...Pp.keys(),Ep]],["droid",[...Rp.keys()]],["gemini-cli",[..._p.keys()]],["grok-build",[...Tp.keys()]],["hermes-agent",[...Ip.keys()]],["kimi-code",[...Ap.keys()]],["openclaw",[Op]],["opencode",[Ye,ke]],["pi",[...Qe.keys()]]].flatMap(([_,L])=>L.map((G)=>({name:G,integration:cn(_)}))),$p="and is already analyzed. Built-in tools cannot be declared.";function jo(_){let L=Ie(_),G=[...new Set(yw.filter((Y)=>Ie(Y.name)===L).map((Y)=>Y.integration))].sort((Y,Z)=>Y.localeCompare(Z));if(G.length>0)return`"${_}" is a built-in shell tool of ${hw(G)}, ${$p}`;if(x(_)!=="unknown")return`"${_}" is a built-in file tool, ${$p}`;return}function hw(_){return _.length===1?_[0]??"":`${_.slice(0,-1).join(", ")} and ${_.at(-1)}`}var Np="CC Safety Net Config",bw="═".repeat(Np.length),ww="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",kw=new Set(["rule.json","rule.lock","cache"]);function Lp(_,L={}){try{return Cw(_,L)}catch(G){if(G instanceof o)return console.error(G.message),1;throw G}}function Cw(_,L){let G=L.cwd??process.cwd(),Y=Q(_,{cwd:G}),Z=jt(_),oe=Lt(G),se=Hs(G,be),fe=i(Y.userScope,Z),ge=i(Y.projectScope,oe),Pe=!1,Ee=!1,Re=[],Le=[],_e=xw(i(Y.projectScope,se));if(Pw(),r(Y.userConfigTarget)!==null){let Te=Un(Y.userConfigTarget);if(Te.errors.push(...V(Y.userConfigPath,Y.userScope),...Dp(Y.userConfigTarget)),Re.push({scope:"User",path:Y.userConfigPath,result:Te,schema:"rules",target:Y.userConfigTarget}),Te.errors.length>0)Pe=!0}if(r(fe)!==null)if(Ee=!0,r(Y.userConfigTarget)!==null)Le.push(Ho("user","cleanup"));else{let Te=zo(fe);if(Re.push({scope:"User",path:Z,result:Te,schema:"legacy",inactive:!0,target:fe}),Le.push(Ho("user",Te.errors.length>0?"fix-or-delete":"migrate")),Te.errors.length>0)Pe=!0}if(r(Y.projectConfigTarget)!==null){let Te=Un(Y.projectConfigTarget);if(Te.errors.push(...V(Y.projectConfigPath,Y.projectScope),...Dp(Y.projectConfigTarget)),Re.push({scope:"Project",path:Hs(Y.projectConfigPath),result:Te,schema:"rules",target:Y.projectConfigTarget}),Te.errors.length>0)Pe=!0;if(r(ge)!==null)Ee=!0,Le.push(Ho("project","cleanup"))}else if(r(ge)!==null){Ee=!0,Pe=!0;let Te=zo(ge);Re.push({scope:"Project",path:Hs(oe),result:Te,schema:"legacy",inactive:!0,target:ge}),Le.push(Ho("project",Te.errors.length>0?"fix-or-delete":"migrate"))}if(_e?.result.errors.length)Pe=!0;if(Re.length===0&&!_e)return console.log(`
280
+ Check that every parent path component is a directory.`;return L}import{mkdirSync as fb}from"node:fs";import{dirname as mb}from"node:path";import{createInterface as gb}from"node:readline";import{existsSync as Iu,readFileSync as lb}from"node:fs";function Ot(_,L){let G=ft(_,L);return{policy:G.policy,errors:ue(ut(G.issues,pt,(Y)=>Y.kind==="custom")," "," ")}}function kr(_,L){return Ot(_,L).errors}function Tu(_,L){return{"safety.level":_.safety.level,...Is("safety.overrides",_.safety.overrides),"workflow.worktree_mode":String(_.workflow.worktree_mode),"destructive_command_protection.enabled":String(_.destructive_command_protection.enabled),...Is("destructive_command_protection.overrides",_.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":As(_.destructive_command_protection.allow_paths),"secret_protection.enabled":String(_.secret_protection.enabled),...Is("secret_protection.overrides",_.secret_protection.overrides),"secret_protection.deny_paths":As(_.secret_protection.deny_paths),"secret_protection.allow_paths":As(_.secret_protection.allow_paths),...L?{"audit.retention_days":String(_.audit.retention_days)}:{}}}function Eo(_,L,G){let Y=Tu(_,G),Z=Tu(L,G);return[...new Set([...Object.keys(Y),...Object.keys(Z)])].flatMap((oe)=>Y[oe]===Z[oe]?[]:[{field:oe,before:Y[oe],after:Z[oe]}])}function Cr(_,L){let G=u(_,L);if(!Iu(G))return{baseline:k(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,_.home),diagnostics:[]};let Y=$t(G),Z=Ot(Y.value,_.home);return{baseline:Z.policy,diagnostics:Y.errors.length>0?Y.errors:Z.errors}}function $t(_){if(!Iu(_))return{errors:[`${_}: file not found`]};try{return{value:JSON.parse(lb(_,"utf-8")),errors:[]}}catch(L){let G=L instanceof Error?L.message:String(L);return{errors:[`${_}: ${L instanceof SyntaxError?`Invalid JSON: ${G}`:G}`]}}}function Ro(_,L){let G=cb(_)?_:{};return{version:L.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((Y)=>G[Y]!==void 0).map((Y)=>[Y,G[Y]]))}}function Is(_,L){return Object.fromEntries(Object.entries(L).flatMap(([G,Y])=>Y===void 0?[]:[[`${_}.${G}`,String(Y)]]))}function As(_){return _.length===0?"(none)":_.join(", ")}function cb(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}import{chmodSync as db,existsSync as Au,mkdirSync as ub,readFileSync as Ou}from"node:fs";import{dirname as pb}from"node:path";function $u(_,L={}){let G=u(_,L);if(!Au(G))return{path:G,exists:!1,raw:"",policy:A(),errors:[]};let Y=Ou(G,"utf-8");if(!Y.trim())return{path:G,exists:!0,raw:Y,policy:A(),errors:["Config file is empty"]};try{let Z=Ot(JSON.parse(Y),_.home);return{path:G,exists:!0,raw:Y,policy:Z.policy,errors:Z.errors}}catch(Z){return{path:G,exists:!0,raw:Y,policy:A(),errors:[`Invalid JSON: ${Z instanceof Error?Z.message:String(Z)}`]}}}function Fn(_,L,G={}){let Y=u(_,G),Z=Ot(L,_.home);if(Z.errors.length>0)return{path:Y,policy:A(),errors:Z.errors};let oe=Z.policy;return ub(pb(Y),{recursive:!0,mode:448}),h(ae(Y),`${JSON.stringify(oe,null,2)}
281
+ `,384),db(Y,384),{path:Y,policy:oe,errors:[]}}function Du(_,L){let G=Ot(L,_.home);if(G.errors.length>0)return{errors:G.errors};return{preview:We(G.policy,_.env),errors:[]}}function Nu(_,L={}){let G=u(_,L);if(!Au(G))return Fn(_,ne,L);let Y=Ou(G,"utf-8");if(!Y.trim())return Fn(_,ne,L);try{return Fn(_,k(JSON.parse(Y),_.home),L)}catch{return Fn(_,ne,L)}}var Lu=new Set(["check","apply"]),ju="(unset)";async function Fu(_,L,G={}){let Y=mn({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},L),Z=Y.positionals[0],oe=[...Y.errors,...Z&&!Lu.has(Z)?[`Unknown policy subcommand: ${Z}`]:[],...Z&&Lu.has(Z)&&!Y.positionals[1]?[`policy ${Z} requires a file`]:[],...Y.positionals.slice(2).map((Be)=>`Unexpected policy argument: ${Be}`)];if(oe.length>0){for(let Be of oe)console.error(Be);return 1}let se=Y.positionals[1];if(!Z||!se)return zt(_r,console.error),1;let fe=G.cwd??process.cwd(),ge=Y.flags.global?u(_):y(fe);if(!Y.flags.global&&O(_,{cwd:fe}))return console.error(`${ge} is the user policy, not a project policy; use --global for the user scope, or run from a project directory`),1;let Pe=$t(se),Ee=[...Pe.errors,...kr(Pe.value,_.home).map((Be)=>`${se}: ${Be}`),...!Y.flags.global&&vb(Pe.value)&&Pe.value.audit!==void 0?[`${se}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(Ee.length>0){for(let Be of Ee)console.error(Be);return 1}let Re=k(Pe.value,_.home);if(console.log(`Scope: ${Y.flags.global?"user":"project"} (${ge})`),console.log(`Proposal: ${se}`),Y.flags.global)Hu(k($t(ge).value,_.home),Re,!0);if(!Y.flags.global){let Be=Cr(_).baseline;console.log("Effective policy (user + project merged):"),Hu(te(Be,pe($t(ge).value,_.home).policy).policy,te(Be,pe(Pe.value,_.home).policy).policy,!1)}if(Z==="check")return 0;let Le=G.input??process.stdin,_e=G.output??process.stdout;if(!Le.isTTY||!_e.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${se}${Y.flags.global?" --global":""}`),1;if(!await yb(`Apply this policy to ${ge}? [y/N] `,Le,_e))return console.log("Cancelled; nothing was written."),0;return hb(_,ge,Pe.value,Re,Y.flags.global),console.log(`Policy applied: ${ge}`),0}function yb(_,L,G){let Y=gb({input:L,output:G,terminal:!1});return new Promise((Z)=>{Y.once("close",()=>Z(!1)),Y.question(_,(oe)=>{Z(/^y(es)?$/i.test(oe.trim())),Y.close()})})}function hb(_,L,G,Y,Z){if(Z){Fn(_,Y);return}fb(mb(L),{recursive:!0}),bn(L,Ro(G,Y))}function Hu(_,L,G){let Y=Eo(_,L,G);if(Y.length===0){console.log("No changes.");return}console.log(`Changes (${Y.length}):`);for(let Z of Y)console.log(` ${Z.field}: ${Z.before??ju} -> ${Z.after??ju}`)}function vb(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}import{join as Ow}from"node:path";var Mu="# 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- `caffeinate`, `exec`, `nice`, `nohup`, `setsid`, `stdbuf`, `time`, and `timeout` are built-in transparent wrappers and need no configuration. Configure only other 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- `command_tools`: Optional array of shell tools that a plugin adds to an agent and that CC Safety Net does not know. Each entry is a tool name such as `\"ops_bash\"`, or `{ \"name\": \"ops_run_background\", \"cwd\": \"cwd\" }` when the tool takes its working directory in a named argument (otherwise `workdir`, `cwd`, or `working_directory` is read). A call to a declared tool with a non-empty string `command` is analyzed like a built-in shell command. User and project lists merge; the user entry wins a name declared in both.\n- Built-in shell and file tools are already analyzed and cannot be declared; `rule verify` reports one declared by hand.\n- Use `cc-safety-net rule tool add ops_bash ops_run_background` to declare tools in the user config, or add `--project` for the project config.\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 _o(_,L){if(!_.ok){Ku(_);return}Bu(_,L)}function Gu(_,L,G){if(_.ok)console.log(G);if(!_.add){_o(_,`Added rulebook source: ${L}`);return}if(!_.ok){Ku(_);return}if(_.add.added.length>0)console.log(`Added ${_.add.added.length} ${_.add.added.length===1?"rulebook":"rulebooks"} from ${_.add.source} at ${_.add.ref}:`),_.add.added.forEach((Y)=>{console.log(` - ${Y}`)});if(_.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${_.add.source} at ${_.add.ref}: ${_.add.alreadyConfigured.join(", ")}`);if(_.add.commits.length>0)console.log(`Vendored at ${_.add.commits.map((Y)=>Y.slice(0,7)).join(", ")}.`);Bu(_,"Rule config updated.")}function Bu(_,L){for(let G of _.changes??[])console.log(G);console.log(L),console.log(""),bb(_.entries)}function bb(_){if(_.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${_.length}):`);for(let L of _)console.log(` - ${L.name} ${L.version} (${wb(L.ruleCount)})`),console.log(` Source: ${L.spec}`)}function wb(_){return`${_} ${_===1?"rule":"rules"}`}function qu(_){Wn("Active sources",_.rulebooks,(L)=>[`[${L.source}] ${L.name} ${L.version}`,` Source: ${L.spec}`]),Wn("Active rules",_.rules,(L)=>[`[${Cb(_,L.name)}] ${L.name}`,...kb(L),` Reason: ${L.reason}`]),Wn("Disabled rules",Uu(_,"off"),(L)=>[L.key]),Wn("Reason overrides",Uu(_,"reason"),(L)=>[L.key,` Reason: ${L.value.reason}`]),Wn("Transparent wrappers",_.transparent_wrappers,(L)=>[L]),Wn("Issues",_.errors,(L)=>[L]),Wn("Warnings",_.warnings,(L)=>[L])}function Vu(_){Wn("Command tools",_,(L)=>typeof L.tool==="string"?[`[${L.scope}] ${L.tool}`]:[`[${L.scope}] ${L.tool.name}`,...L.tool.cwd===void 0?[]:[` Cwd argument: ${L.tool.cwd}`]])}function Wn(_,L,G){if(L.length===0){console.log(`${_}: (none)`);return}console.log(`${_} (${L.length}):`);for(let Y of L){let[Z,...oe]=G(Y);console.log(` - ${Z}`);for(let se of oe)console.log(` ${se}`)}}function kb(_){if(!_.match)return[` Command: ${_.subcommand?`${_.command} ${_.subcommand}`:_.command}`,` Block args: ${_.block_args.join(", ")}`];return[` Command: ${[_.command,..._.match.command_path].join(" ")}`,..._.match.any_args?[` Any args: ${_.match.any_args.join(", ")}`]:[],..._.match.exclude_args?[` Exclude args: ${_.match.exclude_args.join(", ")}`]:[]]}function Cb(_,L){return _.rulebooks.find((G)=>G.rules.includes(L))?.source??"project"}function Uu(_,L){return Object.entries({..._.userConfig?.overrides,..._.projectConfig?.overrides}).filter((G)=>{if(L==="off")return G[1]==="off";return!!G[1]&&typeof G[1]==="object"}).map(([G,Y])=>({key:G,value:Y}))}function Ku(_){for(let L of _.errors)console.error(L)}import{dirname as gp,join as Lo}from"node:path";import{join as Ns,resolve as Db}from"node:path";function xr(_){let L=d(_);if(L.errors.length>0)return{ok:!1,result:{ok:!1,errors:L.errors,entries:[]}};return{ok:!0,config:L.config??le}}function Ju(_){bn(_,le)}function Wu(_){bn(_,{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 Oo}from"node:path";var xb="custom.";function To(_){if(_.rulebook_version!==2)return[];let L=_.rules.map((G)=>({name:G.name,command:G.command,block_args:[],match:G.match,reason:G.reason,intent:G.intent}));return(_.tests??[]).flatMap((G,Y)=>{let Z=Os(b(G.command));if(Z.length===0)return[`tests[${Y}]: could not parse fixture command: ${G.command}`];let oe=Z.reduce((se,fe)=>se??N(fe,L)?.id.slice(xb.length),void 0);if(G.expect==="blocked"){if(oe===G.rule)return[];let se=oe?`"${oe}" matched first`:"no rule matched";return[`tests[${Y}]: expected "${G.rule}" to block "${G.command}" but ${se}`]}return oe?[`tests[${Y}]: expected "${G.command}" to be allowed but "${oe}" matched`]:[]})}function Os(_){return _.nodes.flatMap((L)=>{if(L.kind==="group"||L.kind==="function")return Os(L.body);if(L.kind!=="command")return[];let G=Ce(re(L.dialect,L.words)).words.map(t);return[...G.length>0?[G]:[],...L.nested.flatMap((Y)=>Os(Y))]})}var Io=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Ao(_={}){return{requests:0,responseBytes:0,maxRequests:_.maxRequests??Io.maxRequests,maxResponseBytes:_.maxResponseBytes??Io.maxResponseBytes}}function Mn(_){return{controller:new AbortController,budget:Ao(),resolveUrl:_}}function zu(_){return _ instanceof Error&&_.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Yu(_){if(_.requests>=_.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");_.requests++}function Zu(_,L){if(L>_.maxResponseBytes-_.responseBytes)throw _.responseBytes+=L,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");_.responseBytes+=L}var ep=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Xu(_,L,G=w(Oo(Oo(L)),"rules policy"),Y=Mn()){if(C(_))return Rb(_,Y);return Eb(_,L,G)}async function np(_,L,G,Y,Z,oe){if(!C(_))return Xu(_,L,G,Y);let se=Z?null:Sb(_,L,G);if(se)return se;if(!Z&&!oe)throw Error(`${_} is not vendored; run rule update ${_} to vendor it`);return Xu(_,L,G,Y)}function Sb(_,L,G=w(Oo(Oo(L)),"rules policy")){let Y=M(_),Z=F(L,Y.name),oe=r(i(G,Z));if(oe===null)return null;let se=de($s(oe,`Invalid rulebook ${Z}.`));if(se.name!==Y.name)throw Error(`rulebook name "${se.name}" in ${Z} must match "${Y.name}"`);return{spec:_,rulebook:se,content:oe}}async function tp(_,L={}){if(!X(_))throw Error(`Invalid GitHub repository source: ${_}`);let[G,Y]=_.split("/");if(!G||!Y)throw Error(`Invalid GitHub repository source: ${_}`);if(L.ref!==void 0&&!ce(L.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${L.ref}`);let Z=L.operation??Mn(),oe=L.ref??await Pb(G,Y,_,Z),se=await op(G,Y,oe,_,Z),fe=await $o(`https://api.github.com/repos/${G}/${Y}/git/trees/${se}?recursive=1`,"tree",Z),ge=fe.response;if(!ge.ok)throw Error(`Failed to inspect ${_}: GitHub tree returned ${ge.status}`);let Pe=JSON.parse(fe.content);if(!Array.isArray(Pe?.tree))throw Error(`Failed to inspect ${_}: unexpected GitHub tree response`);let Ee=Pe.tree,Re=[...new Set(Ee.flatMap((Le)=>{if(!Le||typeof Le!=="object")return[];let _e=Le;if(_e.type!=="blob"||typeof _e.path!=="string")return[];let Te=_e.path.match(Et);return Te?.[1]?[Te[1]]:[]}))].sort();if(Re.length===0)throw Error(`No rulebooks found in ${_} under ${be}/`);return{source:_,owner:G,repo:Y,ref:oe,commit:se,names:Re}}async function Pb(_,L,G,Y){let Z=await $o(`https://api.github.com/repos/${_}/${L}`,"metadata",Y),oe=Z.response;if(!oe.ok)throw Error(`Failed to inspect ${G}: GitHub returned ${oe.status}`);let fe=JSON.parse(Z.content)?.default_branch;if(typeof fe!=="string"||fe==="")throw Error(`Failed to inspect ${G}: missing default branch`);if(!ce(fe))throw Error(`GitHub returned an invalid default branch: ${fe}`);return fe}function Eb(_,L,G){kt(_);let Y=F(L,_),Z=r(i(G,Y));if(Z===null)throw Error(`Rulebook source not found: ${_}`);let oe=rp($s(Z,"Invalid local rulebook source."));if(oe.name!==_)throw Error(`rulebook name "${oe.name}" must match local source "${_}"`);return{spec:_,rulebook:oe,content:Z}}async function Rb(_,L){let G=M(_),Y=await op(G.owner,G.repo,G.ref,_,L),Z=await $o(`https://raw.githubusercontent.com/${G.owner}/${G.repo}/${Y}/${G.path}`,"raw",L),oe=Z.response;if(!oe.ok)throw Error(`Failed to fetch ${_}: GitHub raw returned ${oe.status}`);let se=Z.content,fe=rp($s(se,"Invalid GitHub rulebook response."));if(fe.name!==G.name)throw Error(`rulebook name "${fe.name}" must match GitHub source "${G.name}"`);return{spec:_,rulebook:fe,content:se}}function rp(_){let L=de(_),G=To(L);if(G.length>0)throw Error(G.join("; "));return L}function $s(_,L){try{return JSON.parse(_)}catch{throw Error(L)}}async function op(_,L,G,Y,Z){let oe=await $o(`https://api.github.com/repos/${_}/${L}/commits/${encodeURIComponent(G)}`,"commit",Z),se=oe.response;if(!se.ok)throw Error(`Failed to resolve ${Y}: GitHub returned ${se.status}`);let fe=JSON.parse(oe.content);if(typeof fe?.sha!=="string"||fe.sha==="")throw Error(`Failed to resolve commit for ${Y}`);return fe.sha}async function _b(_,L,G={}){if(G.signal?.aborted)throw G.signal.reason;let Y=G.budget??Ao(),Z=new AbortController,oe=()=>Z.abort(G.signal?.reason);G.signal?.addEventListener("abort",oe,{once:!0});let se=!1,fe=setTimeout(()=>{if(Z.signal.aborted)return;se=!0,Z.abort()},G.timeoutMs??ep.timeoutMs);try{if(G.signal?.aborted)throw G.signal.reason;Yu(Y);let ge=await fetch(_,{signal:Z.signal,redirect:"error"});if(!ge.ok)return ip(ge),{response:ge,content:""};return{response:ge,content:await Tb(ge,L,Y,()=>Z.abort())}}catch(ge){if(se)throw Error("GitHub request timed out",{cause:ge});if(G.signal?.aborted)throw G.signal.reason;throw ge}finally{clearTimeout(fe),G.signal?.removeEventListener("abort",oe)}}function $o(_,L,G){return _b(G.resolveUrl?.(_)??_,L,{budget:G.budget,signal:G.controller.signal})}async function Tb(_,L,G=Ao(),Y){let Z=ep[`${L}Bytes`],oe=Number(_.headers.get("content-length"));if(Number.isFinite(oe)&&oe>Z)throw ip(_),Error(`GitHub ${L} response exceeds ${Z} bytes`);if(!_.body)return"";let se=_.body.getReader(),fe=[],ge=0;while(!0){let Pe=await se.read();if(Pe.done)break;try{Zu(G,Pe.value.byteLength)}catch(Ee){throw Y?.(),Qu(se),Ee}if(ge+=Pe.value.byteLength,ge>Z)throw Y?.(),Qu(se),Error(`GitHub ${L} response exceeds ${Z} bytes`);fe.push(Buffer.from(Pe.value))}return Buffer.concat(fe,ge).toString("utf-8")}function ip(_){if(!_.body)return;sp(()=>_.body?.cancel())}function Qu(_){sp(()=>_.cancel())}function sp(_){try{Promise.resolve(_()).catch(()=>{})}catch{}}var Ib=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function ap(_,L){let G=dp(_.rules,L);if(G.length>0)return{ok:!0,specs:G};return cp(_.rules,L)}function lp(_,L){let G=dp(_,L);if(G.length>0)return{ok:!0,specs:G};let Y=Ob(_,L);if(Y.length>0)return{ok:!0,specs:Y};let Z=$b(_,L);if(!Z.ok)return Z;if(Z.specs.length>0)return{ok:!0,specs:Z.specs};return cp(_,L)}function cp(_,L){let G=_.filter((Y)=>Ds(Y)?.name===L);if(G.length===1)return{ok:!0,specs:G};return Ab(L,G)}function Ab(_,L){return{ok:!1,result:{ok:!1,errors:L.length===0?[`No configured rulebook matches ${_}`]:[`Ambiguous rulebook match ${_}: ${L.join(", ")}`],entries:[]}}}function dp(_,L){return _.filter((G)=>G===L)}function Ob(_,L){let G=L.match(Ib),Y=G?.[1],Z=G?.[2],oe=G?.[3];if(!Y||!Z||!oe||!ce(oe))return[];return up(_,(se)=>se.owner===Y&&se.repo===Z&&se.ref===oe)}function $b(_,L){if(!X(L))return{ok:!0,specs:[]};let[G,Y]=L.split("/"),Z=up(_,(se)=>se.owner===G&&se.repo===Y);if(new Set(Z.map((se)=>Ds(se)?.ref).filter((se)=>!!se)).size<2)return{ok:!0,specs:Z};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${L}. Use an explicit ref:`,` cc-safety-net rule remove ${L}#<ref>`],entries:[]}}}function Ds(_){try{return M(_)}catch{return null}}function up(_,L){return _.filter((G)=>{let Y=Ds(G);return Y?L(Y):!1})}async function No(_,L={}){return Nb(_,L,await Do(_,L,Mn()))}function Nb(_,L,G){if(!G.ok)return G;let Y=hn(_,L),Z=[...new Set(V(Y.configPath,Y.filesystemScope))];if(Z.length===0)return G;return{ok:!1,errors:Z,entries:G.entries}}async function Do(_,L,G,Y={},Z=new Set,oe=new Set){try{let se=hn(_,L),fe=xr(se.configTarget);if(!fe.ok)return fe.result;let ge=fe.config,Pe=L.only?ap(ge,L.only):{ok:!0,specs:ge.rules};if(!Pe.ok)return Pe.result;let Ee=new Set([...L.refresh?Pe.specs:[],...Z]),Re=(nn)=>np(nn,se.configDir,se.filesystemScope,G,Ee.has(nn),!L.refresh||Ee.has(nn)),Le=await Vb(ge.rules,L.refresh?(nn)=>Re(nn).then((sn)=>({ok:!0,item:sn})).catch((sn)=>{if(zu(sn))throw sn;return{ok:!1,spec:nn,message:sn instanceof Error?sn.message:String(sn)}}):async(nn)=>({ok:!0,item:await Re(nn)}),G),_e=Le.filter((nn)=>!nn.ok),Te=Le.filter((nn)=>nn.ok).map((nn)=>nn.item),Be=Te.flatMap((nn)=>Lb(nn,ge.rules)),Fe=Te.flatMap((nn)=>jb(nn,oe,se)),Ze=new Set([...Be,...Fe].map((nn)=>nn.spec)),tn=[..._e,...Be,...Fe],on=[],an=Fb(on,()=>Te.flatMap((nn)=>Ze.has(nn.spec)||tn.length>0&&oe.has(nn.spec)?[]:Hb(nn,se,Y,on)));return{ok:tn.length===0,errors:tn.map((nn)=>`Failed to update ${nn.spec}: ${nn.message}`),entries:Te.map(Ub),changes:an}}catch(se){return Pr(se)}}function Lb(_,L){if(!C(_.spec))return[];let G=He(_.spec),Y=L.filter((Z)=>Z!==_.spec&&He(Z).toLowerCase()===G.toLowerCase());if(Y.length===0)return[];return[{ok:!1,spec:_.spec,message:`rulebook name "${G}" is also claimed by ${Y.join(", ")}; rename one of them`}]}function jb(_,L,G){if(!L.has(_.spec)||!C(_.spec))return[];let Y=F(G.configDir,_.rulebook.name),Z=r(i(G.filesystemScope,Y));if(Z===null||Z===_.content)return[];return[{ok:!1,spec:_.spec,message:`${Y} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Hb(_,L,G,Y){if(!C(_.spec))return[];let Z=F(L.configDir,_.rulebook.name),oe=i(L.filesystemScope,Z),se=r(oe);if(se===_.content)return[];return Y?.push({target:oe,previous:se}),h(oe,_.content,void 0,G._testAfterPolicyRename),Mb(_,se)}function Fb(_,L){try{return L()}catch(G){for(let Y of[..._].reverse()){if(Y.previous===null){B(Y.target);continue}h(Y.target,Y.previous)}throw G}}function Mb(_,L){if(L===null)return[`Vendored ${_.spec} (${_.rulebook.version})`];let G=we(L),Y="problem"in G?null:G.rulebook,Z=new Map(Y?.rules.map((se)=>[se.name,JSON.stringify(se)])??[]),oe=new Set(_.rulebook.rules.map((se)=>se.name));return[`Updated ${_.spec} (${Y?.version??"unreadable"} -> ${_.rulebook.version})`,...[...oe].filter((se)=>!Z.has(se)).map((se)=>` + ${se}`),...[...Z.keys()].filter((se)=>!oe.has(se)).map((se)=>` - ${se}`),..._.rulebook.rules.filter((se)=>{let fe=Z.get(se.name);return fe!==void 0&&fe!==JSON.stringify(se)}).map((se)=>` ~ ${se.name}`)]}function Ub(_){return{spec:_.spec,name:_.rulebook.name,version:_.rulebook.version,ruleCount:_.rulebook.rules.length}}async function pp(_,L,G={}){return Gb(_,L,G,Mn())}async function Gb(_,L,G,Y,Z={}){let oe=null,se=!1;try{let fe=hn(_,G),ge=r(fe.configTarget);oe={target:fe.configTarget,content:ge};let Pe=xr(fe.configTarget);if(!Pe.ok)return Pe.result;let Ee=Pe.config,Re=X(L)?await tp(L,{ref:G.ref,operation:Y}):null,Le=Re?Bb(Re,G.rulebooks):[],_e=Re?Le.map((tn)=>qb(Ee.rules,Re,tn)??`${L}#${Re.ref}/${tn}`):[L],Te=_e.filter((tn)=>!Ee.rules.includes(tn)),Be=[...Ee.rules,...Te];if(Be.length>xe)return Kb();if(Be.length!==Ee.rules.length)se=!0,bn(fe.configTarget,{...Ee,rules:Be},void 0,Z._testAfterPolicyRename);let Fe=await Do(_,G,Y,Z,new Set(Te),new Set(Te));if(!Fe.ok)Sr(fe.configTarget,ge);if(!Fe.ok||!Re)return Fe;let Ze=Le.filter((tn,on)=>Te.includes(_e[on]??""));return{...Fe,add:{source:L,ref:Re.ref,selected:Le,added:Ze,alreadyConfigured:Le.filter((tn)=>!Ze.includes(tn)),commits:Te.length>0?[Re.commit]:[]}}}catch(fe){if(se&&oe)try{Sr(oe.target,oe.content)}catch(ge){return Pr(ge)}return Pr(fe)}}function Bb(_,L){let G=L?[...new Set(L)]:_.names,Y=G.filter((Z)=>!_.names.includes(Z));if(Y.length>0)throw Error(`Rulebooks not found in ${_.source} at ${_.ref}: ${Y.join(", ")}
282
+ Available rulebooks: ${_.names.join(", ")}`);return G}function qb(_,L,G){let Y=`${L.source}#${L.ref}/${G}`;if(_.includes(Y))return Y;let Z=`${L.source}#${L.commit}/${G}`;return _.find((oe)=>oe===Z)}async function Vb(_,L,G=Mn()){if(_.length>xe)throw Error(ve);let Y=[],Z=0,oe,se=Array.from({length:Math.min(_.length,Io.concurrency)},async()=>{while(!oe){let fe=Z;if(fe>=_.length)return;Z++;try{Y[fe]=await L(_[fe],fe,G.controller.signal)}catch(ge){if(!oe)oe={value:ge},Z=_.length,G.controller.abort(ge);return}}});if(await Promise.all(se),oe)throw oe.value;return Y}function Kb(){return{ok:!1,errors:[ve],entries:[]}}async function fp(_,L,G={}){try{return await Jb(_,L,G,{})}catch(Y){return Pr(Y)}}async function Jb(_,L,G,Y){let Z=hn(_,G),oe=d(Z.configTarget);if(oe.errors.length>0)return{ok:!1,errors:oe.errors,entries:[]};if(!oe.config)return{ok:!1,errors:[`No config found at ${Z.configPath}`],entries:[]};let se=lp(oe.config.rules,L);if(!se.ok)return se.result;let fe=G.deleteSource?Wb(Z.configDir,se.specs,Z.filesystemScope):{ok:!0,dirs:[]};if(!fe.ok)return fe.result;let ge=r(Z.configTarget);if(ge===null)return Pr(Error("Rules config is unavailable."));try{bn(Z.configTarget,{...oe.config,rules:oe.config.rules.filter((Re)=>!se.specs.includes(Re))},void 0,Y._testAfterPolicyRename)}catch(Re){throw Sr(Z.configTarget,ge),Re}let Pe=await Do(_,G,Mn(),Y);if(!Pe.ok)return Sr(Z.configTarget,ge),Pe;let Ee=zb(fe.dirs,Y,Z.filesystemScope);if(!Ee.ok){Sr(Z.configTarget,ge);let Re=await Do(_,G,Mn(),Y);if(!Re.ok)return{ok:!1,errors:[...Ee.result.errors,...Re.errors],entries:Re.entries};return Ee.result}return Pe}function Wb(_,L,G){let Y=L.flatMap((fe)=>p.test(fe)?[]:["--delete-source can only delete local rulebook sources"]),Z=L.map((fe)=>Ns(_,fe)),oe=Y.length>0?[]:Z.flatMap((fe)=>mp(fe,G)),se=[...Y,...oe];return se.length>0?{ok:!1,result:{ok:!1,errors:se,entries:[]}}:{ok:!0,dirs:Z}}function mp(_,L){let G=Db(_),Y=i(L,G),Z=he(Y);if(!Z)return[`Local rulebook source directory not found: ${_}`];let oe=Z.find((se)=>se.name==="rulebook.json");if(!oe)return[`Local rulebook source directory is missing rulebook.json: ${_}`];if(oe.kind!=="file")throw new o(L.label);if(r(i(L,Ns(G,"rulebook.json"))),Z.length>1)return[`Local rulebook source directory contains extra files: ${_}. delete manually if you really want to remove the directory.`];return[]}function zb(_,L,G){let Y=_.flatMap((Z)=>{try{if(!he(i(G,Z)))return[];let oe=mp(Z,G);if(oe.length>0)return oe;return Yb(Z,L,G),[]}catch(oe){return[`Failed to delete local rulebook source ${Z}: ${oe instanceof Error?oe.message:String(oe)}`]}});return Y.length>0?{ok:!1,result:{ok:!1,errors:Y,entries:[]}}:{ok:!0}}function Yb(_,L,G){if(L._testDeleteLocalSourceDir){L._testDeleteLocalSourceDir(_);return}B(i(G,Ns(_,ye))),Ct(i(G,_))}function Sr(_,L){if(L===null){B(_);return}h(_,L)}function Pr(_){return{ok:!1,errors:[_ instanceof Error?_.message:String(_)],entries:[]}}var Zb=".safety-net.json",Xb="~/.cc-safety-net/config.json";async function vp(_,L){let G=O(_,{cwd:L.cwd});if(G)console.log(`Skipped the project scope: ${I(L.cwd)} is the user rule config, not a project rule config`);return[G||await yp(_,{legacyPath:Lt(L.cwd),configPath:I(L.cwd),defaultRulebookName:"project-rules",migratedFrom:Zb,cleanup:L.cleanup,syncOptions:{cwd:L.cwd}}),await yp(_,{legacyPath:jt(_),configPath:z(_),defaultRulebookName:"user-rules",migratedFrom:Xb,cleanup:L.cleanup,syncOptions:{cwd:L.cwd,global:!0}})].every((Z)=>Z)?0:1}async function yp(_,L){let G=hn(_,L.syncOptions),Y=i(G.filesystemScope,L.legacyPath),Z=r(Y);if(Z===null)return console.log(`No legacy config found at ${L.legacyPath}`),!0;let oe=ew(Z);if(!oe.ok){for(let _e of oe.errors)console.error(_e);return!1}let se=d(G.configTarget);if(se.errors.length>0){for(let _e of se.errors)console.error(_e);return!1}let fe=se.config??le,ge=nw(gp(L.configPath),fe.rules,L.defaultRulebookName,L.migratedFrom,G.filesystemScope),Pe=Lo(gp(L.configPath),ge,"rulebook.json"),Ee=i(G.filesystemScope,Pe),Re=[hp(G.configTarget),hp(Ee)],Le=await Qb(_,L,G.configTarget,Ee,ge,oe.config.rules,{...fe,rules:fe.rules.includes(ge)?fe.rules:[...fe.rules,ge]});if(!Le.ok){ow(Re);for(let _e of Le.errors)console.error(_e);return!1}if(!L.cleanup)return console.log(`Migrated legacy config at ${L.legacyPath}. Legacy file is no longer used.`),!0;if(!rw(G.configTarget,Ee,ge,L.migratedFrom,oe.config.rules))return console.error(`Migration cleanup verification failed for ${L.legacyPath}`),!1;return B(Y),console.log(`Deleted legacy config at ${L.legacyPath}`),!0}async function Qb(_,L,G,Y,Z,oe,se){try{return bn(G,se),bn(Y,tw(Z,L.migratedFrom,oe)),await No(_,L.syncOptions)}catch(fe){return{ok:!1,errors:[fe instanceof Error?fe.message:String(fe)]}}}function ew(_){try{let L=JSON.parse(_),G=Wo(L);if(G.errors.length>0)return{ok:!1,errors:G.errors};return{ok:!0,config:{version:1,rules:L.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function nw(_,L,G,Y,Z){let oe=L.find((se)=>iw(i(Z,Lo(_,se,"rulebook.json")))===Y);if(oe)return oe;if(r(i(Z,Lo(_,G,"rulebook.json")))===null)return G;for(let se=2;;se++){let fe=`${G}-${se}`;if(r(i(Z,Lo(_,fe,"rulebook.json")))===null)return fe}}function tw(_,L,G){return{rulebook_version:1,name:_,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:L,allowed_commands:[...new Set(G.map((Y)=>Y.command))],rules:G,tests:G.map((Y)=>({command:[Y.command,Y.subcommand,Y.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:Y.name}))}}function rw(_,L,G,Y,Z){if(!d(_).config?.rules.includes(G))return!1;try{let se=r(L);if(se===null)return!1;let fe=JSON.parse(se);return fe.migrated_from===Y&&JSON.stringify(fe.rules)===JSON.stringify(Z)}catch{return!1}}function hp(_){return{target:_,content:r(_)}}function ow(_){for(let L of _){if(L.content===null){B(L.target);continue}h(L.target,L.content)}}function iw(_){let L=r(_);if(L===null)return null;try{let G=JSON.parse(L);return typeof G.migrated_from==="string"?G.migrated_from:null}catch{return null}}import{mkdir as sw,readFile as aw,writeFile as lw}from"node:fs/promises";import{dirname as cw,join as dw}from"node:path";var uw=86400000,pw=604800000;async function wp(_,L=Date.now()){if(_.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let G=tt(_);if(!G)return null;let Y=dw(G,".cc-safety-net","update-check.json"),Z=await fw(Y,L);if(!Z.lastCheck||L-Z.lastCheck>uw){let fe=await Gn();if(Z.lastCheck=L,fe.latestVersion)Z.latestVersion=fe.latestVersion;if(!await bp(Y,Z))return null;if(fe.error)return null}let oe=Z.latestVersion,se=pn();if(!oe||!ei(oe,se))return null;if(Z.notifiedVersion===oe&&Z.notifiedAt!==void 0&&L-Z.notifiedAt<pw)return null;if(Z.notifiedVersion=oe,Z.notifiedAt=L,!await bp(Y,Z))return null;return`UPDATE_AVAILABLE: cc-safety-net v${oe} is available (running v${se}). 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 fw(_,L){let G=await aw(_,"utf8").then((oe)=>JSON.parse(oe)).catch(()=>{return});if(!G||typeof G!=="object"||Array.isArray(G))return{};let Y=G,Z=(oe)=>typeof oe==="number"&&Number.isFinite(oe)&&oe<=L?oe:void 0;return{lastCheck:Z(Y.lastCheck),latestVersion:typeof Y.latestVersion==="string"?Y.latestVersion:void 0,notifiedVersion:typeof Y.notifiedVersion==="string"?Y.notifiedVersion:void 0,notifiedAt:Z(Y.notifiedAt)}}async function bp(_,L){return sw(cw(_),{recursive:!0,mode:448}).then(()=>lw(_,JSON.stringify(L),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as vw,resolve as Hs}from"node:path";var kp=new Map([["Bash","posix"],["PowerShell","powershell"],["Monitor","posix"]]);var Cp=new Map([["Bash","auto"]]);var xp=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);var Sp=new Map([["Shell","auto"]]);var Pp=new Map([["exec","auto"]]),Ep="write_to_process";var Rp=new Map([["Execute","auto"]]);var _p=new Map([["run_shell_command","auto"]]);var Tp=new Map([["run_terminal_command","auto"],["run_terminal_cmd","auto"],["monitor","auto"],["bash","auto"],["Shell","auto"]]);var Ip=new Map([["terminal","posix"]]);var Ap=new Map([["Bash","posix"]]);var Op="exec";var yw=[["antigravity-cli",[...tl.keys(),rl]],["claude-code",[...kp.keys()]],["codex",[...Cp.keys()]],["copilot-cli",[...xp.keys()]],["cursor",[...Sp.keys()]],["deepseek-harness",[...et.keys()]],["devin",[...Pp.keys(),Ep]],["droid",[...Rp.keys()]],["gemini-cli",[..._p.keys()]],["grok-build",[...Tp.keys()]],["hermes-agent",[...Ip.keys()]],["kimi-code",[...Ap.keys()]],["openclaw",[Op]],["opencode",[Ye,ke]],["pi",[...Qe.keys()]]].flatMap(([_,L])=>L.map((G)=>({name:G,integration:cn(_)}))),$p="and is already analyzed. Built-in tools cannot be declared.";function jo(_){let L=Ie(_),G=[...new Set(yw.filter((Y)=>Ie(Y.name)===L).map((Y)=>Y.integration))].sort((Y,Z)=>Y.localeCompare(Z));if(G.length>0)return`"${_}" is a built-in shell tool of ${hw(G)}, ${$p}`;if(v(_)!=="unknown")return`"${_}" is a built-in file tool, ${$p}`;return}function hw(_){return _.length===1?_[0]??"":`${_.slice(0,-1).join(", ")} and ${_.at(-1)}`}var Np="CC Safety Net Config",bw="═".repeat(Np.length),ww="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",kw=new Set(["rule.json","rule.lock","cache"]);function Lp(_,L={}){try{return Cw(_,L)}catch(G){if(G instanceof o)return console.error(G.message),1;throw G}}function Cw(_,L){let G=L.cwd??process.cwd(),Y=Q(_,{cwd:G}),Z=jt(_),oe=Lt(G),se=Hs(G,be),fe=i(Y.userScope,Z),ge=i(Y.projectScope,oe),Pe=!1,Ee=!1,Re=[],Le=[],_e=xw(i(Y.projectScope,se));if(Pw(),r(Y.userConfigTarget)!==null){let Te=Un(Y.userConfigTarget);if(Te.errors.push(...V(Y.userConfigPath,Y.userScope),...Dp(Y.userConfigTarget)),Re.push({scope:"User",path:Y.userConfigPath,result:Te,schema:"rules",target:Y.userConfigTarget}),Te.errors.length>0)Pe=!0}if(r(fe)!==null)if(Ee=!0,r(Y.userConfigTarget)!==null)Le.push(Ho("user","cleanup"));else{let Te=zo(fe);if(Re.push({scope:"User",path:Z,result:Te,schema:"legacy",inactive:!0,target:fe}),Le.push(Ho("user",Te.errors.length>0?"fix-or-delete":"migrate")),Te.errors.length>0)Pe=!0}if(r(Y.projectConfigTarget)!==null){let Te=Un(Y.projectConfigTarget);if(Te.errors.push(...V(Y.projectConfigPath,Y.projectScope),...Dp(Y.projectConfigTarget)),Re.push({scope:"Project",path:Hs(Y.projectConfigPath),result:Te,schema:"rules",target:Y.projectConfigTarget}),Te.errors.length>0)Pe=!0;if(r(ge)!==null)Ee=!0,Le.push(Ho("project","cleanup"))}else if(r(ge)!==null){Ee=!0,Pe=!0;let Te=zo(ge);Re.push({scope:"Project",path:Hs(oe),result:Te,schema:"legacy",inactive:!0,target:ge}),Le.push(Ho("project",Te.errors.length>0?"fix-or-delete":"migrate"))}if(_e?.result.errors.length)Pe=!0;if(Re.length===0&&!_e)return console.log(`
283
283
  No config files found. Using built-in rules only.`),0;for(let Te of Re)if(Te.inactive)Rw(Te.scope,Te.path,Te.result);else if(Te.result.errors.length>0)_w(Te.scope,Te.path,Te.result.errors);else{if(Te.schema==="rules"&&Aw(Te.target))console.log(`
284
284
  Added $schema to ${Te.scope.toLowerCase()} config.`);Ew(Te.scope,Te.path,Te.result,Te.schema)}for(let Te of Le)console.error(`
285
285
  ${en.red(Te)}`);if(_e)if(_e.result.errors.length>0)Iw(_e.path,_e.result.errors);else Tw(_e.path,_e.result);if(Pe)return console.error(`
@@ -289,7 +289,7 @@ All configs valid.`),0}function Dp(_){return(d(_).config?.command_tools??[]).fla
289
289
  ✓ ${_} config: ${L}`),console.log(` Schema: ${Y==="rules"?"rulebook sources":"legacy inline rules"}`),G.ruleNames.size>0){console.log(` ${Y==="rules"?"Sources":"Rules"}:`);let Z=1;for(let oe of G.ruleNames)console.log(` ${Z}. ${oe}`),Z++}else console.log(` ${Y==="rules"?"Sources":"Rules"}: (none)`)}function Rw(_,L,G){if(console.error(`
290
290
  ✗ Legacy ${_.toLowerCase()} config: ${L}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),G.errors.length>0){console.error(" Errors:");let Y=1;for(let Z of G.errors)for(let oe of Z.split("; "))console.error(` ${Y}. ${oe}`),Y++;return}if(G.ruleNames.size>0){console.error(" Rules:");let Y=1;for(let Z of G.ruleNames)console.error(` ${Y}. ${Z}`),Y++;return}console.error(" Rules: (none)")}function _w(_,L,G){jp(`${_} config`,L,G)}function Tw(_,L){console.log(`
291
291
  ✓ GitHub source rules: ${_}`),console.log(" Rulebooks:");let G=1;for(let Y of L.ruleNames)console.log(` ${G}. ${Y}`),G++}function Iw(_,L){jp("GitHub source rules",_,L)}function jp(_,L,G){console.error(`
292
- ✗ ${_}: ${L}`),console.error(" Errors:");let Y=1;for(let Z of G)for(let oe of Z.split("; "))console.error(` ${Y}. ${oe}`),Y++}function Aw(_){try{let L=r(_);if(L===null)return!1;let G=JSON.parse(L);if(G.$schema)return!1;return g(_,JSON.stringify({$schema:ww,...G},null,2)),!0}catch(L){if(L instanceof o)throw L;return!1}}var Hp=new Set(["init","add","remove","update","sync","list","wrapper","tool","migrate","doc","verify"]),$w=new Set(["init","add","remove","update","sync","wrapper"]),Mp=new Set(["add","remove","list"]),Dw="cc-safety-net/rulebooks";async function Up(_,L){try{return await Nw(_,L)}catch(G){if(G instanceof o)return console.error(G.message),1;throw G}}async function Nw(_,L){let G=jw(L),Y=G.help?Lw(G.positionals):null;if(Y)return zt(Y),0;if(G.errors.length>0){for(let Pe of G.errors)console.error(Pe);return 1}let Z=G.positionals[0];if(!Z)return zt(Nt,console.error),1;let oe=G.positionals[1],se={global:G.global},fe=process.cwd();if((Z==="tool"?G.project:!G.global&&$w.has(Z)&&!(Z==="wrapper"&&oe==="list"))&&O(_,{cwd:fe}))return console.error(`${I(fe)} is the user rule config, not a project rule config; ${Z==="tool"?"drop --project":"use --global"} for the user scope, or run from a project directory`),1;if(Z==="init"){let Pe=hn(_,se);Mw(Pe.configTarget);let Ee=Ow(Pe.configDir,"example-rules","rulebook.json"),Re=i(Pe.filesystemScope,Ee);if(G.example&&r(Re)===null)Wu(Re);let Le=V(Pe.configPath,Pe.filesystemScope);for(let _e of Le)console.error(_e);if(Le.length>0)return 1;return console.log("Rule config initialized."),0}if(Z==="add"){let Pe=Gp(G);if(!Pe)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let Ee=hn(_,se),Re=await pp(_,Pe,{...se,ref:G.ref,rulebooks:G.only.length>0?G.only:void 0});return Gu(Re,Pe,`Scope: ${G.global?"user":"project"} (${Ee.configDir})`),Re.ok?0:1}if(Z==="remove"){if(!oe)return console.error("rule remove requires a source"),1;let Pe=await fp(_,oe,{...se,deleteSource:G.deleteSource});return _o(Pe,`Removed rulebook source: ${oe}`),Pe.ok?0:1}if(Z==="update"){let Pe=await No(_,{...se,only:oe,refresh:!0});return _o(Pe,"Rule config updated."),Pe.ok?0:1}if(Z==="sync")return Wa(_,{global:G.global});if(Z==="list"){let Pe=ee(_,{cwd:fe});return qu(Pe),Pe.errors.length>0?1:0}if(Z==="wrapper")return Uw(_,G);if(Z==="tool")return Bw(_,G,fe);if(Z==="migrate")return vp(_,{cleanup:G.cleanup,cwd:fe});if(Z==="doc"){console.log(Mu);let Pe=await wp(_);if(Pe)console.error(Pe);return 0}if(Z==="verify")return Lp(_);return 1}function Lw(_){if(_.length===0)return Nt;let L=Nt.subcommands.filter((Y)=>Y.usage.split(" ")[0]===_[0]);if(L.length===0)return null;if(_.length===1&&L.length>1)return{name:`rule ${_[0]}`,description:`Subcommands of rule ${_[0]}`,usage:`rule ${_[0]} <subcommand>`,subcommands:L,options:[]};let G=_.length===1?L[0]:L.find((Y)=>Y.usage.split(" ")[1]===_[1]);if(!G)return null;return{name:`rule ${_[0]}`,description:G.description,usage:`rule ${G.usage}`,options:_[0]==="add"?Vo:[],examples:_[0]==="add"?Ko:void 0}}function jw(_){let L=mn({label:"rule",booleans:{global:["-g","--global"],project:["--project"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"],cwdArg:["--cwd-arg"]},lists:{only:["--only"]},positionals:"list"},_),G={...L.flags,ref:L.values.ref,cwdArg:L.values.cwdArg,only:L.lists.only??[],help:L.help,positionals:L.positionals,errors:L.errors};return Hw(G),G}function Hw(_){let[L]=_.positionals;if(L&&!Hp.has(L))_.errors.push(`Unknown rule subcommand: ${L}`);if(_.deleteSource&&L!=="remove")if(L&&Hp.has(L))_.errors.push(`Unknown option for rule ${L}: --delete-source`);else _.errors.push("--delete-source is only valid with 'rule remove'");if(_.cleanup&&L!=="migrate")_.errors.push(zn(L,"--cleanup"));if(_.example&&L!=="init")_.errors.push(zn(L,"--example"));if(_.ref&&L!=="add")_.errors.push(zn(L,"--ref"));if(_.only.length>0&&L!=="add")_.errors.push(zn(L,"--only"));let G=L==="tool"?_.positionals[1]:void 0,Y=G&&Mp.has(G)?`tool ${G}`:L;if(_.project&&G!=="add"&&G!=="remove")_.errors.push(zn(Y,"--project"));if(_.cwdArg!==void 0&&G!=="add")_.errors.push(zn(Y,"--cwd-arg"));if(L==="tool"&&_.global)_.errors.push(zn(L,"--global"));if(L==="add")Fw(_);if(L==="migrate"){if(_.global)_.errors.push(zn(L,"--global"));if(_.positionals.length>1)_.errors.push(`Unexpected rule migrate argument: ${_.positionals[1]}`)}else if(L==="wrapper")Fp(_,"a command");else if(L==="tool")Fp(_,"a tool name");else if(_.positionals.length>2)_.errors.push(`Unexpected rule argument: ${_.positionals[2]}`);if(L==="list"&&_.global)_.errors.push("Unknown option for rule list: --global")}function Gp(_){if(_.positionals[1])return _.positionals[1];if(_.ref||_.only.length>0)return Dw;return}function Fw(_){let L=Gp(_);if(!L)return;if((_.ref||_.only.length>0)&&!X(L)){if(_.ref)_.errors.push(`--ref can only select a ref for an owner/repo source: ${L}`);if(_.only.length>0)_.errors.push("--only can only select rulebooks from an owner/repo source");return}if(_.ref&&!ce(_.ref))_.errors.push(`--ref must use valid path segments: ${_.ref}`);let G=_.only.filter((Y)=>!p.test(Y));if(G.length>0)_.errors.push(`Invalid rulebook names: ${G.join(", ")}`)}function zn(_,L){return _?`Unknown option for rule ${_}: ${L}`:`Unknown option for rule: ${L}`}function Fp(_,L){let G=_.positionals[0],Y=_.positionals[1],Z=_.positionals[2];if(!Y){_.errors.push(`rule ${G} requires add, remove, or list`);return}if(!Mp.has(Y)){_.errors.push(`Unknown rule ${G} action: ${Y}`);return}if(Y==="list"){if(Z)_.errors.push(`Unexpected rule ${G} argument: ${Z}`);return}if(!Z){_.errors.push(`rule ${G} ${Y} requires ${L}`);return}if(G!=="tool"&&_.positionals.length>3)_.errors.push(`Unexpected rule ${G} argument: ${_.positionals[3]}`)}function Mw(_){if(r(_)===null){Ju(_);return}let L=d(_);if(!L.config)return;bn(_,L.config)}async function Uw(_,L){let G=L.positionals[1],Y=L.positionals[2],Z=hn(_,{global:L.global}).configTarget;if(G==="list"){let ge=d(Z);if(ge.errors.length>0){for(let Pe of ge.errors)console.error(Pe);return 1}return Gw(ge.config?.transparent_wrappers??[]),0}if(!Y||!E.test(Y))return console.error("transparent wrapper must match command pattern"),1;if($e(Y))return console.error(`reserved command "${Y}" cannot be a wrapper`),1;let oe=d(Z);if(oe.errors.length>0){for(let ge of oe.errors)console.error(ge);return 1}let se=oe.config??le,fe=G==="add"?[...new Set([...se.transparent_wrappers??[],Y])]:(se.transparent_wrappers??[]).filter((ge)=>ge!==Y);return bn(Z,{...se,transparent_wrappers:fe}),console.log(G==="add"?`Added transparent wrapper: ${Y}`:`Removed transparent wrapper: ${Y}`),0}function Gw(_){if(_.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${_.length}):`);for(let L of _)console.log(` - ${L}`)}function Bw(_,L,G){let Y=L.positionals[1],Z=[...new Set(L.positionals.slice(2))];if(Y==="list")return qw(_,G);let oe=[...Z.flatMap((Pe)=>{if(!je.test(Pe))return[`"${Pe}" is not a tool name: ${Se}.`];let Ee=Y==="add"?jo(Pe):void 0;return Ee?[Ee]:[]}),...L.cwdArg!==void 0&&!je.test(L.cwdArg)?[`"${L.cwdArg}" is not an argument name: ${Se}.`]:[]];if(oe.length>0){for(let Pe of oe)console.error(en.red(`Error: ${Pe}`));return 1}let se=hn(_,{global:!L.project}),fe=xr(se.configTarget);if(!fe.ok){for(let Pe of fe.result.errors)console.error(Pe);return 1}let ge=Z.reduce((Pe,Ee)=>{let Re=L.cwdArg===void 0?Ee:{name:Ee,cwd:L.cwdArg},Le=(_e)=>(typeof _e==="string"?_e:_e.name)===Ee;if(Y==="remove")return Pe.filter((_e)=>!Le(_e));return Pe.some(Le)?Pe.map((_e)=>Le(_e)?Re:_e):[...Pe,Re]},fe.config.command_tools??[]);bn(se.configTarget,{...fe.config,command_tools:ge});for(let Pe of Z)console.log(Y==="add"?`Added command tool: ${Pe}${L.cwdArg===void 0?"":` (cwd argument: ${L.cwdArg})`}`:`Removed command tool: ${Pe}`);return console.log(`Scope: ${L.project?"project":"user"} (${se.configPath})`),0}function qw(_,L){let G=(O(_,{cwd:L})?["user"]:["user","project"]).map((Z)=>{let oe=hn(_,{global:Z==="user"});return{scope:Z,path:oe.configPath,...d(oe.configTarget)}}),Y=G.flatMap((Z)=>Z.errors.map((oe)=>`${Z.path}: ${oe}`));if(Y.length>0){for(let Z of Y)console.error(Z);return 1}return Vu(G.flatMap((Z)=>(Z.config?.command_tools??[]).map((oe)=>({scope:Z.scope,tool:oe})))),0}import{sep as Yw}from"node:path";import{existsSync as Vw,readFileSync as Kw}from"node:fs";import{join as Jw}from"node:path";async function Ww(_){if(_.isTTY)return null;return(await st(_).catch(()=>null))?.trim()||null}function zw(_){let L=_.env.get("CLAUDE_SETTINGS_PATH");if(L)return L;return Jw(Vr(_),"settings.json")}function Fs(_){let L=zw(_);if(!Vw(L))return!1;try{let G=Kw(L,"utf-8"),Y=JSON.parse(G);if(!Y.enabledPlugins)return!1;let Z="cc-safety-net@cc-marketplace";if(!(Z in Y.enabledPlugins))return!1;return Y.enabledPlugins[Z]===!0}catch(G){if(S(n.debug,_.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${L}: ${G instanceof Error?G.message:String(G)}`);return!1}}async function Ms(_,L=process.stdin){let G=Fs(_),Y;if(!G)Y="\uD83D\uDEE1️ CC Safety Net ❌";else{let oe=R(_,{cwd:process.cwd()}),se=oe.policy,fe=P(se,_.env),ge=Object.values(K(se,fe.capabilities)).some((Re)=>Re.changesInherited),Pe={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[ge?"custom":fe.effectiveLevel],Ee=oe.policyScopes&&!oe.policyScopes.weakeningsIgnored&&oe.policyScopes.weakenings.length>0?"\uD83D\uDD3B":"";Y=`\uD83D\uDEE1️ CC Safety Net ${Pe}${fe.worktreeMode?"\uD83C\uDF33":""}${Ee}${oe.state==="degraded"?"⚠️":""}`}let Z=await Ww(L);if(Z&&!Z.startsWith("{"))console.log(`${Z} | ${Y}`);else console.log(Y)}function Bp(_){let L=R(_,{cwd:process.cwd()}),G=L.policy,Y=P(G,_.env),Z=!!process.env.NO_COLOR||!process.stdout.isTTY,oe=Math.min(process.stdout.columns||80,100),se=Z?"ok":"✔",fe=Z?"OFF":"✘",ge=(Be,Fe)=>{let Ze=` ${Be.padEnd(13)}${Fe}`;return(Ze.length>oe?`${Ze.slice(0,oe-1)}…`:Ze).replaceAll(fe,en.red(fe))},Pe=Object.values(K(G,Y.capabilities)).some((Be)=>Be.changesInherited),Ee=(Be)=>Be===_.home||Be.startsWith(`${_.home}${Yw}`)?`~${Be.slice(_.home.length)}`:Be,Re={ready:en.green,degraded:en.yellow}[L.state],Le=L.policyScopes?.weakenings??[],_e=[...Fs(_)?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...L.diagnostics],Te=Z?"-":"·";console.log([`${Z?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Re(L.state)}`,"",ge("Protection",`destructive ${G.destructiveCommandProtectionEnabled?se:fe} secrets ${G.secretProtection.enabled?se:fe}`),ge("Level",Pe?`${Y.effectiveLevel} (customised)`:Y.effectiveLevel),ge("Rules",G.rules.length===0?"none active":`${G.rules.length} active`),ge("Policy",Ee(u(_))),...L.policyScopes?[ge("Project",Ee(h(process.cwd())))]:[],...Y.worktreeMode?[ge("Worktree","relaxations active")]:[],"",...Le.length===0?[]:[L.policyScopes?.weakeningsIgnored?" Project policy (ignored)":" Project policy",...Le.flatMap((Be)=>fr(Be," ",oe-6).map((Fe,Ze)=>Ze===0?` ${Fe}`:Fe)),""],..._e.length===0?[" Everything configured is active."]:[" Not active",..._e.flatMap((Be)=>fr(Be," ",oe-6).map((Fe,Ze)=>Ze===0?` ${Te} ${Fe}`:Fe)),""," Full report: cc-safety-net doctor"]].join(`
292
+ ✗ ${_}: ${L}`),console.error(" Errors:");let Y=1;for(let Z of G)for(let oe of Z.split("; "))console.error(` ${Y}. ${oe}`),Y++}function Aw(_){try{let L=r(_);if(L===null)return!1;let G=JSON.parse(L);if(G.$schema)return!1;return h(_,JSON.stringify({$schema:ww,...G},null,2)),!0}catch(L){if(L instanceof o)throw L;return!1}}var Hp=new Set(["init","add","remove","update","sync","list","wrapper","tool","migrate","doc","verify"]),$w=new Set(["init","add","remove","update","sync","wrapper"]),Mp=new Set(["add","remove","list"]),Dw="cc-safety-net/rulebooks";async function Up(_,L){try{return await Nw(_,L)}catch(G){if(G instanceof o)return console.error(G.message),1;throw G}}async function Nw(_,L){let G=jw(L),Y=G.help?Lw(G.positionals):null;if(Y)return zt(Y),0;if(G.errors.length>0){for(let Pe of G.errors)console.error(Pe);return 1}let Z=G.positionals[0];if(!Z)return zt(Nt,console.error),1;let oe=G.positionals[1],se={global:G.global},fe=process.cwd();if((Z==="tool"?G.project:!G.global&&$w.has(Z)&&!(Z==="wrapper"&&oe==="list"))&&O(_,{cwd:fe}))return console.error(`${I(fe)} is the user rule config, not a project rule config; ${Z==="tool"?"drop --project":"use --global"} for the user scope, or run from a project directory`),1;if(Z==="init"){let Pe=hn(_,se);Mw(Pe.configTarget);let Ee=Ow(Pe.configDir,"example-rules","rulebook.json"),Re=i(Pe.filesystemScope,Ee);if(G.example&&r(Re)===null)Wu(Re);let Le=V(Pe.configPath,Pe.filesystemScope);for(let _e of Le)console.error(_e);if(Le.length>0)return 1;return console.log("Rule config initialized."),0}if(Z==="add"){let Pe=Gp(G);if(!Pe)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let Ee=hn(_,se),Re=await pp(_,Pe,{...se,ref:G.ref,rulebooks:G.only.length>0?G.only:void 0});return Gu(Re,Pe,`Scope: ${G.global?"user":"project"} (${Ee.configDir})`),Re.ok?0:1}if(Z==="remove"){if(!oe)return console.error("rule remove requires a source"),1;let Pe=await fp(_,oe,{...se,deleteSource:G.deleteSource});return _o(Pe,`Removed rulebook source: ${oe}`),Pe.ok?0:1}if(Z==="update"){let Pe=await No(_,{...se,only:oe,refresh:!0});return _o(Pe,"Rule config updated."),Pe.ok?0:1}if(Z==="sync")return Wa(_,{global:G.global});if(Z==="list"){let Pe=ee(_,{cwd:fe});return qu(Pe),Pe.errors.length>0?1:0}if(Z==="wrapper")return Uw(_,G);if(Z==="tool")return Bw(_,G,fe);if(Z==="migrate")return vp(_,{cleanup:G.cleanup,cwd:fe});if(Z==="doc"){console.log(Mu);let Pe=await wp(_);if(Pe)console.error(Pe);return 0}if(Z==="verify")return Lp(_);return 1}function Lw(_){if(_.length===0)return Nt;let L=Nt.subcommands.filter((Y)=>Y.usage.split(" ")[0]===_[0]);if(L.length===0)return null;if(_.length===1&&L.length>1)return{name:`rule ${_[0]}`,description:`Subcommands of rule ${_[0]}`,usage:`rule ${_[0]} <subcommand>`,subcommands:L,options:[]};let G=_.length===1?L[0]:L.find((Y)=>Y.usage.split(" ")[1]===_[1]);if(!G)return null;return{name:`rule ${_[0]}`,description:G.description,usage:`rule ${G.usage}`,options:_[0]==="add"?Vo:[],examples:_[0]==="add"?Ko:void 0}}function jw(_){let L=mn({label:"rule",booleans:{global:["-g","--global"],project:["--project"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"],cwdArg:["--cwd-arg"]},lists:{only:["--only"]},positionals:"list"},_),G={...L.flags,ref:L.values.ref,cwdArg:L.values.cwdArg,only:L.lists.only??[],help:L.help,positionals:L.positionals,errors:L.errors};return Hw(G),G}function Hw(_){let[L]=_.positionals;if(L&&!Hp.has(L))_.errors.push(`Unknown rule subcommand: ${L}`);if(_.deleteSource&&L!=="remove")if(L&&Hp.has(L))_.errors.push(`Unknown option for rule ${L}: --delete-source`);else _.errors.push("--delete-source is only valid with 'rule remove'");if(_.cleanup&&L!=="migrate")_.errors.push(zn(L,"--cleanup"));if(_.example&&L!=="init")_.errors.push(zn(L,"--example"));if(_.ref&&L!=="add")_.errors.push(zn(L,"--ref"));if(_.only.length>0&&L!=="add")_.errors.push(zn(L,"--only"));let G=L==="tool"?_.positionals[1]:void 0,Y=G&&Mp.has(G)?`tool ${G}`:L;if(_.project&&G!=="add"&&G!=="remove")_.errors.push(zn(Y,"--project"));if(_.cwdArg!==void 0&&G!=="add")_.errors.push(zn(Y,"--cwd-arg"));if(L==="tool"&&_.global)_.errors.push(zn(L,"--global"));if(L==="add")Fw(_);if(L==="migrate"){if(_.global)_.errors.push(zn(L,"--global"));if(_.positionals.length>1)_.errors.push(`Unexpected rule migrate argument: ${_.positionals[1]}`)}else if(L==="wrapper")Fp(_,"a command");else if(L==="tool")Fp(_,"a tool name");else if(_.positionals.length>2)_.errors.push(`Unexpected rule argument: ${_.positionals[2]}`);if(L==="list"&&_.global)_.errors.push("Unknown option for rule list: --global")}function Gp(_){if(_.positionals[1])return _.positionals[1];if(_.ref||_.only.length>0)return Dw;return}function Fw(_){let L=Gp(_);if(!L)return;if((_.ref||_.only.length>0)&&!X(L)){if(_.ref)_.errors.push(`--ref can only select a ref for an owner/repo source: ${L}`);if(_.only.length>0)_.errors.push("--only can only select rulebooks from an owner/repo source");return}if(_.ref&&!ce(_.ref))_.errors.push(`--ref must use valid path segments: ${_.ref}`);let G=_.only.filter((Y)=>!p.test(Y));if(G.length>0)_.errors.push(`Invalid rulebook names: ${G.join(", ")}`)}function zn(_,L){return _?`Unknown option for rule ${_}: ${L}`:`Unknown option for rule: ${L}`}function Fp(_,L){let G=_.positionals[0],Y=_.positionals[1],Z=_.positionals[2];if(!Y){_.errors.push(`rule ${G} requires add, remove, or list`);return}if(!Mp.has(Y)){_.errors.push(`Unknown rule ${G} action: ${Y}`);return}if(Y==="list"){if(Z)_.errors.push(`Unexpected rule ${G} argument: ${Z}`);return}if(!Z){_.errors.push(`rule ${G} ${Y} requires ${L}`);return}if(G!=="tool"&&_.positionals.length>3)_.errors.push(`Unexpected rule ${G} argument: ${_.positionals[3]}`)}function Mw(_){if(r(_)===null){Ju(_);return}let L=d(_);if(!L.config)return;bn(_,L.config)}async function Uw(_,L){let G=L.positionals[1],Y=L.positionals[2],Z=hn(_,{global:L.global}).configTarget;if(G==="list"){let ge=d(Z);if(ge.errors.length>0){for(let Pe of ge.errors)console.error(Pe);return 1}return Gw(ge.config?.transparent_wrappers??[]),0}if(!Y||!E.test(Y))return console.error("transparent wrapper must match command pattern"),1;if($e(Y))return console.error(`reserved command "${Y}" cannot be a wrapper`),1;let oe=d(Z);if(oe.errors.length>0){for(let ge of oe.errors)console.error(ge);return 1}let se=oe.config??le,fe=G==="add"?[...new Set([...se.transparent_wrappers??[],Y])]:(se.transparent_wrappers??[]).filter((ge)=>ge!==Y);return bn(Z,{...se,transparent_wrappers:fe}),console.log(G==="add"?`Added transparent wrapper: ${Y}`:`Removed transparent wrapper: ${Y}`),0}function Gw(_){if(_.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${_.length}):`);for(let L of _)console.log(` - ${L}`)}function Bw(_,L,G){let Y=L.positionals[1],Z=[...new Set(L.positionals.slice(2))];if(Y==="list")return qw(_,G);let oe=[...Z.flatMap((Pe)=>{if(!je.test(Pe))return[`"${Pe}" is not a tool name: ${Se}.`];let Ee=Y==="add"?jo(Pe):void 0;return Ee?[Ee]:[]}),...L.cwdArg!==void 0&&!je.test(L.cwdArg)?[`"${L.cwdArg}" is not an argument name: ${Se}.`]:[]];if(oe.length>0){for(let Pe of oe)console.error(en.red(`Error: ${Pe}`));return 1}let se=hn(_,{global:!L.project}),fe=xr(se.configTarget);if(!fe.ok){for(let Pe of fe.result.errors)console.error(Pe);return 1}let ge=Z.reduce((Pe,Ee)=>{let Re=L.cwdArg===void 0?Ee:{name:Ee,cwd:L.cwdArg},Le=(_e)=>(typeof _e==="string"?_e:_e.name)===Ee;if(Y==="remove")return Pe.filter((_e)=>!Le(_e));return Pe.some(Le)?Pe.map((_e)=>Le(_e)?Re:_e):[...Pe,Re]},fe.config.command_tools??[]);bn(se.configTarget,{...fe.config,command_tools:ge});for(let Pe of Z)console.log(Y==="add"?`Added command tool: ${Pe}${L.cwdArg===void 0?"":` (cwd argument: ${L.cwdArg})`}`:`Removed command tool: ${Pe}`);return console.log(`Scope: ${L.project?"project":"user"} (${se.configPath})`),0}function qw(_,L){let G=(O(_,{cwd:L})?["user"]:["user","project"]).map((Z)=>{let oe=hn(_,{global:Z==="user"});return{scope:Z,path:oe.configPath,...d(oe.configTarget)}}),Y=G.flatMap((Z)=>Z.errors.map((oe)=>`${Z.path}: ${oe}`));if(Y.length>0){for(let Z of Y)console.error(Z);return 1}return Vu(G.flatMap((Z)=>(Z.config?.command_tools??[]).map((oe)=>({scope:Z.scope,tool:oe})))),0}import{sep as Yw}from"node:path";import{existsSync as Vw,readFileSync as Kw}from"node:fs";import{join as Jw}from"node:path";async function Ww(_){if(_.isTTY)return null;return(await st(_).catch(()=>null))?.trim()||null}function zw(_){let L=_.env.get("CLAUDE_SETTINGS_PATH");if(L)return L;return Jw(Vr(_),"settings.json")}function Fs(_){let L=zw(_);if(!Vw(L))return!1;try{let G=Kw(L,"utf-8"),Y=JSON.parse(G);if(!Y.enabledPlugins)return!1;let Z="cc-safety-net@cc-marketplace";if(!(Z in Y.enabledPlugins))return!1;return Y.enabledPlugins[Z]===!0}catch(G){if(S(n.debug,_.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${L}: ${G instanceof Error?G.message:String(G)}`);return!1}}async function Ms(_,L=process.stdin){let G=Fs(_),Y;if(!G)Y="\uD83D\uDEE1️ CC Safety Net ❌";else{let oe=R(_,{cwd:process.cwd()}),se=oe.policy,fe=P(se,_.env),ge=Object.values(K(se,fe.capabilities)).some((Re)=>Re.changesInherited),Pe={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[ge?"custom":fe.effectiveLevel],Ee=oe.policyScopes&&!oe.policyScopes.weakeningsIgnored&&oe.policyScopes.weakenings.length>0?"\uD83D\uDD3B":"";Y=`\uD83D\uDEE1️ CC Safety Net ${Pe}${fe.worktreeMode?"\uD83C\uDF33":""}${Ee}${oe.state==="degraded"?"⚠️":""}`}let Z=await Ww(L);if(Z&&!Z.startsWith("{"))console.log(`${Z} | ${Y}`);else console.log(Y)}function Bp(_){let L=R(_,{cwd:process.cwd()}),G=L.policy,Y=P(G,_.env),Z=!!process.env.NO_COLOR||!process.stdout.isTTY,oe=Math.min(process.stdout.columns||80,100),se=Z?"ok":"✔",fe=Z?"OFF":"✘",ge=(Be,Fe)=>{let Ze=` ${Be.padEnd(13)}${Fe}`;return(Ze.length>oe?`${Ze.slice(0,oe-1)}…`:Ze).replaceAll(fe,en.red(fe))},Pe=Object.values(K(G,Y.capabilities)).some((Be)=>Be.changesInherited),Ee=(Be)=>Be===_.home||Be.startsWith(`${_.home}${Yw}`)?`~${Be.slice(_.home.length)}`:Be,Re={ready:en.green,degraded:en.yellow}[L.state],Le=L.policyScopes?.weakenings??[],_e=[...Fs(_)?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...L.diagnostics],Te=Z?"-":"·";console.log([`${Z?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Re(L.state)}`,"",ge("Protection",`destructive ${G.destructiveCommandProtectionEnabled?se:fe} secrets ${G.secretProtection.enabled?se:fe}`),ge("Level",Pe?`${Y.effectiveLevel} (customised)`:Y.effectiveLevel),ge("Rules",G.rules.length===0?"none active":`${G.rules.length} active`),ge("Policy",Ee(u(_))),...L.policyScopes?[ge("Project",Ee(y(process.cwd())))]:[],...Y.worktreeMode?[ge("Worktree","relaxations active")]:[],"",...Le.length===0?[]:[L.policyScopes?.weakeningsIgnored?" Project policy (ignored)":" Project policy",...Le.flatMap((Be)=>fr(Be," ",oe-6).map((Fe,Ze)=>Ze===0?` ${Fe}`:Fe)),""],..._e.length===0?[" Everything configured is active."]:[" Not active",..._e.flatMap((Be)=>fr(Be," ",oe-6).map((Fe,Ze)=>Ze===0?` ${Te} ${Fe}`:Fe)),""," Full report: cc-safety-net doctor"]].join(`
293
293
  `))}import{spawn as ef}from"node:child_process";import{randomBytes as sk}from"node:crypto";import{existsSync as ak}from"node:fs";import{createServer as lk}from"node:http";import{Writable as ck}from"node:stream";var Fo=500;function Zw(_){let L=_.filter((Z)=>Z.decision!=="allow"),G=_.filter((Z)=>Z.decision==="allow"),Y=Math.min(L.length,Math.max(Fo-G.length,Math.ceil(Fo/2)));return[...L.slice(0,Y),...G.slice(0,Fo-Y)]}function qp(_,L,G=H(_)){if(G)J(_,G);let Y=(Fe)=>new Date(Fe.getFullYear(),Fe.getMonth(),Fe.getDate()).getTime(),Z=Y(new Date),oe=new Date(Z);oe.setDate(oe.getDate()-(L-1));let se=oe.getTime(),fe=[],ge={count:0};for(let Fe of G?Yn(G,ge):[])for(let Ze of Dt(Fe,ge)){let tn=new Date(Ze.ts).getTime();if(!Number.isFinite(tn))continue;if(tn>=se)fe.push(Ze)}fe.sort((Fe,Ze)=>new Date(Ze.ts).getTime()-new Date(Fe.ts).getTime());let Pe=Array.from({length:L},()=>0),Ee=Array.from({length:L},()=>0),Re={},Le={},_e={},Te=0,Be=0;for(let Fe of fe){let Ze=Fe.agent||"unknown";Re[Ze]=(Re[Ze]??0)+1;let tn=Math.round((Z-Y(new Date(Fe.ts)))/86400000),on=L-1-tn,an=tn>=0&&tn<L;if(an)Ee[on]=(Ee[on]??0)+1;if(Fe.decision!=="allow"){if(Te++,Fe.ruleId)Le[Fe.ruleId]=(Le[Fe.ruleId]??0)+1;let nn=Go(Fe.segment||Fe.command);if(nn)_e[nn]=(_e[nn]??0)+1;if(Fe.failureStage)Be++;if(an)Pe[on]=(Pe[on]??0)+1}}return{days:L,logsDir:G,homeDir:_.home,totalInWindow:fe.length,truncated:fe.length>Fo,unreadable:ge.count,counts:{blocked:Te,allowed:fe.length-Te,agents:Re,blockedByDay:Pe,analyzedByDay:Ee,rules:Le,commands:_e,errors:Be},entries:Zw(fe).sort((Fe,Ze)=>new Date(Ze.ts).getTime()-new Date(Fe.ts).getTime())}}import{spawn as Xw}from"node:child_process";import{existsSync as Qw,statSync as Vp}from"node:fs";import{delimiter as ek,join as nk}from"node:path";var tk=120000,Mo="Choose the project folder",rk=`try
294
294
  return POSIX path of (choose folder with prompt "${Mo}")
295
295
  on error number -128
@@ -5720,6 +5720,6 @@ loadPolicy().then((loaded) => {
5720
5720
  </script>
5721
5721
  </body>
5722
5722
  </html>
5723
- `;var zp='<script id="ccsn-data" type="application/json">';function Yp(_,L=Wp){return L.replace(zp,()=>zp+JSON.stringify({token:_}).replaceAll("<","\\u003c"))}var qs="kenryu42/cc-safety-net",dk=`https://github.com/${qs}`,nf=1e4,uk=7,pk="The project draft directory changed; reload the draft before applying.",fk="audit settings are user scope only; remove the audit section from a project proposal";async function tf(_,L={}){let G=mn({label:"gui",booleans:{noOpen:["--no-open"]}},_),Y=L.log??console.log,Z=L.error??console.error;if(G.errors.length>0){for(let se of G.errors)Z(se);return Z("Usage: cc-safety-net gui [--no-open]"),1}let oe=await mk(c,L);if(Y(`CC Safety Net policy GUI: ${oe.url}`),!G.flags.noOpen)try{await(L.openBrowser??Pk)(oe.url)}catch(se){Z(`Failed to open browser: ${se instanceof Error?se.message:String(se)}`),Z(`Open this URL manually: ${oe.url}`)}if(L.keepAlive===!1)return await oe.close(),0;return await Sk(oe),0}async function mk(_,L={}){let G=sk(24).toString("base64url"),Y={dir:null,revision:0},Z=lk((fe,ge)=>{gk(_,fe,ge,G,L,Y)});await new Promise((fe,ge)=>{Z.once("error",ge),Z.listen(0,"127.0.0.1",()=>{Z.off("error",ge),fe()})});let se=`http://127.0.0.1:${Z.address().port}`;return{origin:se,token:G,url:`${se}/?token=${encodeURIComponent(G)}`,close:()=>xk(Z)}}async function gk(_,L,G,Y,Z,oe){let se=_(),fe=new URL(L.url??"/","http://127.0.0.1");if(L.method==="GET"&&fe.pathname==="/favicon.ico"){G.writeHead(204,{"cache-control":"no-store"}),G.end();return}if(!wk(L,fe,Y)){rn(G,403,{error:"Forbidden"});return}if(L.method==="GET"&&fe.pathname==="/"){await Promise.resolve(Z.buildDocument?.()).then((ge)=>Ck(G,Yp(Y,ge)),(ge)=>rn(G,500,{error:ge instanceof Error?ge.message:String(ge)}));return}if(L.method==="GET"&&fe.pathname==="/api/policy"){let ge=$u(se,Z),Pe=R(se,Bs(Z));rn(G,200,{...ge,configState:Ve(Pe),...Pe.policyScopes?{projectPolicy:{path:h(Z.cwd??process.cwd()),weakenings:Pe.policyScopes.weakeningsIgnored?[]:Pe.policyScopes.weakenings}}:{},destructiveCommandRules:q,secretPatterns:dt,version:pn(),preview:ge.errors.length>0?null:We(ge.policy,se.env)});return}if(L.method==="POST"&&fe.pathname==="/api/policy/preview"){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=Du(se,ge.value);rn(G,Pe.errors.length>0?400:200,Pe);return}if(L.method==="POST"&&fe.pathname==="/api/policy/explain"){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=ge.value;if(Pe===null||typeof Pe.command!=="string"){rn(G,400,{errors:["command must be a string"]});return}let Ee=kr(Pe.policy,se.home);if(Ee.length>0){rn(G,400,{errors:Ee});return}rn(G,200,vk(se,Pe.command,Pe.policy,Z));return}if(L.method==="POST"&&fe.pathname==="/api/policy"){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=Fn(se,ge.value,Z);rn(G,Pe.errors.length>0?400:200,Pe);return}if(L.method==="POST"&&fe.pathname==="/api/reset"){rn(G,200,Fn(se,ne,Z));return}if(L.method==="POST"&&fe.pathname==="/api/repair"){rn(G,200,Nu(se,Z));return}if(L.method==="POST"&&fe.pathname==="/api/policy/project/choose-directory"){let ge=await(Z.chooseDirectory??Gs)();if("path"in ge)oe.dir=ge.path,oe.revision+=1;rn(G,200,{cancelled:"cancelled"in ge,..."error"in ge?{error:ge.error}:{}});return}if(L.method==="GET"&&fe.pathname==="/api/policy/project"){let ge=rf(oe,Z),Pe=of(se,ge,Z),Ee=Pe?{projection:{},diagnostics:[Pe]}:Zp(ge,se.home),Re=Cr(se,Z);rn(G,200,{path:h(ge),revision:oe.revision,baseline:Re.baseline,userPolicyDiagnostics:Re.diagnostics,projection:Ee.projection,projectionDiagnostics:Ee.diagnostics,canPickDirectory:Us(process.platform,process.env)});return}if(L.method==="POST"&&fe.pathname==="/api/policy/project/diff"){let ge=await Xp(se,L,G,oe,Z);if(!ge)return;let Pe=Zp(ge.dir,se.home),Ee=Cr(se,Z).baseline,Re=te(Ee,pe(ge.proposal,se.home).policy);rn(G,200,{rows:Eo(te(Ee,Pe.projection).policy,Re.policy,!1),weakenings:Re.weakenings,existingFileDiagnostics:Pe.diagnostics});return}if(L.method==="POST"&&fe.pathname==="/api/policy/project/apply"){let ge=await Xp(se,L,G,oe,Z);if(!ge)return;let Pe=hk(ge.dir,ge.proposal,se.home);rn(G,Pe.errors.length>0?500:200,Pe);return}if(L.method==="GET"&&fe.pathname==="/api/activity"){let ge=ie(se,Z),Pe=bk(fe.searchParams.get("days"),ge);if(Pe===null){rn(G,400,{error:`days must be an integer between 1 and ${ge}`});return}rn(G,200,qp(se,Pe,Z.activityLogsDir));return}if(L.method==="POST"&&fe.pathname==="/api/rules/choose-directory"){rn(G,200,await Gs());return}if(L.method==="GET"&&fe.pathname==="/api/rules"){let ge=ee(se,Bs(Z)),Pe=new Map(ge.rules.map((Ee)=>[Ee.name,Ee]));rn(G,200,{projectPath:Z.cwd??process.cwd(),canPickDirectory:Us(process.platform,process.env),rulebooks:ge.rulebooks.map((Ee)=>({source:Ee.source,spec:Ee.spec,name:Ee.name,version:Ee.version,rules:Ee.rules.flatMap((Re)=>{let Le=Pe.get(Re);if(!Le)return[];return[{name:Le.name,command:Le.command,subcommand:Le.subcommand,block_args:Le.block_args,reason:Le.reason}]})})),errors:ge.errors,warnings:ge.warnings});return}if(L.method==="GET"&&fe.pathname==="/api/star/context"){rn(G,200,await(Z.fetchStarContext??(()=>Ak(se,{logsDir:Z.activityLogsDir})))());return}if(L.method==="POST"&&fe.pathname==="/api/star"){let ge=await(Z.starRepo??Ek)();rn(G,200,ge.ok?{ok:!0}:{ok:!1,fallbackUrl:dk});return}if(L.method==="GET"&&fe.pathname==="/api/integrations"){rn(G,200,await(Z.fetchIntegrations??(()=>Rk(se)))());return}if(L.method==="GET"&&fe.pathname==="/api/health"){rn(G,200,await(Z.fetchHealth??Tk)());return}if(L.method==="POST"&&(fe.pathname==="/api/install"||fe.pathname==="/api/uninstall")){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=ge.value?.target;if(typeof Pe!=="string"||!On.some((Re)=>Re.target===Pe)){rn(G,400,{error:"unknown target"});return}let Ee=fe.pathname==="/api/install"?"install":"uninstall";rn(G,200,await(Z.runIntegration??Ik)(Ee,Pe));return}rn(G,404,{error:"Not found"})}function Bs(_){return{..._,cwd:_.cwd??process.cwd()}}function rf(_,L){return _.dir??L.cwd??process.cwd()}function of(_,L,G){if(!O(_,{...G,cwd:L}))return null;return`${h(L)} is the user policy, not a project policy; choose a project directory, or run the GUI from one`}function Zp(_,L){let G=h(_),Y=ak(G)?$t(G):{value:void 0,errors:[]},Z=pe(Y.value,L);return{projection:Z.policy,diagnostics:[...Y.errors,...Z.diagnostics]}}async function Xp(_,L,G,Y,Z){let oe=rf(Y,Z),se=Y.revision,fe=await Er(L);if(!fe.ok)return rn(G,fe.status,{errors:[fe.error]}),null;let ge=fe.value;if(typeof ge?.revision!=="number")return rn(G,400,{errors:["revision must be a number"]}),null;if(ge.revision!==se)return rn(G,409,{errors:[pk]}),null;let Pe=of(_,oe,Z);if(Pe)return rn(G,400,{errors:[Pe]}),null;let Ee=yk(ge.proposal,_.home);if(Ee.length>0)return rn(G,400,{errors:Ee}),null;return{dir:oe,proposal:ge.proposal}}function yk(_,L){let G=kr(_,L);if(G.length>0)return G;return _?.audit===void 0?[]:[fk]}function hk(_,L,G){let Y=h(_),Z=Ro(L,k(L,G));try{return g(i(w(_,"project policy"),Y),`${JSON.stringify(Z,null,2)}
5723
+ `;var zp='<script id="ccsn-data" type="application/json">';function Yp(_,L=Wp){return L.replace(zp,()=>zp+JSON.stringify({token:_}).replaceAll("<","\\u003c"))}var qs="kenryu42/cc-safety-net",dk=`https://github.com/${qs}`,nf=1e4,uk=7,pk="The project draft directory changed; reload the draft before applying.",fk="audit settings are user scope only; remove the audit section from a project proposal";async function tf(_,L={}){let G=mn({label:"gui",booleans:{noOpen:["--no-open"]}},_),Y=L.log??console.log,Z=L.error??console.error;if(G.errors.length>0){for(let se of G.errors)Z(se);return Z("Usage: cc-safety-net gui [--no-open]"),1}let oe=await mk(c,L);if(Y(`CC Safety Net policy GUI: ${oe.url}`),!G.flags.noOpen)try{await(L.openBrowser??Pk)(oe.url)}catch(se){Z(`Failed to open browser: ${se instanceof Error?se.message:String(se)}`),Z(`Open this URL manually: ${oe.url}`)}if(L.keepAlive===!1)return await oe.close(),0;return await Sk(oe),0}async function mk(_,L={}){let G=sk(24).toString("base64url"),Y={dir:null,revision:0},Z=lk((fe,ge)=>{gk(_,fe,ge,G,L,Y)});await new Promise((fe,ge)=>{Z.once("error",ge),Z.listen(0,"127.0.0.1",()=>{Z.off("error",ge),fe()})});let se=`http://127.0.0.1:${Z.address().port}`;return{origin:se,token:G,url:`${se}/?token=${encodeURIComponent(G)}`,close:()=>xk(Z)}}async function gk(_,L,G,Y,Z,oe){let se=_(),fe=new URL(L.url??"/","http://127.0.0.1");if(L.method==="GET"&&fe.pathname==="/favicon.ico"){G.writeHead(204,{"cache-control":"no-store"}),G.end();return}if(!wk(L,fe,Y)){rn(G,403,{error:"Forbidden"});return}if(L.method==="GET"&&fe.pathname==="/"){await Promise.resolve(Z.buildDocument?.()).then((ge)=>Ck(G,Yp(Y,ge)),(ge)=>rn(G,500,{error:ge instanceof Error?ge.message:String(ge)}));return}if(L.method==="GET"&&fe.pathname==="/api/policy"){let ge=$u(se,Z),Pe=R(se,Bs(Z));rn(G,200,{...ge,configState:Ve(Pe),...Pe.policyScopes?{projectPolicy:{path:y(Z.cwd??process.cwd()),weakenings:Pe.policyScopes.weakeningsIgnored?[]:Pe.policyScopes.weakenings}}:{},destructiveCommandRules:q,secretPatterns:dt,version:pn(),preview:ge.errors.length>0?null:We(ge.policy,se.env)});return}if(L.method==="POST"&&fe.pathname==="/api/policy/preview"){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=Du(se,ge.value);rn(G,Pe.errors.length>0?400:200,Pe);return}if(L.method==="POST"&&fe.pathname==="/api/policy/explain"){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=ge.value;if(Pe===null||typeof Pe.command!=="string"){rn(G,400,{errors:["command must be a string"]});return}let Ee=kr(Pe.policy,se.home);if(Ee.length>0){rn(G,400,{errors:Ee});return}rn(G,200,vk(se,Pe.command,Pe.policy,Z));return}if(L.method==="POST"&&fe.pathname==="/api/policy"){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=Fn(se,ge.value,Z);rn(G,Pe.errors.length>0?400:200,Pe);return}if(L.method==="POST"&&fe.pathname==="/api/reset"){rn(G,200,Fn(se,ne,Z));return}if(L.method==="POST"&&fe.pathname==="/api/repair"){rn(G,200,Nu(se,Z));return}if(L.method==="POST"&&fe.pathname==="/api/policy/project/choose-directory"){let ge=await(Z.chooseDirectory??Gs)();if("path"in ge)oe.dir=ge.path,oe.revision+=1;rn(G,200,{cancelled:"cancelled"in ge,..."error"in ge?{error:ge.error}:{}});return}if(L.method==="GET"&&fe.pathname==="/api/policy/project"){let ge=rf(oe,Z),Pe=of(se,ge,Z),Ee=Pe?{projection:{},diagnostics:[Pe]}:Zp(ge,se.home),Re=Cr(se,Z);rn(G,200,{path:y(ge),revision:oe.revision,baseline:Re.baseline,userPolicyDiagnostics:Re.diagnostics,projection:Ee.projection,projectionDiagnostics:Ee.diagnostics,canPickDirectory:Us(process.platform,process.env)});return}if(L.method==="POST"&&fe.pathname==="/api/policy/project/diff"){let ge=await Xp(se,L,G,oe,Z);if(!ge)return;let Pe=Zp(ge.dir,se.home),Ee=Cr(se,Z).baseline,Re=te(Ee,pe(ge.proposal,se.home).policy);rn(G,200,{rows:Eo(te(Ee,Pe.projection).policy,Re.policy,!1),weakenings:Re.weakenings,existingFileDiagnostics:Pe.diagnostics});return}if(L.method==="POST"&&fe.pathname==="/api/policy/project/apply"){let ge=await Xp(se,L,G,oe,Z);if(!ge)return;let Pe=hk(ge.dir,ge.proposal,se.home);rn(G,Pe.errors.length>0?500:200,Pe);return}if(L.method==="GET"&&fe.pathname==="/api/activity"){let ge=ie(se,Z),Pe=bk(fe.searchParams.get("days"),ge);if(Pe===null){rn(G,400,{error:`days must be an integer between 1 and ${ge}`});return}rn(G,200,qp(se,Pe,Z.activityLogsDir));return}if(L.method==="POST"&&fe.pathname==="/api/rules/choose-directory"){rn(G,200,await Gs());return}if(L.method==="GET"&&fe.pathname==="/api/rules"){let ge=ee(se,Bs(Z)),Pe=new Map(ge.rules.map((Ee)=>[Ee.name,Ee]));rn(G,200,{projectPath:Z.cwd??process.cwd(),canPickDirectory:Us(process.platform,process.env),rulebooks:ge.rulebooks.map((Ee)=>({source:Ee.source,spec:Ee.spec,name:Ee.name,version:Ee.version,rules:Ee.rules.flatMap((Re)=>{let Le=Pe.get(Re);if(!Le)return[];return[{name:Le.name,command:Le.command,subcommand:Le.subcommand,block_args:Le.block_args,reason:Le.reason}]})})),errors:ge.errors,warnings:ge.warnings});return}if(L.method==="GET"&&fe.pathname==="/api/star/context"){rn(G,200,await(Z.fetchStarContext??(()=>Ak(se,{logsDir:Z.activityLogsDir})))());return}if(L.method==="POST"&&fe.pathname==="/api/star"){let ge=await(Z.starRepo??Ek)();rn(G,200,ge.ok?{ok:!0}:{ok:!1,fallbackUrl:dk});return}if(L.method==="GET"&&fe.pathname==="/api/integrations"){rn(G,200,await(Z.fetchIntegrations??(()=>Rk(se)))());return}if(L.method==="GET"&&fe.pathname==="/api/health"){rn(G,200,await(Z.fetchHealth??Tk)());return}if(L.method==="POST"&&(fe.pathname==="/api/install"||fe.pathname==="/api/uninstall")){let ge=await Er(L);if(!ge.ok){rn(G,ge.status,{errors:[ge.error]});return}let Pe=ge.value?.target;if(typeof Pe!=="string"||!On.some((Re)=>Re.target===Pe)){rn(G,400,{error:"unknown target"});return}let Ee=fe.pathname==="/api/install"?"install":"uninstall";rn(G,200,await(Z.runIntegration??Ik)(Ee,Pe));return}rn(G,404,{error:"Not found"})}function Bs(_){return{..._,cwd:_.cwd??process.cwd()}}function rf(_,L){return _.dir??L.cwd??process.cwd()}function of(_,L,G){if(!O(_,{...G,cwd:L}))return null;return`${y(L)} is the user policy, not a project policy; choose a project directory, or run the GUI from one`}function Zp(_,L){let G=y(_),Y=ak(G)?$t(G):{value:void 0,errors:[]},Z=pe(Y.value,L);return{projection:Z.policy,diagnostics:[...Y.errors,...Z.diagnostics]}}async function Xp(_,L,G,Y,Z){let oe=rf(Y,Z),se=Y.revision,fe=await Er(L);if(!fe.ok)return rn(G,fe.status,{errors:[fe.error]}),null;let ge=fe.value;if(typeof ge?.revision!=="number")return rn(G,400,{errors:["revision must be a number"]}),null;if(ge.revision!==se)return rn(G,409,{errors:[pk]}),null;let Pe=of(_,oe,Z);if(Pe)return rn(G,400,{errors:[Pe]}),null;let Ee=yk(ge.proposal,_.home);if(Ee.length>0)return rn(G,400,{errors:Ee}),null;return{dir:oe,proposal:ge.proposal}}function yk(_,L){let G=kr(_,L);if(G.length>0)return G;return _?.audit===void 0?[]:[fk]}function hk(_,L,G){let Y=y(_),Z=Ro(L,k(L,G));try{return h(i(w(_,"project policy"),Y),`${JSON.stringify(Z,null,2)}
5724
5724
  `),{path:Y,errors:[]}}catch(oe){return{path:Y,errors:[oe instanceof Error?oe.message:String(oe)]}}}function vk(_,L,G,Y){let Z=k(G,_.home),oe=R(_,Bs(Y)),se=Ne({rules:oe.policy.rules,transparentWrappers:oe.policy.transparentWrappers,commandTools:oe.policy.commandTools,safety:ze(Z.safety),worktreeMode:Z.workflow.worktree_mode,destructiveCommandProtectionEnabled:Z.destructive_command_protection.enabled,destructiveCommandRuleOverrides:Z.destructive_command_protection.overrides,destructiveCommandAllowPaths:Z.destructive_command_protection.allow_paths,secretProtection:{enabled:Z.secret_protection.enabled,disabledRules:mt(Z.secret_protection.overrides),denyPaths:Z.secret_protection.deny_paths,allowPaths:Z.secret_protection.allow_paths}});return mr(L,{policySnapshot:se,cwd:Y.cwd,userConfigDir:Y.userConfigDir},_)}function bk(_,L){if(_===null)return Math.min(uk,L);let G=Number(_);if(!Number.isInteger(G)||G<1||G>L)return null;return G}function wk(_,L,G){if(L.searchParams.get("token")!==G)return!1;if(_.method!=="POST")return!0;return _.headers["x-cc-safety-net-token"]===G}var kk=1048576;async function Er(_){let L=[],G=0;for await(let Y of _){let Z=Y;if(G+=Z.byteLength,G>kk)return{ok:!1,status:413,error:"Request body is too large"};L.push(Z)}try{return{ok:!0,value:JSON.parse(Buffer.concat(L).toString("utf-8")||"{}")}}catch(Y){return{ok:!1,status:400,error:`Invalid JSON: ${Y instanceof Error?Y.message:String(Y)}`}}}function Ck(_,L){_.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),_.end(L)}function rn(_,L,G){_.writeHead(L,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),_.end(JSON.stringify(G))}function xk(_){return new Promise((L,G)=>{_.close((Y)=>Y?G(Y):L())})}function Sk(_){return new Promise((L)=>{let G=()=>{process.off("SIGINT",Y),process.off("SIGTERM",Y)},Y=()=>{G(),_.close().then(L)};process.once("SIGINT",Y),process.once("SIGTERM",Y)})}function Pk(_){let L=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",G=process.platform==="win32"?["/c","start","",_]:[_];return new Promise((Y,Z)=>{let oe=ef(L,G,{detached:!0,stdio:"ignore"}),se=(ge)=>{oe.off("spawn",fe),Z(ge)},fe=()=>{oe.off("error",se),oe.unref(),Y()};oe.once("error",se),oe.once("spawn",fe)})}async function Ek(_="gh",L=nf){return{ok:await Ok(_,["api","-X","PUT",`/user/starred/${qs}`],L)===0}}async function Rk(_,L={}){let G=await Nr((Z)=>Jt({environment:_,cwd:process.cwd(),openCodeVersion:Z}).status!=="n/a",L.fetcher),Y=_k(_,G);return{targets:En.map((Z)=>{let oe=Y.find((se)=>se.platform===Z.id);return{target:Z.id,label:cn(Z.id),version:G.versions[Z.id]??null,status:oe?.configured?"active":oe?.detected?"disabled":oe?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:G.version,nodeVersion:G.nodeVersion,platform:G.platform}}}function _k(_,L){return Wt(_,process.cwd(),{ampPluginListOutput:L.ampPluginListOutput,codexPluginListOutput:L.codexPluginListOutput,copilotCliVersion:L.versions["copilot-cli"],openCodeVersion:L.versions.opencode,openCodePluginListOutput:L.openCodePluginListOutput})}async function Tk(_={}){let L=await(_.checkUpdates??Gn)();return{update:{latestVersion:L.latestVersion??null,updateAvailable:L.updateAvailable}}}var Qp=Promise.resolve();function Ik(_,L,G={}){let Y=async()=>{let oe=[],{log:se,error:fe}=console;console.log=(...ge)=>oe.push(ge.map(String).join(" ")),console.error=console.log;try{return{ok:await wr(_,[],{selectTargets:async()=>[L],output:new ck({write(Pe,Ee,Re){oe.push(String(Pe).replace(/\n$/,"")),Re()}}),...G})===0,output:oe.join(`
5725
5725
  `)}}finally{console.log=se,console.error=fe}},Z=Qp.then(Y);return Qp=Z.then(()=>{return},()=>{return}),Z}async function Ak(_,L={}){let[G,Y]=await Promise.all([$k(L.fetchRepo),Promise.resolve(Ar(_,ie(_),L.logsDir).totalBlocked)]);return{starCount:G,blockedTotal:Y}}function Ok(_,L,G){return new Promise((Y)=>{let Z=ef(_,L,{stdio:"ignore",windowsHide:!0}),oe=!1,se=setTimeout(()=>{Z.kill(),fe(null)},G),fe=(ge)=>{if(oe)return;oe=!0,clearTimeout(se),Y(ge)};Z.once("error",()=>fe(null)),Z.once("close",fe)})}async function $k(_=fetch){try{let L=await _(`https://api.github.com/repos/${qs}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(nf)});if(!L.ok)return null;let G=await L.json();return typeof G.stargazers_count==="number"?G.stargazers_count:null}catch{return null}}function Dk(_){if(_[0]!=="help")return!1;let L=_[1];if(!L)ms(),process.exit(0);if(gr(L))process.exit(0);console.error(`Unknown command: ${L}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var Nk={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),gr("hook",console.error),process.exit(1)},install:async(_)=>{process.exit(await wr("install",_))},update:async(_)=>{process.exit(await Ts(_))},uninstall:async(_)=>{process.exit(await wr("uninstall",_))},rule:async(_)=>{process.exit(await Up(c(),_))},policy:async(_)=>{process.exit(await Fu(c(),_))},status:async(_)=>{if($n(mn({label:"status"},_).errors))process.exit(1);Bp(c())},statusline:async(_)=>{let L=mn({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},_);if(L.errors.length===0&&L.flags.claudeCode){await Ms(c());return}if($n(L.errors),!L.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");gr("statusline",console.error),process.exit(1)},doctor:async(_)=>{let L=is(_);if(!L)process.exit(1);let G=await Qc(c(),{json:L.json,skipUpdateCheck:L.skipUpdateCheck});process.exit(G)},logs:async(_)=>{process.exit(await Xs(c(),_))},gui:async(_)=>{process.exit(await tf(_))},explain:async(_)=>{process.exit(await dd(c(),_))}};async function Lk(_){let L=mn({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},_);if(Dk(_))return;let G=_[0],Y=G?Ir(G):void 0;if(L.help&&Y&&Y.name!=="rule")gr(Y.name),process.exit(0);if(!G||L.help&&!Y)ms(),process.exit(0);if(L.flags.version)fd(),process.exit(0);if(Y){await Nk[Y.name](_.slice(1));return}if(G==="--statusline"){await Ms(c());return}console.error(G.startsWith("-")?`Unknown option: ${G}`:`Unknown command: ${G}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Lk as runCli};