cc-safety-net 2.4.12 → 2.4.13

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,53 +1,52 @@
1
- import{a,s,ke,Ue,k,Ze,Ge,c,o,He,R,L,ve,Qe,f,We,d,r,v,i,re,n,g,le,F,tt,nt,l,ue,de,rt,I,K,oe,S,ot,M,b,Se,j,u,J,Be,ze,O,w,T,pe,fe,Le,it,m,e,Te,we,Ve,qe,ie,Ce,se,_e,Y,U,Pe,me,G,Ke,H,Z,X,ae,Je,Ye,C,W,Ae,Oe,De,E,Ne,Ee,Fe,h,t,Q,ge,y,x,_,st,Me,$e,p,B}from"./chunks/index-kwg376ge.js";import{te,z,je,D,N}from"./chunks/index-q47ejf84.js";var Ud=["-h","--help"];function xt(P,A){let q=Object.entries(P.booleans??{}),V=Object.entries(P.values??{}),ee=Object.entries(P.lists??{}),ne=Object.fromEntries(q.map(([Xe])=>[Xe,!1])),ce={},he=Object.fromEntries(ee.map(([Xe])=>[Xe,[]])),ye=[],be=[],xe=!1,Ie=-1;for(let[Xe,et]of A.entries()){if(Xe<=Ie)continue;if(et==="--"){ye.push(...A.slice(Xe+1));break}if(Ud.includes(et)){xe=!0;continue}let Re=q.find(([,lt])=>lt.includes(et));if(Re){ne[Re[0]]=!0;continue}let at=V.find(([,lt])=>lt.includes(et));if(at){let lt=A[Xe+1];if(lt===void 0||lt.startsWith("-")){be.push(`${et} requires a value`);continue}ce[at[0]]=lt,Ie=Xe+1;continue}let ct=ee.find(([,lt])=>lt.includes(et));if(ct){let lt=A.slice(Xe+1),pt=lt.findIndex((gt)=>gt.startsWith("-")),mt=lt.slice(0,pt===-1?lt.length:pt);if(mt.length===0){be.push(`${et} requires at least one value`);continue}he[ct[0]]=[...he[ct[0]]??[],...mt],Ie=Xe+mt.length;continue}if(et.startsWith("-")){be.push(`Unknown option for ${P.label}: ${et}`);continue}if(P.positionals==="tail"){ye.push(...A.slice(Xe));break}ye.push(et)}if(P.positionals!=="list"&&P.positionals!=="tail")be.push(...ye.map((Xe)=>`Unexpected argument for ${P.label}: ${Xe}`));return{flags:ne,values:ce,lists:he,positionals:ye,help:xe,errors:be}}function Ht(P){for(let A of P)console.error(A);return P.length>0}import{readdirSync as Wd,statSync as Ni,unlinkSync as Kd}from"node:fs";import{basename as Mi,dirname as Yd,isAbsolute as Zd,join as Xd,relative as Qd,resolve as eu,sep as tu}from"node:path";var Oi=(P)=>{let A=Date.now()-new Date(P).getTime();if(!Number.isFinite(A))return"";let q=Math.floor(A/60000),V=Math.floor(q/60),ee=Math.floor(V/24);if(ee>0)return`${ee}d ago`;if(V>0)return`${V}h ago`;if(q>0)return`${q}m ago`;return"just now"},Qr=(P)=>{let A=(P??"").trim().split(/\s+/).filter((ee)=>ee&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(ee)),q=A[0]?.split("/").pop();if(!q)return null;let V=A[1];return V&&/^[a-z][a-z0-9-]*$/.test(V)?`${q} ${V}`:q};function Fi(P){let A=(ee)=>`${ee.sessionId}
2
- ${Qr(ee.segment||ee.command)}`,q=P.filter((ee)=>ee.decision!=="allow"),V=q.filter((ee)=>ee.sessionId).reduce((ee,ne)=>ee.set(A(ne),(ee.get(A(ne))??0)+1),new Map);return new Set(q.filter((ee)=>ee.failureStage||(V.get(A(ee))??0)>=2))}import{existsSync as Gd,readdirSync as Bd,readFileSync as qd}from"node:fs";import{join as Vd}from"node:path";function Yt(P,A){try{return Bd(P,{withFileTypes:!0,encoding:"utf8"}).flatMap((q)=>{let V=Vd(P,q.name);if(q.isDirectory())return Yt(V,A);if(q.name.endsWith(".jsonl"))return[V];return[]})}catch{if(A&&Gd(P))A.count++;return[]}}var zd=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Jd(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let A=P;if(typeof A.ts!=="string"||typeof A.command!=="string")return!1;return zd.every((q)=>A[q]===void 0||typeof A[q]==="string")}function pn(P,A){try{return qd(P,"utf-8").split(`
3
- `).filter(Boolean).flatMap((q)=>{try{let V=JSON.parse(q);if(!Jd(V)){if(A)A.count++;return[]}return[V]}catch{if(A)A.count++;return[]}})}catch{if(A)A.count++;return[]}}function Ct(P){return Array.from(P,(A)=>{let q=A.charCodeAt(0);if(q<=31||q>=127&&q<=159)return`\\x${q.toString(16).padStart(2,"0")}`;return A}).join("")}function nu(P,A){let q=te(P),V=xt({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},A);if(Ht(V.errors))return null;if(V.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(V.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let ee=V.values.limit===void 0?20:ji(V.values.limit);if(ee===null)return console.error("--limit must be a positive number"),null;let ne=V.values.since===void 0?Math.min(30,q):ji(V.values.since);if(ne===null||ne>q)return console.error(`--since must be a positive number of days no greater than ${q}`),null;let ce={limit:ee,limitExplicit:V.values.limit!==void 0,since:ne,sinceExplicit:V.values.since!==void 0,all:V.flags.all,json:V.flags.json,suspect:V.flags.suspect,pruneLegacy:V.flags.pruneLegacy,dryRun:V.flags.dryRun,id:V.values.id,agent:V.values.agent,rule:V.values.rule,session:V.values.session,project:V.values.project===void 0?void 0:eu(V.values.project)};if(ce.id&&(ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.sinceExplicit||ce.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(ce.pruneLegacy&&(ce.id!==void 0||ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.all||ce.sinceExplicit||ce.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(ce.dryRun&&!ce.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return ce}async function Hi(P,A,q={}){let V=nu(P,A);if(!V)return 1;let ee=q.logsDir??D(P);if(V.pruneLegacy)return ru(ee,V.json,V.dryRun);if(!ee)return console.log(V.json?"[]":V.id?`No retained audit log entry found for id ${Ct(V.id)}.`:"No audit log entries found."),0;z(P,ee);let ne={count:0},ce=Yt(ee,ne).flatMap((Ie)=>pn(Ie,ne).map((Xe)=>({entry:Xe,file:Ie})));if(ne.count>0)console.error(`warning: ${ne.count} audit log ${ne.count===1?"source":"sources"} could not be read; these results are incomplete`);if(V.id)return au(ce,V,q.timeZone);let he=Date.now()-V.since*24*60*60*1000,ye=ce.filter((Ie)=>lu(Ie,V,ee,he)),be=V.suspect?Fi(ye.map((Ie)=>Ie.entry)):null,xe=(be?ye.filter((Ie)=>be.has(Ie.entry)):ye).sort((Ie,Xe)=>Date.parse(Xe.entry.ts)-Date.parse(Ie.entry.ts)).slice(0,V.limit);if(V.json)return console.log(JSON.stringify(xe.map((Ie)=>Ie.entry),null,2)),0;if(xe.length===0)return console.log("No audit log entries found."),0;for(let Ie of xe)console.log(uu(Ie.entry,q.timeZone));return 0}function ru(P,A,q){let V=P?iu(P).map((he)=>Xd(P,he)):[];if(q)return ou(V,A);let ee=[],ne=0,ce=0;for(let he of V){let ye=Ni(he,{throwIfNoEntry:!1})?.size??0,be=su(he);if(be){ee.push(`${Mi(he)}: ${be}`);continue}ne++,ce+=ye}if(A)return console.log(JSON.stringify({removedFiles:ne,removedBytes:ce,failedFiles:ee.length})),ee.length===0?0:1;console.log(ne===0&&ee.length===0?"No legacy audit log files found.":`Removed ${ne} legacy audit log ${ne===1?"file":"files"} (${Ui(ce)}).`);for(let he of ee)console.error(`Could not remove ${Ct(he)}`);if(console.log("Nested v2 audit logs were not changed."),ne>0)console.log("This deletion cannot be undone.");return ee.length===0?0:1}function ou(P,A){let q=P.reduce((V,ee)=>V+(Ni(ee,{throwIfNoEntry:!1})?.size??0),0);if(A)return console.log(JSON.stringify({dryRun:!0,files:P.length,bytes:q})),0;if(console.log(P.length===0?"No legacy audit log files found.":`Would remove ${P.length} legacy audit log ${P.length===1?"file":"files"} (${Ui(q)}).`),console.log("Nested v2 audit logs are not included."),P.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function iu(P){try{return Wd(P,{withFileTypes:!0}).filter((A)=>A.isFile()&&A.name.endsWith(".jsonl")).map((A)=>A.name)}catch{return[]}}function su(P){try{return Kd(P),null}catch(A){return A instanceof Error?A.message:String(A)}}function Ui(P){let A=["B","KiB","MiB","GiB"],q=Math.min(Math.floor(Math.log2(Math.max(P,1))/10),A.length-1);return`${Math.round(P/1024**q*10)/10} ${A[q]}`}function au(P,A,q){let V=P.filter((ne)=>ne.entry.id===A.id);if(V.length>1)return console.error(`Multiple audit log entries found for id ${Ct(A.id??"")}.`),1;if(A.json)return console.log(JSON.stringify(V.map((ne)=>ne.entry),null,2)),0;let ee=V[0];if(!ee)return console.log(`No retained audit log entry found for id ${Ct(A.id??"")}.`),0;return console.log(pu(ee.entry,q)),0}function lu(P,A,q,V){if(!A.all&&P.entry.decision==="allow")return!1;if(Date.parse(P.entry.ts)<V)return!1;if(A.agent!==void 0&&P.entry.agent!==A.agent)return!1;if(A.rule!==void 0&&P.entry.ruleId!==A.rule)return!1;if(A.session!==void 0&&!cu(P,q,A.session))return!1;if(A.project!==void 0&&!du(P.entry.cwd,A.project))return!1;return!0}function cu(P,A,q){if(P.entry.sessionId===q)return!0;return Yd(P.file)===A&&Mi(P.file,".jsonl")===q}function du(P,A){if(!P)return!1;let q=Qd(A,P);return q!==".."&&!q.startsWith(`..${tu}`)&&!Zd(q)}function uu(P,A){let q=Ct(P.id??"-"),V=Ct(P.decision??"deny"),ee=P.cwd?` [${Ct(P.cwd)}]`:"",ne=P.segment||P.command,ce=ne===P.command?"":"↳ ",he=ne.length>50?`${ne.slice(0,50)}…`:ne;return`${q.padEnd(16)} ${Ct(Gi(P.ts,A))} ${V.padEnd(5)} ${Ct(P.agent??"-").padEnd(15)} ${Ct(P.ruleId??"-").padEnd(20)} ${ce}${Ct(he)}${ee}`}function pu(P,A){let q=(ee)=>Ct(ee===void 0||ee===null||ee===""?"-":ee),V=P.shape?`${P.agent??"-"} (shape: ${P.shape})`:P.agent??"-";return[`id: ${q(P.id)}`,`ts: ${q(Gi(P.ts,A))}`,`decision: ${q(P.decision)}`,`agent: ${q(V)}`,`level: ${q(P.level)}`,`tool: ${q(P.toolName)}`,`rule: ${q(P.ruleId)}`,`intent: ${q(P.intent)}`,`stage: ${q(P.failureStage)}`,`error: ${q(P.errorCode)}`,`session: ${q(P.sessionId)}`,`cwd: ${q(P.cwd)}`,`version: ${q(P.v)}`,`truncated: ${q(P.truncated===!0?"yes":void 0)}`,`reason: ${q(P.reason)}`,`command: ${q(P.command)}`,`segment: ${q(P.segment)}`].join(`
4
- `)}function Gi(P,A){let q=new Date(P);if(Number.isNaN(q.getTime()))return P;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:A}).format(q)}function ji(P){let A=Number(P);return Number.isFinite(A)&&A>0?A:null}var Bi={name:"doctor",aliases:["--doctor"],description:"Run diagnostic checks to verify installation and configuration",usage:"doctor [options]",options:[{flags:"--json",description:"Output diagnostics as JSON"},{flags:"--skip-update-check",description:"Skip npm registry version check"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net doctor","cc-safety-net doctor --json","cc-safety-net doctor --skip-update-check"]};var qi={name:"explain",description:"Show step-by-step analysis trace of how a command would be analyzed",usage:"explain [options] <command>",argument:"<command>",options:[{flags:"--json",description:"Output analysis as JSON"},{flags:"--cwd",argument:"<path>",description:"Use custom working directory"},{flags:"-h, --help",description:"Show this help"}],examples:['cc-safety-net explain "git reset --hard"','cc-safety-net explain --json "rm -rf /"','cc-safety-net explain --cwd /tmp "git status"']};var Vi={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};var Yn=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Zn=Yn.slice().sort((P,A)=>P.doctorOrder-A.doctorOrder).map((P)=>P.id),Sn=Yn.filter((P)=>("runtime"in P)).slice().sort((P,A)=>P.runtime.order-A.runtime.order).map((P)=>({id:P.id,displayName:"displayName"in P.runtime?P.runtime.displayName:P.displayName,flags:P.runtime.flags,legacyFlags:"legacyFlags"in P.runtime?P.runtime.legacyFlags:[],description:P.runtime.description,legacyTopLevelFlags:P.runtime.legacyTopLevelFlags})),$t=Yn.slice().sort((P,A)=>P.install.order-A.install.order).map((P)=>({id:P.id,...P.install})).map(({order:P,...A})=>A),fu=Object.fromEntries(Yn.map((P)=>[P.id,P.displayName]));function vt(P){return fu[P]}var mu=Sn.map((P)=>({flags:P.flags.join(", "),description:P.description})),gu=Sn.flatMap((P)=>P.flags.map((A)=>`cc-safety-net hook ${A}`)),zi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...mu,{flags:"-h, --help",description:"Show this help"}],examples:gu};var Ji={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Install ${vt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...$t.map((P)=>`cc-safety-net install ${P.flag}`)]},Wi={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Uninstall ${vt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...$t.map((P)=>`cc-safety-net uninstall ${P.flag}`)]},Ki={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var Yi={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var Xn={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var eo=[{flags:"--ref",argument:"<ref>",description:"Use a branch, tag, or commit"},{flags:"--only",argument:"<rulebook...>",description:"Add only these repository rulebooks"},{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"-h, --help",description:"Show this help"}],to=["cc-safety-net rule add project-rules","cc-safety-net rule add acme/safety-rules","cc-safety-net rule add acme/safety-rules --only aws gcloud","cc-safety-net rule add acme/safety-rules --ref v2 --only aws","cc-safety-net rule add --only terraform aws"],fn={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...eo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk",...to,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var Zi={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var Xi={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var Qn=[Zi,Bi,Yi,qi,fn,Xn,Ji,Ki,Wi,zi,Vi,Xi];function hu(P){return P.aliases??[]}function er(P){let A=P.toLowerCase();return Qn.find((q)=>q.name.toLowerCase()===A||hu(q).some((V)=>V.toLowerCase()===A))}import{basename as yu}from"node:path";function tr(P,A=7,q=D(P)){let V=Date.now()-A*24*60*60*1000,ee=[],ne=new Set,ce=0,he,ye,be,xe;if(q)z(P,q);let Ie={count:0},Xe=q?Yt(q,Ie):[];for(let Re of Xe)for(let at of pn(Re,Ie)){if(at.decision==="allow")continue;let ct=new Date(at.ts).getTime();if(ct>=V){if(ce++,ne.add(at.sessionId??yu(Re,".jsonl")),ye===void 0||ct<=ye)he=at.ts,ye=ct;if(xe===void 0||ct>xe)be=at.ts,xe=ct;vu(ee,at,ct)}}let et=ee.map((Re)=>({timestamp:Re.ts,command:Re.command,reason:Re.reason,relativeTime:Oi(new Date(Re.ts))}));return{totalBlocked:ce,sessionCount:ne.size,recentEntries:et,oldestEntry:he,newestEntry:be,unreadable:Ie.count}}function vu(P,A,q){let V=P.findIndex((ee)=>q>new Date(ee.ts).getTime());if(V===-1){if(P.length<3)P.push(A);return}if(P.splice(V,0,A),P.length>3)P.pop()}import{dirname as Au}from"node:path";import{dirname as bu,join as Lu,resolve as wu}from"node:path";var ku="config.json";function Rt(P,A,q,V){g(xu(P),`${JSON.stringify(A,null,2)}
5
- `,q,V)}function xu(P){return typeof P==="string"?re(P):P}function ro(P){return{errors:ie(Su(P),": "," "),ruleNames:new Set(_e(P).map((A)=>A.toLowerCase()))}}var Cu="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",Qi="must match pattern (letters, numbers, hyphens, underscores)";function Su(P){if(!es(P))return[e([],"Config must be an object")];return[...P.version===1?[]:[e(["version"],"must be 1")],...Ru(P.rules)]}function Ru(P){if(P===void 0)return[];if(!Array.isArray(P))return[e(["rules"],"must be an array")];return[...P.flatMap((A,q)=>es(A)?Pu(A,["rules",q]):[e(["rules",q],"must be an object")]),...Te(P)]}function Pu(P,A){return[...no(P.name,[...A,"name"],"required string",l,Cu),...no(P.command,[...A,"command"],"required string",w,Qi),...P.subcommand===void 0?[]:no(P.subcommand,[...A,"subcommand"],"must be a string if provided",w,Qi),...Eu(P.block_args,[...A,"block_args"]),...Du(P.reason,[...A,"reason"]),...P.intent===void 0||Ce(P.intent)?[]:[e([...A,"intent"],we)]]}function no(P,A,q,V,ee){if(typeof P!=="string")return[e(A,q)];return V.test(P)?[]:[e(A,ee)]}function Eu(P,A){if(!Array.isArray(P))return[e(A,"required array")];if(P.length===0)return[e(A,"must have at least one element")];return P.flatMap((q,V)=>{if(typeof q!=="string")return[e([...A,V],"must be a string")];return q===""?[e([...A,V],"must not be empty")]:[]})}function Du(P,A){if(typeof P!=="string")return[e(A,"required string")];if(P==="")return[e(A,"must not be empty")];return P.length>T?[e(A,`must be at most ${T} characters`)]:[]}function es(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function oo(P){let A=ts(P);if(!A.ok)return A.result;return ro(A.parsed)}function ts(P){let A=[],q=new Set;try{let V=typeof P==="string"?re(P):P,ee=n(V);if(ee===null)return A.push(`File not found: ${V.path}`),{ok:!1,result:{errors:A,ruleNames:q}};if(!ee.trim())return A.push("Config file is empty"),{ok:!1,result:{errors:A,ruleNames:q}};return{ok:!0,parsed:JSON.parse(ee)}}catch(V){if(V instanceof r)return A.push(V.message),{ok:!1,result:{errors:A,ruleNames:q}};let ee=V instanceof Error?V.message:String(V);return A.push(V instanceof SyntaxError?"Invalid JSON":ee),{ok:!1,result:{errors:A,ruleNames:q}}}}function ns(P){return wu(P,".safety-net.json")}function Jt(P){let A=ts(P);if(!A.ok)return A.result;let q=Ve(A.parsed);return{errors:q.errors,ruleNames:q.sources}}function nr(P,A={}){return Lu(bu(Se(P,A)),ku)}function rs(P,A,q){let V;try{if(n(A)===null)return{path:P,exists:!1,valid:!1,ruleCount:0};V=Jt(A),V.errors.push(...U(P,q))}catch(ee){if(!(ee instanceof r))throw ee;V={errors:[ee.message],ruleNames:new Set}}return{path:P,exists:!0,valid:V.errors.length===0,ruleCount:V.ruleNames.size,...V.errors.length>0?{errors:V.errors}:{}}}function _u(P,A){return{source:A,name:P.name,command:P.command,subcommand:P.subcommand,blockArgs:[...P.block_args],reason:P.reason}}function os(P,A){let q=j(P),V=M(A),ee=Au(q),ne=Y(P,{cwd:A,userConfigPath:q,projectConfigPath:V,userConfigDir:ee}),ce=J(P,{cwd:A,userConfigPath:q,projectConfigPath:V,userConfigDir:ee}),he=new Map(ne.rulebooks.flatMap((ye)=>ye.rules.map((be)=>[be,ye.source])));return{userConfig:rs(q,ce.userConfigTarget,ce.userScope),projectConfig:rs(V,ce.projectConfigTarget,ce.projectScope),effectiveRules:ne.rules.map((ye)=>_u(ye,he.get(ye.name)??"project"))}}var Tu=[{flag:o.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:o.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:o.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:o.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:o.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:o.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:o.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:o.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function is(P){return[...Tu.map((A)=>({name:A.flag.name,value:ve(A.flag,P.env),isSet:Qe(A.flag,P.env),legacyName:A.flag.legacyName,legacyValue:A.flag.legacyName?P.env.get(A.flag.legacyName):void 0,legacyIsSet:A.flag.legacyName?P.env.get(A.flag.legacyName)!==void 0:void 0,description:A.description,defaultBehavior:A.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:P.env.get("CC_SAFETY_NET_HOME"),isSet:P.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ss={error:0,warning:1,info:2},$u=["policy","config","audit"];function Iu(P){return P.map((A)=>{if(A==="ownership")return"is not owned by the current user";if(A==="permissions")return"has unsafe permissions";if(A==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var Ou=[{derive:(P)=>P.hooks.length>0&&P.hooks.every((A)=>!A.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(P)=>P.hooks.filter((A)=>A.inspectionStatus==="failed").map((A)=>{let q=vt(A.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${q} inspection failed`,detail:`Doctor could not verify the ${q} integration configuration.`,fixHint:`Correct the reported ${q} configuration error, then run \`cc-safety-net doctor\` again.`,integration:A.platform}})},{derive:(P)=>P.userConfig.exists&&!P.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:P.userConfig.path}]:[]},{derive:(P)=>P.projectConfig.exists&&!P.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:P.projectConfig.path}]:[]},{derive:(P)=>P.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${P.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(P)=>P.v2Leftovers&&P.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${P.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(P)=>{let A=P.environment.find((q)=>q.name==="CC_SAFETY_NET_AUDIT_SCOPE");return He(A?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...$u.map((P)=>({derive:(A)=>A.posture.directories.filter((q)=>q.kind===P&&q.status==="unsafe").map((q)=>({checkId:`posture.${P}-directory-unsafe`,severity:"error",title:`${P[0]?.toUpperCase()}${P.slice(1)} directory is unsafe`,detail:`The ${P} directory ${Iu(q.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...q.path?{path:q.path}:{}}))})),{derive:(P)=>{let A=[...P.effectiveSafety.weakenedRuleOverrides].sort();return A.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: ${A.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${A.join(", ")}.`}]:[]}}];function as(P){return Ou.flatMap((A,q)=>A.derive(P).map((V,ee)=>({finding:V,catalogOrder:q,occurrence:ee}))).sort((A,q)=>ss[A.finding.severity]-ss[q.finding.severity]||A.catalogOrder-q.catalogOrder||A.occurrence-q.occurrence).map((A)=>A.finding)}function Ut(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Fu=(P)=>Ut()?`\x1B[32m${P}\x1B[0m`:P,ju=(P)=>Ut()?`\x1B[33m${P}\x1B[0m`:P,Nu=(P)=>Ut()?`\x1B[34m${P}\x1B[0m`:P,Mu=(P)=>Ut()?`\x1B[36m${P}\x1B[0m`:P,Hu=(P)=>Ut()?`\x1B[31m${P}\x1B[0m`:P,Uu=(P)=>Ut()?`\x1B[2m${P}\x1B[0m`:P,Gu=(P)=>Ut()?`\x1B[1m${P}\x1B[0m`:P,dt={green:Fu,yellow:ju,blue:Nu,cyan:Mu,red:Hu,dim:Uu,bold:Gu},Bu="\x1B[0m",qu=[39,82,198,226,208,51,196,46,201,214,93,154,220,27,49,190,200,33,129,227,45,160,63,118,123,202];function Vu(P){let A=P;return()=>(A=(A*1664525+1013904223)%4294967296,A/4294967296)}function zu(P){let A=[...qu],q=Vu(P);for(let V=A.length-1;V>0;V--){let ee=Math.floor(q()*(V+1)),ne=A[V];A[V]=A[ee],A[ee]=ne}return A}function Ju(P,A=0){if(!Ut())return"";let q=zu(A);return`\x1B[38;5;${q[P%q.length]}m`}function ls(P,A,q=0){if(!Ut())return`"${P}"`;return`${Ju(A,q)}"${P}"${Bu}`}function rr(P){return P==="default"?"built-in default":`${P} policy`}var Wu=new RegExp("\x1B\\[[0-9;]*m","g"),io=(P)=>P.replace(Wu,"").length;function Zt(P){let A=(P.headers??P.rows[0]??[]).map((ce,he)=>{let ye=Math.max(...P.rows.map((be)=>io(be[he]??"")));return Math.max(io(ce),ye)}),q=(ce,he)=>ce+" ".repeat(Math.max(0,he-io(ce))),V=(ce,he)=>he[0]+A.map((ye)=>ce.repeat(ye+2)).join(he[1])+he[2],ee=(ce)=>`│ ${ce.map((he,ye)=>q(he,A[ye]??0)).join(" │ ")} │`,ne=P.headers?[` ${ee(P.headers)}`,` ${V("─",["├","┼","┤"])}`]:[];return[` ${V("─",["┌","┬","┐"])}`,...ne,...P.rows.map((ce)=>` ${ee(ce)}`),` ${V("─",["└","┴","┘"])}`].join(`
6
- `)}function cs(P){let A=[];A.push("Hook Integration"),A.push(Ku(P));let q=[],V=[];for(let ee of P){let ne=vt(ee.platform);if(ee.errors&&ee.errors.length>0)for(let ce of ee.errors)if(ee.configured)q.push({platform:ne,message:ce});else V.push({platform:ne,message:ce})}for(let ee of q)A.push(` Warning (${ee.platform}): ${ee.message}`);for(let ee of V)A.push(dt.red(` Error (${ee.platform}): ${ee.message}`));return A.join(`
7
- `)}function Ku(P){let A=["Platform","Discovery","Configuration","Inspection"],q=P.map((V)=>{let ee=vt(V.platform);if(V.inspectionStatus==="not-inspected"){let ye=dt.dim("Not inspected");return[ee,ye,ye,ye]}let ne=V.detected?dt.green("Detected"):V.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not detected"),ce=V.configured?dt.green("Configured"):V.detected?dt.yellow("Not configured"):V.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not applicable"),he=V.inspectionStatus==="verified"?dt.green("Verified"):V.inspectionStatus==="failed"?dt.red("Failed"):dt.dim("Not applicable");return[ee,ne,ce,he]});return Zt({headers:A,rows:q})}function ds(P){let q=["Guard Engine Verification",` Synthetic self-test: ${P.failed>0?dt.red(`${P.passed}/${P.total} FAIL`):dt.green(`${P.passed}/${P.total} passed`)}`],V=P.results.filter((ee)=>!ee.passed);if(V.length>0){q.push(""),q.push(dt.red(" Failures:"));for(let ee of V)q.push(dt.red(` • ${ee.description}`)),q.push(dt.red(` expected ${ee.expected}, got ${ee.actual}`))}return q.join(`
8
- `)}function Yu(P){if(P.length===0)return" (no custom rules)";let A=["Source","Name","Command","Block Args"],q=P.map((V)=>[V.source,V.name,V.subcommand?`${V.command} ${V.subcommand}`:V.command,V.blockArgs.join(", ")]);return Zt({headers:A,rows:q})}function us(P){let A=[];if(A.push("Configuration"),A.push(Zu(P.userConfig,P.projectConfig)),A.push(""),P.effectiveRules.length>0)A.push(` Effective rules (${P.effectiveRules.length} total):`),A.push(Yu(P.effectiveRules));else A.push(" Effective rules: (none - using built-in rules only)");return A.join(`
9
- `)}function Zu(P,A){let q=["Scope","Status"],V=(ne)=>{if(!ne.exists)return dt.dim("N/A");if(!ne.valid)return dt.red(`Invalid (${ne.errors?.[0]??"unknown error"})`);return dt.green("Configured")},ee=[["User",V(P)],["Project",V(A)]];return Zt({headers:q,rows:ee})}function ps(P){let A=[];return A.push("Environment"),A.push(Xu(P)),A.join(`
10
- `)}function fs(P){let A=P.effectiveSafety.policyScopes,q=["Effective Safety",` Selected preset: ${P.effectiveSafety.selectedPreset}${A?` (${rr(A.levelScope)})`:""}`,` Effective: ${P.effectiveSafety.level}`],V=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[ee,ne]of V){let ce=P.effectiveSafety.capabilities[ee],he=ce.enabled?dt.green("ON"):dt.dim("OFF"),ye=ce.sources.length>0?` (${ce.sources.join(", ")})`:"";q.push(` ${ne}: ${he} via ${ce.source}${ye}`)}if(A&&A.weakenings.length>0){q.push(" Project policy deltas:");for(let ee of A.weakenings)q.push(` ${ee}`)}q.push(` Stored rule customizations: ${P.effectiveSafety.ruleCounts.stored}`),q.push(` Effective rule customizations: ${P.effectiveSafety.ruleCounts.effective}`);for(let[ee,ne]of Object.entries(P.effectiveSafety.ruleOverrides))q.push(` ${ee}: ${ne}`);return q.join(`
11
- `)}function ms(P){let A=["Findings"];if(P.length===0)return A.push(" No findings from inspected doctor facts."),A.join(`
1
+ import{a,s,ke,Ue,k,Ze,Ge,c,o,He,R,L,ve,Qe,f,We,d,r,v,i,re,n,g,le,F,tt,nt,l,ue,de,rt,I,K,oe,S,ot,M,b,Se,j,u,J,Be,ze,O,w,T,pe,fe,Le,it,m,e,Te,we,Ve,qe,ie,Ce,se,_e,Y,U,Pe,me,G,Ke,H,Z,X,ae,Je,Ye,C,W,Ae,Oe,De,E,Ne,Ee,Fe,h,t,Q,ge,y,x,_,st,Me,$e,p,B}from"./chunks/index-av9c301x.js";import{te,z,je,D,N}from"./chunks/index-fjkkpma1.js";var Zd=["-h","--help"];function xt(P,A){let q=Object.entries(P.booleans??{}),V=Object.entries(P.values??{}),ee=Object.entries(P.lists??{}),ne=Object.fromEntries(q.map(([Xe])=>[Xe,!1])),ce={},he=Object.fromEntries(ee.map(([Xe])=>[Xe,[]])),ye=[],be=[],xe=!1,Ie=-1;for(let[Xe,et]of A.entries()){if(Xe<=Ie)continue;if(et==="--"){ye.push(...A.slice(Xe+1));break}if(Zd.includes(et)){xe=!0;continue}let Re=q.find(([,lt])=>lt.includes(et));if(Re){ne[Re[0]]=!0;continue}let at=V.find(([,lt])=>lt.includes(et));if(at){let lt=A[Xe+1];if(lt===void 0||lt.startsWith("-")){be.push(`${et} requires a value`);continue}ce[at[0]]=lt,Ie=Xe+1;continue}let ct=ee.find(([,lt])=>lt.includes(et));if(ct){let lt=A.slice(Xe+1),ft=lt.findIndex((gt)=>gt.startsWith("-")),mt=lt.slice(0,ft===-1?lt.length:ft);if(mt.length===0){be.push(`${et} requires at least one value`);continue}he[ct[0]]=[...he[ct[0]]??[],...mt],Ie=Xe+mt.length;continue}if(et.startsWith("-")){be.push(`Unknown option for ${P.label}: ${et}`);continue}if(P.positionals==="tail"){ye.push(...A.slice(Xe));break}ye.push(et)}if(P.positionals!=="list"&&P.positionals!=="tail")be.push(...ye.map((Xe)=>`Unexpected argument for ${P.label}: ${Xe}`));return{flags:ne,values:ce,lists:he,positionals:ye,help:xe,errors:be}}function Ut(P){for(let A of P)console.error(A);return P.length>0}import{readdirSync as iu,statSync as Vi,unlinkSync as su}from"node:fs";import{basename as zi,dirname as au,isAbsolute as lu,join as cu,relative as du,resolve as uu,sep as pu}from"node:path";var Gi=(P)=>{let A=Date.now()-new Date(P).getTime();if(!Number.isFinite(A))return"";let q=Math.floor(A/60000),V=Math.floor(q/60),ee=Math.floor(V/24);if(ee>0)return`${ee}d ago`;if(V>0)return`${V}h ago`;if(q>0)return`${q}m ago`;return"just now"},so=(P)=>{let A=(P??"").trim().split(/\s+/).filter((ee)=>ee&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(ee)),q=A[0]?.split("/").pop();if(!q)return null;let V=A[1];return V&&/^[a-z][a-z0-9-]*$/.test(V)?`${q} ${V}`:q};function Bi(P){let A=(ee)=>`${ee.sessionId}
2
+ ${so(ee.segment||ee.command)}`,q=P.filter((ee)=>ee.decision!=="allow"),V=q.filter((ee)=>ee.sessionId).reduce((ee,ne)=>ee.set(A(ne),(ee.get(A(ne))??0)+1),new Map);return new Set(q.filter((ee)=>ee.failureStage||(V.get(A(ee))??0)>=2))}import{existsSync as Qd,readdirSync as eu,readFileSync as tu}from"node:fs";import{join as nu}from"node:path";function Xt(P,A){try{return eu(P,{withFileTypes:!0,encoding:"utf8"}).flatMap((q)=>{let V=nu(P,q.name);if(q.isDirectory())return Xt(V,A);if(q.name.endsWith(".jsonl"))return[V];return[]})}catch{if(A&&Qd(P))A.count++;return[]}}var ru=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function ou(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let A=P;if(typeof A.ts!=="string"||typeof A.command!=="string")return!1;return ru.every((q)=>A[q]===void 0||typeof A[q]==="string")}function mn(P,A){try{return tu(P,"utf-8").split(`
3
+ `).filter(Boolean).flatMap((q)=>{try{let V=JSON.parse(q);if(!ou(V)){if(A)A.count++;return[]}return[V]}catch{if(A)A.count++;return[]}})}catch{if(A)A.count++;return[]}}function Ct(P){return Array.from(P,(A)=>{let q=A.charCodeAt(0);if(q<=31||q>=127&&q<=159)return`\\x${q.toString(16).padStart(2,"0")}`;return A}).join("")}function fu(P,A){let q=te(P),V=xt({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},A);if(Ut(V.errors))return null;if(V.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(V.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let ee=V.values.limit===void 0?20:qi(V.values.limit);if(ee===null)return console.error("--limit must be a positive number"),null;let ne=V.values.since===void 0?Math.min(30,q):qi(V.values.since);if(ne===null||ne>q)return console.error(`--since must be a positive number of days no greater than ${q}`),null;let ce={limit:ee,limitExplicit:V.values.limit!==void 0,since:ne,sinceExplicit:V.values.since!==void 0,all:V.flags.all,json:V.flags.json,suspect:V.flags.suspect,pruneLegacy:V.flags.pruneLegacy,dryRun:V.flags.dryRun,id:V.values.id,agent:V.values.agent,rule:V.values.rule,session:V.values.session,project:V.values.project===void 0?void 0:uu(V.values.project)};if(ce.id&&(ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.sinceExplicit||ce.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(ce.pruneLegacy&&(ce.id!==void 0||ce.agent!==void 0||ce.rule!==void 0||ce.session!==void 0||ce.project!==void 0||ce.suspect||ce.all||ce.sinceExplicit||ce.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(ce.dryRun&&!ce.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return ce}async function Ji(P,A,q={}){let V=fu(P,A);if(!V)return 1;let ee=q.logsDir??D(P);if(V.pruneLegacy)return mu(ee,V.json,V.dryRun);if(!ee)return console.log(V.json?"[]":V.id?`No retained audit log entry found for id ${Ct(V.id)}.`:"No audit log entries found."),0;z(P,ee);let ne={count:0},ce=Xt(ee,ne).flatMap((Ie)=>mn(Ie,ne).map((Xe)=>({entry:Xe,file:Ie})));if(ne.count>0)console.error(`warning: ${ne.count} audit log ${ne.count===1?"source":"sources"} could not be read; these results are incomplete`);if(V.id)return vu(ce,V,q.timeZone);let he=Date.now()-V.since*24*60*60*1000,ye=ce.filter((Ie)=>bu(Ie,V,ee,he)),be=V.suspect?Bi(ye.map((Ie)=>Ie.entry)):null,xe=(be?ye.filter((Ie)=>be.has(Ie.entry)):ye).sort((Ie,Xe)=>Date.parse(Xe.entry.ts)-Date.parse(Ie.entry.ts)).slice(0,V.limit);if(V.json)return console.log(JSON.stringify(xe.map((Ie)=>Ie.entry),null,2)),0;if(xe.length===0)return console.log("No audit log entries found."),0;for(let Ie of xe)console.log(ku(Ie.entry,q.timeZone));return 0}function mu(P,A,q){let V=P?hu(P).map((he)=>cu(P,he)):[];if(q)return gu(V,A);let ee=[],ne=0,ce=0;for(let he of V){let ye=Vi(he,{throwIfNoEntry:!1})?.size??0,be=yu(he);if(be){ee.push(`${zi(he)}: ${be}`);continue}ne++,ce+=ye}if(A)return console.log(JSON.stringify({removedFiles:ne,removedBytes:ce,failedFiles:ee.length})),ee.length===0?0:1;console.log(ne===0&&ee.length===0?"No legacy audit log files found.":`Removed ${ne} legacy audit log ${ne===1?"file":"files"} (${Wi(ce)}).`);for(let he of ee)console.error(`Could not remove ${Ct(he)}`);if(console.log("Nested v2 audit logs were not changed."),ne>0)console.log("This deletion cannot be undone.");return ee.length===0?0:1}function gu(P,A){let q=P.reduce((V,ee)=>V+(Vi(ee,{throwIfNoEntry:!1})?.size??0),0);if(A)return console.log(JSON.stringify({dryRun:!0,files:P.length,bytes:q})),0;if(console.log(P.length===0?"No legacy audit log files found.":`Would remove ${P.length} legacy audit log ${P.length===1?"file":"files"} (${Wi(q)}).`),console.log("Nested v2 audit logs are not included."),P.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function hu(P){try{return iu(P,{withFileTypes:!0}).filter((A)=>A.isFile()&&A.name.endsWith(".jsonl")).map((A)=>A.name)}catch{return[]}}function yu(P){try{return su(P),null}catch(A){return A instanceof Error?A.message:String(A)}}function Wi(P){let A=["B","KiB","MiB","GiB"],q=Math.min(Math.floor(Math.log2(Math.max(P,1))/10),A.length-1);return`${Math.round(P/1024**q*10)/10} ${A[q]}`}function vu(P,A,q){let V=P.filter((ne)=>ne.entry.id===A.id);if(V.length>1)return console.error(`Multiple audit log entries found for id ${Ct(A.id??"")}.`),1;if(A.json)return console.log(JSON.stringify(V.map((ne)=>ne.entry),null,2)),0;let ee=V[0];if(!ee)return console.log(`No retained audit log entry found for id ${Ct(A.id??"")}.`),0;return console.log(xu(ee.entry,q)),0}function bu(P,A,q,V){if(!A.all&&P.entry.decision==="allow")return!1;if(Date.parse(P.entry.ts)<V)return!1;if(A.agent!==void 0&&P.entry.agent!==A.agent)return!1;if(A.rule!==void 0&&P.entry.ruleId!==A.rule)return!1;if(A.session!==void 0&&!Lu(P,q,A.session))return!1;if(A.project!==void 0&&!wu(P.entry.cwd,A.project))return!1;return!0}function Lu(P,A,q){if(P.entry.sessionId===q)return!0;return au(P.file)===A&&zi(P.file,".jsonl")===q}function wu(P,A){if(!P)return!1;let q=du(A,P);return q!==".."&&!q.startsWith(`..${pu}`)&&!lu(q)}function ku(P,A){let q=Ct(P.id??"-"),V=Ct(P.decision??"deny"),ee=P.cwd?` [${Ct(P.cwd)}]`:"",ne=P.segment||P.command,ce=ne===P.command?"":"↳ ",he=ne.length>50?`${ne.slice(0,50)}…`:ne;return`${q.padEnd(16)} ${Ct(Ki(P.ts,A))} ${V.padEnd(5)} ${Ct(P.agent??"-").padEnd(15)} ${Ct(P.ruleId??"-").padEnd(20)} ${ce}${Ct(he)}${ee}`}function xu(P,A){let q=(ee)=>Ct(ee===void 0||ee===null||ee===""?"-":ee),V=P.shape?`${P.agent??"-"} (shape: ${P.shape})`:P.agent??"-";return[`id: ${q(P.id)}`,`ts: ${q(Ki(P.ts,A))}`,`decision: ${q(P.decision)}`,`agent: ${q(V)}`,`level: ${q(P.level)}`,`tool: ${q(P.toolName)}`,`rule: ${q(P.ruleId)}`,`intent: ${q(P.intent)}`,`stage: ${q(P.failureStage)}`,`error: ${q(P.errorCode)}`,`session: ${q(P.sessionId)}`,`cwd: ${q(P.cwd)}`,`version: ${q(P.v)}`,`truncated: ${q(P.truncated===!0?"yes":void 0)}`,`reason: ${q(P.reason)}`,`command: ${q(P.command)}`,`segment: ${q(P.segment)}`].join(`
4
+ `)}function Ki(P,A){let q=new Date(P);if(Number.isNaN(q.getTime()))return P;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:A}).format(q)}function qi(P){let A=Number(P);return Number.isFinite(A)&&A>0?A:null}var Yi={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 Xi={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 Zi={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 nr=[{id:"antigravity-cli",displayName:"Antigravity CLI",doctorOrder:3,runtime:{order:1,flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:2,flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",doctorOrder:1,runtime:{order:2,displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{order:3,flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",doctorOrder:4,runtime:{order:3,flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{order:4,flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",doctorOrder:7,runtime:{order:6,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:7,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:6,runtime:{order:5,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:6,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:8,runtime:{order:7,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:9,runtime:{order:8,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:9,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:10,runtime:{order:9,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:10,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:11,install:{order:11,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:12,install:{order:12,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:13,install:{order:13,flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",doctorOrder:5,runtime:{order:4,flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{order:5,flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],rr=nr.slice().sort((P,A)=>P.doctorOrder-A.doctorOrder).map((P)=>P.id),En=nr.filter((P)=>("runtime"in P)).slice().sort((P,A)=>P.runtime.order-A.runtime.order).map((P)=>({id:P.id,displayName:"displayName"in P.runtime?P.runtime.displayName:P.displayName,flags:P.runtime.flags,legacyFlags:"legacyFlags"in P.runtime?P.runtime.legacyFlags:[],description:P.runtime.description,legacyTopLevelFlags:P.runtime.legacyTopLevelFlags})),$t=nr.slice().sort((P,A)=>P.install.order-A.install.order).map((P)=>({id:P.id,...P.install})).map(({order:P,...A})=>A),Cu=Object.fromEntries(nr.map((P)=>[P.id,P.displayName]));function bt(P){return Cu[P]}var Su=En.map((P)=>({flags:P.flags.join(", "),description:P.description})),Ru=En.flatMap((P)=>P.flags.map((A)=>`cc-safety-net hook ${A}`)),Qi={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Su,{flags:"-h, --help",description:"Show this help"}],examples:Ru};var es={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Install ${bt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...$t.map((P)=>`cc-safety-net install ${P.flag}`)]},ts={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...$t.map((P)=>({flags:P.flag,description:`Uninstall ${bt(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...$t.map((P)=>`cc-safety-net uninstall ${P.flag}`)]},ns={name:"update",description:"Update every installed CC Safety Net integration to the latest version",usage:"update",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net update"]};var rs={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var or={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 ao=[{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"}],lo=["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"],gn={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},...ao.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",...lo,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var os={name:"status",description:"Show what the runtime is enforcing right now",usage:"status",options:[{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net status"]};var is={name:"statusline",description:"Print status line with mode indicators for shell integration",usage:"statusline --claude-code",options:[{flags:"-cc, --claude-code",description:"Print status line for Claude Code"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net statusline -cc","cc-safety-net statusline --claude-code"]};var ir=[os,Yi,rs,Xi,gn,or,es,ns,ts,Qi,Zi,is];function Pu(P){return P.aliases??[]}function sr(P){let A=P.toLowerCase();return ir.find((q)=>q.name.toLowerCase()===A||Pu(q).some((V)=>V.toLowerCase()===A))}import{basename as Eu}from"node:path";function ar(P,A=7,q=D(P)){let V=Date.now()-A*24*60*60*1000,ee=[],ne=new Set,ce=0,he,ye,be,xe;if(q)z(P,q);let Ie={count:0},Xe=q?Xt(q,Ie):[];for(let Re of Xe)for(let at of mn(Re,Ie)){if(at.decision==="allow")continue;let ct=new Date(at.ts).getTime();if(ct>=V){if(ce++,ne.add(at.sessionId??Eu(Re,".jsonl")),ye===void 0||ct<=ye)he=at.ts,ye=ct;if(xe===void 0||ct>xe)be=at.ts,xe=ct;Du(ee,at,ct)}}let et=ee.map((Re)=>({timestamp:Re.ts,command:Re.command,reason:Re.reason,relativeTime:Gi(new Date(Re.ts))}));return{totalBlocked:ce,sessionCount:ne.size,recentEntries:et,oldestEntry:he,newestEntry:be,unreadable:Ie.count}}function Du(P,A,q){let V=P.findIndex((ee)=>q>new Date(ee.ts).getTime());if(V===-1){if(P.length<3)P.push(A);return}if(P.splice(V,0,A),P.length>3)P.pop()}import{dirname as Uu}from"node:path";import{dirname as Au,join as _u,resolve as Tu}from"node:path";var Iu="config.json";function Pt(P,A,q,V){g($u(P),`${JSON.stringify(A,null,2)}
5
+ `,q,V)}function $u(P){return typeof P==="string"?re(P):P}function uo(P){return{errors:ie(Fu(P),": "," "),ruleNames:new Set(_e(P).map((A)=>A.toLowerCase()))}}var Ou="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",ss="must match pattern (letters, numbers, hyphens, underscores)";function Fu(P){if(!as(P))return[e([],"Config must be an object")];return[...P.version===1?[]:[e(["version"],"must be 1")],...Nu(P.rules)]}function Nu(P){if(P===void 0)return[];if(!Array.isArray(P))return[e(["rules"],"must be an array")];return[...P.flatMap((A,q)=>as(A)?ju(A,["rules",q]):[e(["rules",q],"must be an object")]),...Te(P)]}function ju(P,A){return[...co(P.name,[...A,"name"],"required string",l,Ou),...co(P.command,[...A,"command"],"required string",w,ss),...P.subcommand===void 0?[]:co(P.subcommand,[...A,"subcommand"],"must be a string if provided",w,ss),...Mu(P.block_args,[...A,"block_args"]),...Hu(P.reason,[...A,"reason"]),...P.intent===void 0||Ce(P.intent)?[]:[e([...A,"intent"],we)]]}function co(P,A,q,V,ee){if(typeof P!=="string")return[e(A,q)];return V.test(P)?[]:[e(A,ee)]}function Mu(P,A){if(!Array.isArray(P))return[e(A,"required array")];if(P.length===0)return[e(A,"must have at least one element")];return P.flatMap((q,V)=>{if(typeof q!=="string")return[e([...A,V],"must be a string")];return q===""?[e([...A,V],"must not be empty")]:[]})}function Hu(P,A){if(typeof P!=="string")return[e(A,"required string")];if(P==="")return[e(A,"must not be empty")];return P.length>T?[e(A,`must be at most ${T} characters`)]:[]}function as(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function po(P){let A=ls(P);if(!A.ok)return A.result;return uo(A.parsed)}function ls(P){let A=[],q=new Set;try{let V=typeof P==="string"?re(P):P,ee=n(V);if(ee===null)return A.push(`File not found: ${V.path}`),{ok:!1,result:{errors:A,ruleNames:q}};if(!ee.trim())return A.push("Config file is empty"),{ok:!1,result:{errors:A,ruleNames:q}};return{ok:!0,parsed:JSON.parse(ee)}}catch(V){if(V instanceof r)return A.push(V.message),{ok:!1,result:{errors:A,ruleNames:q}};let ee=V instanceof Error?V.message:String(V);return A.push(V instanceof SyntaxError?"Invalid JSON":ee),{ok:!1,result:{errors:A,ruleNames:q}}}}function cs(P){return Tu(P,".safety-net.json")}function Jt(P){let A=ls(P);if(!A.ok)return A.result;let q=Ve(A.parsed);return{errors:q.errors,ruleNames:q.sources}}function lr(P,A={}){return _u(Au(Se(P,A)),Iu)}function ds(P,A,q){let V;try{if(n(A)===null)return{path:P,exists:!1,valid:!1,ruleCount:0};V=Jt(A),V.errors.push(...U(P,q))}catch(ee){if(!(ee instanceof r))throw ee;V={errors:[ee.message],ruleNames:new Set}}return{path:P,exists:!0,valid:V.errors.length===0,ruleCount:V.ruleNames.size,...V.errors.length>0?{errors:V.errors}:{}}}function Gu(P,A){return{source:A,name:P.name,command:P.command,subcommand:P.subcommand,blockArgs:[...P.block_args],reason:P.reason}}function us(P,A){let q=j(P),V=M(A),ee=Uu(q),ne=Y(P,{cwd:A,userConfigPath:q,projectConfigPath:V,userConfigDir:ee}),ce=J(P,{cwd:A,userConfigPath:q,projectConfigPath:V,userConfigDir:ee}),he=new Map(ne.rulebooks.flatMap((ye)=>ye.rules.map((be)=>[be,ye.source])));return{userConfig:ds(q,ce.userConfigTarget,ce.userScope),projectConfig:ds(V,ce.projectConfigTarget,ce.projectScope),effectiveRules:ne.rules.map((ye)=>Gu(ye,he.get(ye.name)??"project"))}}var Bu=[{flag:o.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:o.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:o.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:o.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:o.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:o.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:o.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:o.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"}];function ps(P){return[...Bu.map((A)=>({name:A.flag.name,value:ve(A.flag,P.env),isSet:Qe(A.flag,P.env),legacyName:A.flag.legacyName,legacyValue:A.flag.legacyName?P.env.get(A.flag.legacyName):void 0,legacyIsSet:A.flag.legacyName?P.env.get(A.flag.legacyName)!==void 0:void 0,description:A.description,defaultBehavior:A.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:P.env.get("CC_SAFETY_NET_HOME"),isSet:P.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var fs={error:0,warning:1,info:2},qu=["policy","config","audit"];function Vu(P){return P.map((A)=>{if(A==="ownership")return"is not owned by the current user";if(A==="permissions")return"has unsafe permissions";if(A==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var zu=[{derive:(P)=>P.hooks.length>0&&P.hooks.every((A)=>!A.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(P)=>P.hooks.filter((A)=>A.inspectionStatus==="failed").map((A)=>{let q=bt(A.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${q} inspection failed`,detail:`Doctor could not verify the ${q} integration configuration.`,fixHint:`Correct the reported ${q} configuration error, then run \`cc-safety-net doctor\` again.`,integration:A.platform}})},{derive:(P)=>P.userConfig.exists&&!P.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:P.userConfig.path}]:[]},{derive:(P)=>P.projectConfig.exists&&!P.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:P.projectConfig.path}]:[]},{derive:(P)=>P.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${P.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(P)=>P.v2Leftovers&&P.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${P.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(P)=>{let A=P.environment.find((q)=>q.name==="CC_SAFETY_NET_AUDIT_SCOPE");return He(A?.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."}]:[]}},...qu.map((P)=>({derive:(A)=>A.posture.directories.filter((q)=>q.kind===P&&q.status==="unsafe").map((q)=>({checkId:`posture.${P}-directory-unsafe`,severity:"error",title:`${P[0]?.toUpperCase()}${P.slice(1)} directory is unsafe`,detail:`The ${P} directory ${Vu(q.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...q.path?{path:q.path}:{}}))})),{derive:(P)=>{let A=[...P.effectiveSafety.weakenedRuleOverrides].sort();return A.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: ${A.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${A.join(", ")}.`}]:[]}}];function ms(P){return zu.flatMap((A,q)=>A.derive(P).map((V,ee)=>({finding:V,catalogOrder:q,occurrence:ee}))).sort((A,q)=>fs[A.finding.severity]-fs[q.finding.severity]||A.catalogOrder-q.catalogOrder||A.occurrence-q.occurrence).map((A)=>A.finding)}function Gt(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var Ju=(P)=>Gt()?`\x1B[32m${P}\x1B[0m`:P,Wu=(P)=>Gt()?`\x1B[33m${P}\x1B[0m`:P,Ku=(P)=>Gt()?`\x1B[34m${P}\x1B[0m`:P,Yu=(P)=>Gt()?`\x1B[36m${P}\x1B[0m`:P,Xu=(P)=>Gt()?`\x1B[31m${P}\x1B[0m`:P,Zu=(P)=>Gt()?`\x1B[2m${P}\x1B[0m`:P,Qu=(P)=>Gt()?`\x1B[1m${P}\x1B[0m`:P,dt={green:Ju,yellow:Wu,blue:Ku,cyan:Yu,red:Xu,dim:Zu,bold:Qu},ep="\x1B[0m",tp=[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 np(P){let A=P;return()=>(A=(A*1664525+1013904223)%4294967296,A/4294967296)}function rp(P){let A=[...tp],q=np(P);for(let V=A.length-1;V>0;V--){let ee=Math.floor(q()*(V+1)),ne=A[V];A[V]=A[ee],A[ee]=ne}return A}function op(P,A=0){if(!Gt())return"";let q=rp(A);return`\x1B[38;5;${q[P%q.length]}m`}function gs(P,A,q=0){if(!Gt())return`"${P}"`;return`${op(A,q)}"${P}"${ep}`}function cr(P){return P==="default"?"built-in default":`${P} policy`}var ip=new RegExp("\x1B\\[[0-9;]*m","g"),fo=(P)=>P.replace(ip,"").length;function Zt(P){let A=(P.headers??P.rows[0]??[]).map((ce,he)=>{let ye=Math.max(...P.rows.map((be)=>fo(be[he]??"")));return Math.max(fo(ce),ye)}),q=(ce,he)=>ce+" ".repeat(Math.max(0,he-fo(ce))),V=(ce,he)=>he[0]+A.map((ye)=>ce.repeat(ye+2)).join(he[1])+he[2],ee=(ce)=>`│ ${ce.map((he,ye)=>q(he,A[ye]??0)).join(" │ ")} │`,ne=P.headers?[` ${ee(P.headers)}`,` ${V("─",["├","┼","┤"])}`]:[];return[` ${V("─",["┌","┬","┐"])}`,...ne,...P.rows.map((ce)=>` ${ee(ce)}`),` ${V("─",["└","┴","┘"])}`].join(`
6
+ `)}function hs(P){let A=[];A.push("Hook Integration"),A.push(sp(P));let q=[],V=[];for(let ee of P){let ne=bt(ee.platform);if(ee.errors&&ee.errors.length>0)for(let ce of ee.errors)if(ee.configured)q.push({platform:ne,message:ce});else V.push({platform:ne,message:ce})}for(let ee of q)A.push(` Warning (${ee.platform}): ${ee.message}`);for(let ee of V)A.push(dt.red(` Error (${ee.platform}): ${ee.message}`));return A.join(`
7
+ `)}function sp(P){let A=["Platform","Discovery","Configuration","Inspection"],q=P.map((V)=>{let ee=bt(V.platform);if(V.inspectionStatus==="not-inspected"){let ye=dt.dim("Not inspected");return[ee,ye,ye,ye]}let ne=V.detected?dt.green("Detected"):V.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not detected"),ce=V.configured?dt.green("Configured"):V.detected?dt.yellow("Not configured"):V.inspectionStatus==="failed"?dt.red("Unknown"):dt.dim("Not applicable"),he=V.inspectionStatus==="verified"?dt.green("Verified"):V.inspectionStatus==="failed"?dt.red("Failed"):dt.dim("Not applicable");return[ee,ne,ce,he]});return Zt({headers:A,rows:q})}function ys(P){let q=["Guard Engine Verification",` Synthetic self-test: ${P.failed>0?dt.red(`${P.passed}/${P.total} FAIL`):dt.green(`${P.passed}/${P.total} passed`)}`],V=P.results.filter((ee)=>!ee.passed);if(V.length>0){q.push(""),q.push(dt.red(" Failures:"));for(let ee of V)q.push(dt.red(` • ${ee.description}`)),q.push(dt.red(` expected ${ee.expected}, got ${ee.actual}`))}return q.join(`
8
+ `)}function ap(P){if(P.length===0)return" (no custom rules)";let A=["Source","Name","Command","Block Args"],q=P.map((V)=>[V.source,V.name,V.subcommand?`${V.command} ${V.subcommand}`:V.command,V.blockArgs.join(", ")]);return Zt({headers:A,rows:q})}function vs(P){let A=[];if(A.push("Configuration"),A.push(lp(P.userConfig,P.projectConfig)),A.push(""),P.effectiveRules.length>0)A.push(` Effective rules (${P.effectiveRules.length} total):`),A.push(ap(P.effectiveRules));else A.push(" Effective rules: (none - using built-in rules only)");return A.join(`
9
+ `)}function lp(P,A){let q=["Scope","Status"],V=(ne)=>{if(!ne.exists)return dt.dim("N/A");if(!ne.valid)return dt.red(`Invalid (${ne.errors?.[0]??"unknown error"})`);return dt.green("Configured")},ee=[["User",V(P)],["Project",V(A)]];return Zt({headers:q,rows:ee})}function bs(P){let A=[];return A.push("Environment"),A.push(cp(P)),A.join(`
10
+ `)}function Ls(P){let A=P.effectiveSafety.policyScopes,q=["Effective Safety",` Selected preset: ${P.effectiveSafety.selectedPreset}${A?` (${cr(A.levelScope)})`:""}`,` Effective: ${P.effectiveSafety.level}`],V=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[ee,ne]of V){let ce=P.effectiveSafety.capabilities[ee],he=ce.enabled?dt.green("ON"):dt.dim("OFF"),ye=ce.sources.length>0?` (${ce.sources.join(", ")})`:"";q.push(` ${ne}: ${he} via ${ce.source}${ye}`)}if(A&&A.weakenings.length>0){q.push(" Project policy deltas:");for(let ee of A.weakenings)q.push(` ${ee}`)}q.push(` Stored rule customizations: ${P.effectiveSafety.ruleCounts.stored}`),q.push(` Effective rule customizations: ${P.effectiveSafety.ruleCounts.effective}`);for(let[ee,ne]of Object.entries(P.effectiveSafety.ruleOverrides))q.push(` ${ee}: ${ne}`);return q.join(`
11
+ `)}function ws(P){let A=["Findings"];if(P.length===0)return A.push(" No findings from inspected doctor facts."),A.join(`
12
12
  `);for(let q of P){let V=`[${q.severity.toUpperCase()}] ${q.checkId}: ${Ct(q.title)}`,ee=q.severity==="error"?dt.red:q.severity==="warning"?dt.yellow:dt.blue;if(A.push(` ${ee(V)}`),A.push(` ${Ct(q.detail)}`),q.path)A.push(` Path: ${Ct(q.path)}`);if(q.fixHint)A.push(` Fix: ${Ct(q.fixHint)}`)}return A.join(`
13
- `)}function Xu(P){let A=["Variable","Status","Legacy"],q=P.map((V)=>{let ee=V.isSet?dt.green("✓"):dt.dim("✗"),ne=V.legacyName&&V.legacyIsSet?`${V.legacyName} ${dt.green("✓")}`:V.legacyName??"";return[V.name,ee,ne]});return Zt({headers:A,rows:q})}function gs(P){let A=[];if(P.totalBlocked===0)A.push("Recent Activity"),A.push(" No blocked commands in the last 7 days"),A.push(" Tip: This is normal for new installations");else A.push(`Recent Activity · last 7 days (${P.totalBlocked} blocked / ${P.sessionCount} sessions)`),A.push(Qu(P.recentEntries));if(P.unreadable>0)A.push(` Warning: ${P.unreadable} audit log ${P.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return A.join(`
14
- `)}function Qu(P){let A=["Time","Command"],q=P.map((V)=>{let ee=Ct(V.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),ne=ee.length>40?`${ee.slice(0,37)}...`:ee;return[V.relativeTime,ne]});return Zt({headers:A,rows:q})}function hs(P){let A=[];if(A.push("Update Check"),P.latestVersion===null&&!P.error)return A.push(or([["Status",dt.dim("Skipped")],["Installed",P.currentVersion]])),A.join(`
15
- `);if(P.error)return A.push(or([["Status",`${dt.yellow("⚠")} Error`],["Installed",P.currentVersion],["Error",dt.dim(P.error)]])),A.join(`
16
- `);if(P.updateAvailable)return A.push(or([["Status",`${dt.yellow("⚠")} Update Available`],["Current",P.currentVersion],["Latest",dt.green(P.latestVersion??"")]])),A.push(""),A.push(" Run: bunx cc-safety-net@latest doctor"),A.push(" Or: npx cc-safety-net@latest doctor"),A.join(`
17
- `);return A.push(or([["Status",`${dt.green("✓")} Up to date`],["Version",P.currentVersion]])),A.join(`
18
- `)}function or(P){return Zt({rows:P})}function ys(P){let A=[];return A.push("System Info"),A.push(ep(P)),A.join(`
19
- `)}function ep(P){let A=["Component","Version"],q=(ne)=>{if(ne===null)return dt.dim("not found");return ne},ee=[{label:"cc-safety-net",value:P.version},...Zn.map((ne)=>({label:vt(ne),value:P.versions[ne]??null})),{label:"Node.js",value:P.nodeVersion},{label:"npm",value:P.npmVersion},{label:"Bun",value:P.bunVersion},{label:"Platform",value:P.platform}].map((ne)=>[ne.label,q(ne.value)]);return Zt({headers:A,rows:ee})}function vs(P){if(P.findings.length===0)return dt.green(`
13
+ `)}function cp(P){let A=["Variable","Status","Legacy"],q=P.map((V)=>{let ee=V.isSet?dt.green("✓"):dt.dim("✗"),ne=V.legacyName&&V.legacyIsSet?`${V.legacyName} ${dt.green("✓")}`:V.legacyName??"";return[V.name,ee,ne]});return Zt({headers:A,rows:q})}function ks(P){let A=[];if(P.totalBlocked===0)A.push("Recent Activity"),A.push(" No blocked commands in the last 7 days"),A.push(" Tip: This is normal for new installations");else A.push(`Recent Activity · last 7 days (${P.totalBlocked} blocked / ${P.sessionCount} sessions)`),A.push(dp(P.recentEntries));if(P.unreadable>0)A.push(` Warning: ${P.unreadable} audit log ${P.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return A.join(`
14
+ `)}function dp(P){let A=["Time","Command"],q=P.map((V)=>{let ee=Ct(V.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),ne=ee.length>40?`${ee.slice(0,37)}...`:ee;return[V.relativeTime,ne]});return Zt({headers:A,rows:q})}function xs(P){let A=[];if(A.push("Update Check"),P.latestVersion===null&&!P.error)return A.push(dr([["Status",dt.dim("Skipped")],["Installed",P.currentVersion]])),A.join(`
15
+ `);if(P.error)return A.push(dr([["Status",`${dt.yellow("⚠")} Error`],["Installed",P.currentVersion],["Error",dt.dim(P.error)]])),A.join(`
16
+ `);if(P.updateAvailable)return A.push(dr([["Status",`${dt.yellow("⚠")} Update Available`],["Current",P.currentVersion],["Latest",dt.green(P.latestVersion??"")]])),A.push(""),A.push(" Run: bunx cc-safety-net@latest doctor"),A.push(" Or: npx cc-safety-net@latest doctor"),A.join(`
17
+ `);return A.push(dr([["Status",`${dt.green("✓")} Up to date`],["Version",P.currentVersion]])),A.join(`
18
+ `)}function dr(P){return Zt({rows:P})}function Cs(P){let A=[];return A.push("System Info"),A.push(up(P)),A.join(`
19
+ `)}function up(P){let A=["Component","Version"],q=(ne)=>{if(ne===null)return dt.dim("not found");return ne},ee=[{label:"cc-safety-net",value:P.version},...rr.map((ne)=>({label:bt(ne),value:P.versions[ne]??null})),{label:"Node.js",value:P.nodeVersion},{label:"npm",value:P.npmVersion},{label:"Bun",value:P.bunVersion},{label:"Platform",value:P.platform}].map((ne)=>[ne.label,q(ne.value)]);return Zt({headers:A,rows:ee})}function Ss(P){if(P.findings.length===0)return dt.green(`
20
20
  No findings from inspected doctor facts.`);let A={error:P.findings.filter((ne)=>ne.severity==="error").length,warning:P.findings.filter((ne)=>ne.severity==="warning").length,info:P.findings.filter((ne)=>ne.severity==="info").length},q=["error","warning","info"].filter((ne)=>A[ne]>0).map((ne)=>`${A[ne]} ${ne}`),V=P.findings.length===1?"finding":"findings",ee=`
21
- ${P.findings.length} ${V}: ${q.join(", ")}.`;if(A.error>0)return dt.red(ee);if(A.warning>0)return dt.yellow(ee);return dt.blue(ee)}import{lstatSync as tp}from"node:fs";import{dirname as so}from"node:path";function ao(P,A){try{let q=tp(A);if(q.isSymbolicLink())return{kind:P,path:A,status:"unsafe",issues:["symlink"]};if(!q.isDirectory())return{kind:P,path:A,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:P,path:A,status:"unknown",issues:[]};let V=[...q.uid!==process.getuid()?["ownership"]:[],...(q.mode&18)!==0?["permissions"]:[]];return{kind:P,path:A,status:V.length>0?"unsafe":"safe",issues:V}}catch(q){if(typeof q==="object"&&q!==null&&"code"in q&&q.code==="ENOENT")return{kind:P,path:A,status:"not-applicable",issues:[]};return{kind:P,path:A,status:"unknown",issues:[]}}}function bs(P,A){let q=D(P);return{directories:[ao("policy",so(so(A))),ao("config",so(A)),...q?[ao("audit",q)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as np}from"node:child_process";import{existsSync as Ls}from"node:fs";import{delimiter as rp,extname as op,join as ip}from"node:path";import{stripVTControlCharacters as ws}from"node:util";var xs="2.4.12",sp=5000,ap="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function wt(){return xs}function lo(P,A){let q=P[A];if(q)return q;let V=Object.keys(P).find((ee)=>ee.toLowerCase()===A.toLowerCase()&&!!P[ee]);return V?P[V]:q}function lp(P){return(lo(P,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((A)=>A.length>0)}function cp(P,A){let q=op(P)?[P]:[...lp(A).map((V)=>`${P}${V}`),P];if(P.includes("/")||P.includes("\\"))return q.find((V)=>Ls(V))??P;return(lo(A,"PATH")??"").split(rp).flatMap((V)=>q.map((ee)=>ip(V,ee))).find((V)=>Ls(V))??P}function ks(P){if(!/[\s"&|<>^]/.test(P))return P;return`"${P.replace(/"/g,'""')}"`}function Xt(P,A){let[q,...V]=P,ee=A[ap]==="win32"?"win32":process.platform;if(!q||ee!=="win32")return{cmd:q??"",args:V};let ne=cp(q,A);if(!/\.(?:bat|cmd)$/i.test(ne))return{cmd:ne,args:V};return{cmd:lo(A,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",ks(ne),...V.map(ks)].join(" ")]}}var mn=async(P,A=sp)=>{let q=await dp(P,{timeoutMs:A});if(q.code!==0)return null;return ws(q.stdout).trim()||ws(q.stderr).trim()||null};function dp(P,A){let[q,...V]=P;if(!q)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((ee)=>{try{let ne=Xt([q,...V],process.env),ce=np(ne.cmd,ne.args,{stdio:["ignore","pipe","pipe"]}),he=!1,ye="",be="";ce.stdout.on("data",(Xe)=>{ye+=Xe.toString()}),ce.stderr.on("data",(Xe)=>{be+=Xe.toString()});let xe=(Xe)=>{if(he)return;he=!0,clearTimeout(Ie),ee(Xe)},Ie=setTimeout(()=>{ce.kill(),xe({code:null,stdout:ye,stderr:be})},A.timeoutMs);ce.on("close",(Xe)=>{xe({code:Xe,stdout:ye,stderr:be})}),ce.on("error",()=>{xe({code:null,stdout:ye,stderr:be})})}catch{ee({code:null,stdout:"",stderr:""})}})}function ir(P){if(!P)return null;let A=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(P);if(A)return A[1]??null;let q=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(P);if(q)return q[1]??null;return P.split(`
22
- `)[0]?.trim()||null}async function sr(P=mn){let[A,q,V,ee,ne,ce]=await Promise.all([Promise.all($t.map(async(he)=>[he.id,ir(await P([...he.probeCommand]))])),P(["codex","plugin","list"],30000),P(["amp","plugins","list"],30000),P(["node","--version"]),P(["npm","--version"]),P(["bun","--version"])]);return{version:xs,versions:Object.fromEntries(A),codexPluginListOutput:q,ampPluginListOutput:V,nodeVersion:ir(ee),npmVersion:ir(ne),bunVersion:ir(ce),platform:`${process.platform} ${process.arch}`}}function co(P,A){if(A==="dev")return!1;let q=P.split(".").map(Number),V=A.split(".").map(Number),[ee=0,ne=0,ce=0]=q,[he=0,ye=0,be=0]=V;if(ee!==he)return ee>he;if(ne!==ye)return ne>ye;return ce>be}async function Wt(){let P=wt(),A=new AbortController,q=setTimeout(()=>A.abort(),3000);try{let V=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:A.signal});if(!V.ok)return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${V.status}`};let ee=await V.json(),ne=co(ee.version,P);return{currentVersion:P,latestVersion:ee.version,updateAvailable:ne}}catch(V){return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:V instanceof Error?V.message:"Network error"}}finally{clearTimeout(q)}}import*as _s from"node:readline";var Ps=(P)=>`\x1B[${P}B`,up=(P)=>`\x1B[${P}A`;var Cs=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function pp(P){return new Promise((A)=>setTimeout(A,P))}function fp(P,A,q){if(!q)return A(P);if(q.aborted)return Promise.resolve();return new Promise((V,ee)=>{let ne=()=>q.removeEventListener("abort",ce),ce=()=>{ne(),V()};q.addEventListener("abort",ce,{once:!0}),A(P).then(()=>{ne(),V()},(he)=>{ne(),ee(he)})})}function ar(P){return Math.max(0,Math.min(1,P))}function gn(P){return Math.max(0,Math.min(255,Math.round(P)))}function uo(P){return P<=0.0031308?12.92*P:1.055*P**0.4166666666666667-0.055}function mp(P,A,q){let V=q*Math.PI/180,ee=A*Math.cos(V),ne=A*Math.sin(V),ce=(P+0.3963377774*ee+0.2158037573*ne)**3,he=(P-0.1055613458*ee-0.0638541728*ne)**3,ye=(P-0.0894841775*ee-1.291485548*ne)**3;return{blue:gn(uo(ar(-0.0041960863*ce-0.7034186147*he+1.707614701*ye))*255),green:gn(uo(ar(-1.2684380046*ce+2.6097574011*he-0.3413193965*ye))*255),red:gn(uo(ar(4.0767416621*ce-3.3077115913*he+0.2309699292*ye))*255)}}function po(P,A){let q=(A*P*180/Math.PI%360+360)%360;return mp(0.72,0.15,q)}function Es(P,A=0.1){let q=po(A,P);return`\x1B[38;2;${q.red};${q.green};${q.blue}m`}function gp(P,A){return{blue:gn(P.blue+(255-P.blue)*A),green:gn(P.green+(255-P.green)*A),red:gn(P.red+(255-P.red)*A)}}function Ds(P,A,q){let V=Math.imul(P+2654435769,2246822507)^Math.imul(A+3266489909,668265263)^Math.imul(q+374761393,2654435761),ee=V^V>>>15,ne=Math.imul(ee,739982445),ce=ne^ne>>>12,he=Math.imul(ce,695872825);return((he^he>>>15)>>>0)/4294967296}function hp(P,A,q){let V=Math.floor(Ds(P,A,q)*Cs.length);return Cs[V]??"░"}function Ss(P){let A=ar(P);return A*A*A*(A*(A*6-15)+10)}function yp(P){if(P.length===0)return"";let A=[],q=!1,V="";for(let ee of P){let ne=`${ee.red};${ee.green};${ee.blue}`;if(ee.bold!==q)A.push(ee.bold?"\x1B[1m":"\x1B[22m"),q=ee.bold;if(ne!==V)A.push(`\x1B[38;2;${ne}m`),V=ne;A.push(ee.character)}return`${A.join("")}\x1B[22m\x1B[39m`}function vp(P,A,q,V,ee){return P.map((ne,ce)=>({...po(q,V+A+ce/ee),bold:!1,character:ne}))}function bp(P,A,q,V,ee,ne,ce,he){let ye=Math.max(1,V*0.75),be=Math.min(1,q/ye),xe=ee*Ss(be),Ie=Math.max(0,(q-ye)/Math.max(1,V-ye)),Xe=(1-Ss(q/V))*he*2,et=0.35*Math.max(0,1-Ie*2),Re=be>=1,at=Math.min(P.length,Math.ceil(xe+2+1));return P.slice(0,at).map((ct,lt)=>{let pt=po(ne,ce+A+lt/he+Xe),mt=lt+Ds(A,lt,7919)*2-1;if(mt>xe+2)return{...pt,bold:!1,character:" "};let gt=xe-mt,ut=0.8*Math.exp(-(gt*gt)/12.5),yt=Math.min(0.9,ut+et),Dt=!Re&&mt>xe-4;return{...gp(pt,yt),bold:yt>0.3,character:Dt?hp(A,lt,q):ct}})}function Rs(P){return`\x1B[?2026h${P.map((A,q)=>`\x1B8${q>0?Ps(q):""}${yp(A)}`).join("")}\x1B[?2026l`}async function fo(P,A={}){if(!P)return;let q=A.output??process.stdout,V=A.sleep??pp,ee=A.seed??0,ne=P.split(`
21
+ ${P.findings.length} ${V}: ${q.join(", ")}.`;if(A.error>0)return dt.red(ee);if(A.warning>0)return dt.yellow(ee);return dt.blue(ee)}import{lstatSync as pp}from"node:fs";import{dirname as mo}from"node:path";function go(P,A){try{let q=pp(A);if(q.isSymbolicLink())return{kind:P,path:A,status:"unsafe",issues:["symlink"]};if(!q.isDirectory())return{kind:P,path:A,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:P,path:A,status:"unknown",issues:[]};let V=[...q.uid!==process.getuid()?["ownership"]:[],...(q.mode&18)!==0?["permissions"]:[]];return{kind:P,path:A,status:V.length>0?"unsafe":"safe",issues:V}}catch(q){if(typeof q==="object"&&q!==null&&"code"in q&&q.code==="ENOENT")return{kind:P,path:A,status:"not-applicable",issues:[]};return{kind:P,path:A,status:"unknown",issues:[]}}}function Rs(P,A){let q=D(P);return{directories:[go("policy",mo(mo(A))),go("config",mo(A)),...q?[go("audit",q)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as fp}from"node:child_process";import{existsSync as Ps}from"node:fs";import{delimiter as mp,extname as gp,join as hp}from"node:path";import{stripVTControlCharacters as Es}from"node:util";var As="2.4.13",yp=5000,vp="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function wt(){return As}function ho(P,A){let q=P[A];if(q)return q;let V=Object.keys(P).find((ee)=>ee.toLowerCase()===A.toLowerCase()&&!!P[ee]);return V?P[V]:q}function bp(P){return(ho(P,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((A)=>A.length>0)}function Lp(P,A){let q=gp(P)?[P]:[...bp(A).map((V)=>`${P}${V}`),P];if(P.includes("/")||P.includes("\\"))return q.find((V)=>Ps(V))??P;return(ho(A,"PATH")??"").split(mp).flatMap((V)=>q.map((ee)=>hp(V,ee))).find((V)=>Ps(V))??P}function Ds(P){if(!/[\s"&|<>^]/.test(P))return P;return`"${P.replace(/"/g,'""')}"`}function Qt(P,A){let[q,...V]=P,ee=A[vp]==="win32"?"win32":process.platform;if(!q||ee!=="win32")return{cmd:q??"",args:V};let ne=Lp(q,A);if(!/\.(?:bat|cmd)$/i.test(ne))return{cmd:ne,args:V};return{cmd:ho(A,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Ds(ne),...V.map(Ds)].join(" ")]}}var hn=async(P,A=yp)=>{let q=await wp(P,{timeoutMs:A});if(q.code!==0)return null;return Es(q.stdout).trim()||Es(q.stderr).trim()||null};function wp(P,A){let[q,...V]=P;if(!q)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((ee)=>{try{let ne=Qt([q,...V],process.env),ce=fp(ne.cmd,ne.args,{stdio:["ignore","pipe","pipe"]}),he=!1,ye="",be="";ce.stdout.on("data",(Xe)=>{ye+=Xe.toString()}),ce.stderr.on("data",(Xe)=>{be+=Xe.toString()});let xe=(Xe)=>{if(he)return;he=!0,clearTimeout(Ie),ee(Xe)},Ie=setTimeout(()=>{ce.kill(),xe({code:null,stdout:ye,stderr:be})},A.timeoutMs);ce.on("close",(Xe)=>{xe({code:Xe,stdout:ye,stderr:be})}),ce.on("error",()=>{xe({code:null,stdout:ye,stderr:be})})}catch{ee({code:null,stdout:"",stderr:""})}})}function ur(P){if(!P)return null;let A=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(P);if(A)return A[1]??null;let q=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(P);if(q)return q[1]??null;return P.split(`
22
+ `)[0]?.trim()||null}async function pr(P,A=hn,q=process.cwd()){let V=Promise.all($t.map(async(Ie)=>[Ie.id,ur(await A([...Ie.probeCommand]))])),[ee,ne,ce,he,ye,be,xe]=await Promise.all([V,V.then(async(Ie)=>{let Xe=Ie.find(([at])=>at==="opencode")?.[1];if(!Xe?.startsWith("2.")||!P(Xe))return null;let et=["--param",`location[directory]=${q}`],Re=["opencode","api","integration.list",...et];return await A(Re,30000),A(["opencode","api","plugin.list",...et],30000)}),A(["codex","plugin","list"],30000),A(["amp","plugins","list"],30000),A(["node","--version"]),A(["npm","--version"]),A(["bun","--version"])]);return{version:As,versions:Object.fromEntries(ee),codexPluginListOutput:ce,ampPluginListOutput:he,openCodePluginListOutput:ne,nodeVersion:ur(ye),npmVersion:ur(be),bunVersion:ur(xe),platform:`${process.platform} ${process.arch}`}}function yo(P,A){if(A==="dev")return!1;let q=P.split(".").map(Number),V=A.split(".").map(Number),[ee=0,ne=0,ce=0]=q,[he=0,ye=0,be=0]=V;if(ee!==he)return ee>he;if(ne!==ye)return ne>ye;return ce>be}async function Wt(){let P=wt(),A=new AbortController,q=setTimeout(()=>A.abort(),3000);try{let V=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:A.signal});if(!V.ok)return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${V.status}`};let ee=await V.json(),ne=yo(ee.version,P);return{currentVersion:P,latestVersion:ee.version,updateAvailable:ne}}catch(V){return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:V instanceof Error?V.message:"Network error"}}finally{clearTimeout(q)}}import*as js from"node:readline";var $s=(P)=>`\x1B[${P}B`,kp=(P)=>`\x1B[${P}A`;var _s=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function xp(P){return new Promise((A)=>setTimeout(A,P))}function Cp(P,A,q){if(!q)return A(P);if(q.aborted)return Promise.resolve();return new Promise((V,ee)=>{let ne=()=>q.removeEventListener("abort",ce),ce=()=>{ne(),V()};q.addEventListener("abort",ce,{once:!0}),A(P).then(()=>{ne(),V()},(he)=>{ne(),ee(he)})})}function fr(P){return Math.max(0,Math.min(1,P))}function yn(P){return Math.max(0,Math.min(255,Math.round(P)))}function vo(P){return P<=0.0031308?12.92*P:1.055*P**0.4166666666666667-0.055}function Sp(P,A,q){let V=q*Math.PI/180,ee=A*Math.cos(V),ne=A*Math.sin(V),ce=(P+0.3963377774*ee+0.2158037573*ne)**3,he=(P-0.1055613458*ee-0.0638541728*ne)**3,ye=(P-0.0894841775*ee-1.291485548*ne)**3;return{blue:yn(vo(fr(-0.0041960863*ce-0.7034186147*he+1.707614701*ye))*255),green:yn(vo(fr(-1.2684380046*ce+2.6097574011*he-0.3413193965*ye))*255),red:yn(vo(fr(4.0767416621*ce-3.3077115913*he+0.2309699292*ye))*255)}}function bo(P,A){let q=(A*P*180/Math.PI%360+360)%360;return Sp(0.72,0.15,q)}function Os(P,A=0.1){let q=bo(A,P);return`\x1B[38;2;${q.red};${q.green};${q.blue}m`}function Rp(P,A){return{blue:yn(P.blue+(255-P.blue)*A),green:yn(P.green+(255-P.green)*A),red:yn(P.red+(255-P.red)*A)}}function Fs(P,A,q){let V=Math.imul(P+2654435769,2246822507)^Math.imul(A+3266489909,668265263)^Math.imul(q+374761393,2654435761),ee=V^V>>>15,ne=Math.imul(ee,739982445),ce=ne^ne>>>12,he=Math.imul(ce,695872825);return((he^he>>>15)>>>0)/4294967296}function Pp(P,A,q){let V=Math.floor(Fs(P,A,q)*_s.length);return _s[V]??"░"}function Ts(P){let A=fr(P);return A*A*A*(A*(A*6-15)+10)}function Ep(P){if(P.length===0)return"";let A=[],q=!1,V="";for(let ee of P){let ne=`${ee.red};${ee.green};${ee.blue}`;if(ee.bold!==q)A.push(ee.bold?"\x1B[1m":"\x1B[22m"),q=ee.bold;if(ne!==V)A.push(`\x1B[38;2;${ne}m`),V=ne;A.push(ee.character)}return`${A.join("")}\x1B[22m\x1B[39m`}function Dp(P,A,q,V,ee){return P.map((ne,ce)=>({...bo(q,V+A+ce/ee),bold:!1,character:ne}))}function Ap(P,A,q,V,ee,ne,ce,he){let ye=Math.max(1,V*0.75),be=Math.min(1,q/ye),xe=ee*Ts(be),Ie=Math.max(0,(q-ye)/Math.max(1,V-ye)),Xe=(1-Ts(q/V))*he*2,et=0.35*Math.max(0,1-Ie*2),Re=be>=1,at=Math.min(P.length,Math.ceil(xe+2+1));return P.slice(0,at).map((ct,lt)=>{let ft=bo(ne,ce+A+lt/he+Xe),mt=lt+Fs(A,lt,7919)*2-1;if(mt>xe+2)return{...ft,bold:!1,character:" "};let gt=xe-mt,ut=0.8*Math.exp(-(gt*gt)/12.5),vt=Math.min(0.9,ut+et),At=!Re&&mt>xe-4;return{...Rp(ft,vt),bold:vt>0.3,character:At?Pp(A,lt,q):ct}})}function Is(P){return`\x1B[?2026h${P.map((A,q)=>`\x1B8${q>0?$s(q):""}${Ep(A)}`).join("")}\x1B[?2026l`}async function Lo(P,A={}){if(!P)return;let q=A.output??process.stdout,V=A.sleep??xp,ee=A.seed??0,ne=P.split(`
23
23
  `).map((xe)=>Array.from(xe)),ce=Math.max(...ne.map((xe)=>xe.length)),he=12000*ne.filter((xe)=>xe.length>0).length/40,ye=ce>0?Math.max(1,Math.ceil(he/16.666666666666668)):0,be=ye>0?he/ye:0;q.write(`\x1B[?25l${ne.length>1?`${`
24
- `.repeat(ne.length-1)}${up(ne.length-1)}`:""}\x1B7`);try{for(let xe=1;xe<=ye;xe+=1){if(A.signal?.aborted)break;q.write(Rs(ne.map((Ie,Xe)=>bp(Ie,Xe,xe,ye,ce,0.1,ee,3)))),await fp(be,V,A.signal)}}finally{if(q.write(Rs(ne.map((xe,Ie)=>vp(xe,Ie,0.1,ee,3)))),q.write("\x1B8"),ne.length>1)q.write(Ps(ne.length-1));q.write(`
25
- \x1B[0m\x1B[?25h`)}}var As=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
- `);function Lp(P){return Boolean(P.isTTY)}async function Rn(P={}){let A=P.output??process.stdout;if(!Lp(A))return;let q=P.input??process.stdin,V={output:A,seed:P.seed??Math.random()*8192,sleep:P.sleep};if(!q.isTTY||typeof q.setRawMode!=="function"){await fo(As,V);return}let ee=new AbortController,ne=q.readableFlowing===!0,ce=q.isRaw===!0,he=!1,ye=(be,xe)=>{if(xe.ctrl&&xe.name==="c")he=!0;if(he||xe.name==="return"||xe.name==="enter")ee.abort()};_s.emitKeypressEvents(q),q.on("keypress",ye),q.setRawMode(!0),q.resume();try{await fo(As,{...V,signal:ee.signal})}finally{if(q.off("keypress",ye),q.setRawMode(ce),!ne)q.pause()}if(!he)return;if(P.onInterrupt){P.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Sp}from"node:crypto";import{existsSync as Is}from"node:fs";import{dirname as lr,join as Os}from"node:path";import{dirname as Ts,join as wp,resolve as kp}from"node:path";var xp="rule.lock";function Cp(P){return wp(Ts(P),xp)}function $s(P={}){return kp(P.cwd??process.cwd(),".safety-net.json")}function Pt(P,A){let q=A.global?A.userConfigPath??j(P,A):A.projectConfigPath??M(A.cwd??process.cwd()),V=A.global?Be(P,A):ze(q,A.cwd??process.cwd()),ee=Cp(q);return{configDir:Ts(q),configPath:q,lockPath:ee,filesystemScope:V,configTarget:i(V,q),lockTarget:i(V,ee)}}var Rp="`cc-safety-net rule sync` is deprecated: rulebooks are live files that need no synchronization. This run only migrates the lock and cache an earlier version left behind.",Pp="cache",Ep="rulebooks";function Fs(P,A={}){let q=Pt(P,A),V=i(q.filesystemScope,Ns(q.configDir)),ee=n(q.lockTarget);if(console.log(Rp),ee===null&&!Is(V.path))return console.log(`No v2 lock or cache leftovers found in ${lr(q.configDir)}; nothing to migrate.`),0;let ne=$p(ee),ce=m(q.configTarget);if(!ce.config&&(n(q.configTarget)!==null||ne.size>0))return console.error(`Cannot migrate: the rules config in ${lr(q.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let he=ce.config?.rules??[];for(let ye of he.flatMap((be)=>Dp(be,ne,q,V,A.global===!0)))console.log(ye);return F(q.lockTarget),tt(V),console.log(`Removed the v2 lock and cache under ${lr(q.configDir)}.`),0}function js(P,A){return[...new Set([{cwd:A},{cwd:A,global:!0}].flatMap((q)=>{let V=Pt(P,q);return[V.lockPath,Ns(V.configDir)]}))].filter((q)=>Is(q))}function Dp(P,A,q,V,ee){if(!S(P))return[];let ne=I(P).name,ce=i(q.filesystemScope,O(q.configDir,ne)),he=n(ce);if(he!==null&&Ap(he,ne))return[];let ye=A.get(P),be=ye?_p(ye,ne,V.path,q.filesystemScope):null;if(be===null)return[`Could not migrate ${P} from the v2 cache. Run \`cc-safety-net rule update ${P}${ee?" --global":""}\` to vendor it.`];if(g(ce,be),he!==null)return[`Restored ${P} from the v2 cache over an invalid file.`];return[`Vendored ${P} from the v2 cache.`]}function Ap(P,A){let q=me(P);return!("problem"in q)&&q.rulebook.name===A}function _p(P,A,q,V){let ee=Os(q,Ep,`${Tp(P)}--${P.digest.replace("sha256:","").slice(0,12)}`,ue),ne=n(i(V,ee));if(ne===null||Fp(ne)!==P.digest)return null;let ce=me(ne);if("problem"in ce||ce.rulebook.name!==A)return null;return ne}function Ns(P){return Os(lr(P),Pp)}function Tp(P){return([P.owner,P.repo,P.display_ref,P.name].every((V)=>typeof V==="string"&&V!=="")?`${P.owner}/${P.repo}#${P.display_ref}/${P.name}`:P.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function $p(P){let A=P===null?null:Op(P),q=Ms(A)&&Array.isArray(A.rulebooks)?A.rulebooks:[];return new Map(q.filter(Ip).map((V)=>[V.spec,V]))}function Ip(P){return Ms(P)&&typeof P.spec==="string"&&typeof P.digest==="string"}function Ms(P){return!!P&&typeof P==="object"}function Op(P){try{return JSON.parse(P)}catch{return null}}function Fp(P){return`sha256:${Sp("sha256").update(P).digest("hex")}`}var Hs="\r\x1B[2K",jp="\x1B[?25l",Np="\x1B[39m",Mp="\x1B[?25h",Hp=100,Up=0.55,Gp=80,Us=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function Bp(P){return new Promise((A)=>setTimeout(A,P))}async function cr(P,A={}){let q=A.output??process.stdout;if(!q.isTTY)return P;let V=A.sleep??Bp,ee=!1,ne=P.then((he)=>(ee=!0,he),(he)=>{throw ee=!0,he});if(await Promise.race([ne.then(()=>!0),V(Hp).then(()=>!1)]))return ne;q.write(jp);try{for(let he=0;!ee;he+=1)q.write(`${Hs}${Es(he*Up)}${Us[he%Us.length]}${Np} ${A.loadingMessage??"Loading…"}`),await Promise.race([ne,V(Gp)]);return await ne}finally{q.write(`${Hs}${Mp}`)}}async function Pn(P,A,q,V={}){let ee=A();if(P)await q();if(P&&ee.ready)await cr(ee.ready,V);return ee.finish()}import{stripVTControlCharacters as qp}from"node:util";var dr="amp plugins list",Vp=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Gs(P){if(!P.ampPluginListOutput)return{platform:"amp",status:"n/a"};let A=qp(P.ampPluginListOutput).split(`
27
- `).map((q)=>Vp.exec(q)?.[1]).find((q)=>q!==void 0);if(!A)return{platform:"amp",status:"n/a"};if(A!=="active")return{platform:"amp",status:"disabled",method:dr,configPath:dr,errors:[`Amp personal plugin cc-safety-net is ${A}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:dr,configPath:dr}}import{existsSync as Wp,readFileSync as Kp}from"node:fs";import{isAbsolute as ev,join as Jp}from"node:path";function En(P){return Jp(P,".gemini","config","hooks.json")}var Yp=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Zp(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];return Object.values(P).flatMap((A)=>{if(!A||typeof A!=="object"||Array.isArray(A))return[];let q=A,V=q.PreToolUse;if(!Array.isArray(V))return[];return V.flatMap((ee)=>{if(!ee||typeof ee!=="object"||Array.isArray(ee))return[];let ne=ee.hooks;if(!Array.isArray(ne))return[];return ne.flatMap((ce)=>{if(!ce||typeof ce!=="object"||Array.isArray(ce))return[];let he=ce.command;if(typeof he!=="string"||!Yp.test(he))return[];return[{command:he,enabled:q.enabled!==!1}]})})})}function Bs(P){let A=En(P.environment.home);if(!Wp(A))return{platform:"antigravity-cli",status:"n/a",configPath:A};let q;try{q=Zp(JSON.parse(Kp(A,"utf-8")))}catch(V){return{platform:"antigravity-cli",status:"n/a",configPath:A,errors:[`Failed to parse Antigravity hooks config ${A}: ${V instanceof Error?V.message:String(V)}`]}}if(q.some((V)=>V.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:A};if(q.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:A};return{platform:"antigravity-cli",status:"n/a",configPath:A}}import{join as qs}from"node:path";import{existsSync as Xp,lstatSync as Qp,readFileSync as e2}from"node:fs";function Ft(P,A=(q)=>q){if(!Xp(P))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(A(e2(P,"utf-8")))}}catch{return{kind:"unreadable"}}}function bt(P){try{return Qp(P)}catch{return}}function ur(P,A){let q=bt(A);if(!q)return{platform:P,status:"n/a",configPath:A};if(!q.isSymbolicLink()&&q.isDirectory())return;return{platform:P,status:"n/a",configPath:A,errors:[`${A} is a symlink or not a directory; move or remove it before installing`]}}function ft(P,A){return typeof P==="object"&&P!==null?P[A]:void 0}var mo="cc-safety-net@cc-marketplace";function Vs(P){return qs(P.home,".claude","plugins","installed_plugins.json")}function zs(P,A){let q=ft(ft(P,"plugins"),A);return Array.isArray(q)&&q.length>0}function pr(P,A){let q=Ft(Vs(P));return q.kind==="ok"&&zs(q.value,A)}function go(P){let A=Vs(P),q=Ft(A);if(q.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(q.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!zs(q.value,mo))return{platform:"claude-code",status:"n/a"};let V=qs(P.home,".claude","settings.json"),ee=Ft(V);if(ee.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(ee.kind==="ok"&&ft(ft(ee.value,"enabledPlugins"),mo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:V,errors:[`${mo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:A}}function Js(P){return go(P.environment)}function Ws(P){if(!P.codexPluginListOutput)return{platform:"codex",status:"n/a"};let A=P.codexPluginListOutput.split(`
28
- `).find((q)=>q.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!A)return{platform:"codex",status:"n/a"};if(!A.includes("installed,"))return{platform:"codex",status:"n/a"};if(!A.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list"}}import{existsSync as yr,readdirSync as t2,readFileSync as n2}from"node:fs";import{join as St}from"node:path";function At(P){let A="",q=0,V=!1,ee=!1,ne=-1;while(q<P.length){let ce=P[q],he=P[q+1];if(ee){A+=ce,ee=!1,q++;continue}if(ce==='"'&&!V){V=!0,ne=-1,A+=ce,q++;continue}if(ce==='"'&&V){V=!1,A+=ce,q++;continue}if(ce==="\\"&&V){ee=!0,A+=ce,q++;continue}if(V){A+=ce,q++;continue}if(ce==="/"&&he==="/"){while(q<P.length&&P[q]!==`
29
- `)q++;continue}if(ce==="/"&&he==="*"){q+=2;while(q<P.length-1){if(P[q]==="*"&&P[q+1]==="/"){q+=2;break}q++}continue}if(ce===","){ne=A.length,A+=ce,q++;continue}if(ce==="}"||ce==="]"){if(ne!==-1){let ye=A.slice(ne+1);if(/^\s*$/.test(ye))A=A.slice(0,ne)+ye}ne=-1,A+=ce,q++;continue}if(!/\s/.test(ce))ne=-1;A+=ce,q++}return A}function Ys(P,A,q){let V=A+1,ee=!1;while(V<P.length){if(ee){ee=!1,V++;continue}if(P[V]==="\\"){ee=!0,V++;continue}if(P[V]==='"')return V+1;V++}throw Error(q)}function yo(P,A,q){let V=P[A],ee=V==="["?"]":"}",ne=0,ce=A;while(ce<P.length){let he=q.skipComment?.(P,ce)??ce;if(he!==ce){ce=he;continue}if(P[ce]==='"'){ce=Ys(P,ce,q.stringError);continue}if(P[ce]===V)ne++;if(P[ce]===ee){if(ne--,ne===0)return ce}ce++}throw Error(q.bracketError)}function Zs(P,A){let q=P.lastIndexOf(`
30
- `,A)+1;return/^[ \t]*/.exec(P.slice(q))?.[0]??""}function fr(P,A){let q=A.end+(/^\s*/.exec(P.slice(A.end))?.[0].length??0);if(P[q]===","){let ce=P[q+1]===`
24
+ `.repeat(ne.length-1)}${kp(ne.length-1)}`:""}\x1B7`);try{for(let xe=1;xe<=ye;xe+=1){if(A.signal?.aborted)break;q.write(Is(ne.map((Ie,Xe)=>Ap(Ie,Xe,xe,ye,ce,0.1,ee,3)))),await Cp(be,V,A.signal)}}finally{if(q.write(Is(ne.map((xe,Ie)=>Dp(xe,Ie,0.1,ee,3)))),q.write("\x1B8"),ne.length>1)q.write($s(ne.length-1));q.write(`
25
+ \x1B[0m\x1B[?25h`)}}var Ns=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
+ `);function _p(P){return Boolean(P.isTTY)}async function Dn(P={}){let A=P.output??process.stdout;if(!_p(A))return;let q=P.input??process.stdin,V={output:A,seed:P.seed??Math.random()*8192,sleep:P.sleep};if(!q.isTTY||typeof q.setRawMode!=="function"){await Lo(Ns,V);return}let ee=new AbortController,ne=q.readableFlowing===!0,ce=q.isRaw===!0,he=!1,ye=(be,xe)=>{if(xe.ctrl&&xe.name==="c")he=!0;if(he||xe.name==="return"||xe.name==="enter")ee.abort()};js.emitKeypressEvents(q),q.on("keypress",ye),q.setRawMode(!0),q.resume();try{await Lo(Ns,{...V,signal:ee.signal})}finally{if(q.off("keypress",ye),q.setRawMode(ce),!ne)q.pause()}if(!he)return;if(P.onInterrupt){P.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Fp}from"node:crypto";import{existsSync as Us}from"node:fs";import{dirname as mr,join as Gs}from"node:path";import{dirname as Ms,join as Tp,resolve as Ip}from"node:path";var $p="rule.lock";function Op(P){return Tp(Ms(P),$p)}function Hs(P={}){return Ip(P.cwd??process.cwd(),".safety-net.json")}function Et(P,A){let q=A.global?A.userConfigPath??j(P,A):A.projectConfigPath??M(A.cwd??process.cwd()),V=A.global?Be(P,A):ze(q,A.cwd??process.cwd()),ee=Op(q);return{configDir:Ms(q),configPath:q,lockPath:ee,filesystemScope:V,configTarget:i(V,q),lockTarget:i(V,ee)}}var Np="`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.",jp="cache",Mp="rulebooks";function Bs(P,A={}){let q=Et(P,A),V=i(q.filesystemScope,Vs(q.configDir)),ee=n(q.lockTarget);if(console.log(Np),ee===null&&!Us(V.path))return console.log(`No v2 lock or cache leftovers found in ${mr(q.configDir)}; nothing to migrate.`),0;let ne=qp(ee),ce=m(q.configTarget);if(!ce.config&&(n(q.configTarget)!==null||ne.size>0))return console.error(`Cannot migrate: the rules config in ${mr(q.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let he=ce.config?.rules??[];for(let ye of he.flatMap((be)=>Hp(be,ne,q,V,A.global===!0)))console.log(ye);return F(q.lockTarget),tt(V),console.log(`Removed the v2 lock and cache under ${mr(q.configDir)}.`),0}function qs(P,A){return[...new Set([{cwd:A},{cwd:A,global:!0}].flatMap((q)=>{let V=Et(P,q);return[V.lockPath,Vs(V.configDir)]}))].filter((q)=>Us(q))}function Hp(P,A,q,V,ee){if(!S(P))return[];let ne=I(P).name,ce=i(q.filesystemScope,O(q.configDir,ne)),he=n(ce);if(he!==null&&Up(he,ne))return[];let ye=A.get(P),be=ye?Gp(ye,ne,V.path,q.filesystemScope):null;if(be===null)return[`Could not migrate ${P} from the v2 cache. Run \`cc-safety-net rule update ${P}${ee?" --global":""}\` to vendor it.`];if(g(ce,be),he!==null)return[`Restored ${P} from the v2 cache over an invalid file.`];return[`Vendored ${P} from the v2 cache.`]}function Up(P,A){let q=me(P);return!("problem"in q)&&q.rulebook.name===A}function Gp(P,A,q,V){let ee=Gs(q,Mp,`${Bp(P)}--${P.digest.replace("sha256:","").slice(0,12)}`,ue),ne=n(i(V,ee));if(ne===null||Jp(ne)!==P.digest)return null;let ce=me(ne);if("problem"in ce||ce.rulebook.name!==A)return null;return ne}function Vs(P){return Gs(mr(P),jp)}function Bp(P){return([P.owner,P.repo,P.display_ref,P.name].every((V)=>typeof V==="string"&&V!=="")?`${P.owner}/${P.repo}#${P.display_ref}/${P.name}`:P.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function qp(P){let A=P===null?null:zp(P),q=zs(A)&&Array.isArray(A.rulebooks)?A.rulebooks:[];return new Map(q.filter(Vp).map((V)=>[V.spec,V]))}function Vp(P){return zs(P)&&typeof P.spec==="string"&&typeof P.digest==="string"}function zs(P){return!!P&&typeof P==="object"}function zp(P){try{return JSON.parse(P)}catch{return null}}function Jp(P){return`sha256:${Fp("sha256").update(P).digest("hex")}`}var Js="\r\x1B[2K",Wp="\x1B[?25l",Kp="\x1B[39m",Yp="\x1B[?25h",Xp=100,Zp=0.55,Qp=80,Ws=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function e2(P){return new Promise((A)=>setTimeout(A,P))}async function gr(P,A={}){let q=A.output??process.stdout;if(!q.isTTY)return P;let V=A.sleep??e2,ee=!1,ne=P.then((he)=>(ee=!0,he),(he)=>{throw ee=!0,he});if(await Promise.race([ne.then(()=>!0),V(Xp).then(()=>!1)]))return ne;q.write(Wp);try{for(let he=0;!ee;he+=1)q.write(`${Js}${Os(he*Zp)}${Ws[he%Ws.length]}${Kp} ${A.loadingMessage??"Loading…"}`),await Promise.race([ne,V(Qp)]);return await ne}finally{q.write(`${Js}${Yp}`)}}async function An(P,A,q,V={}){let ee=A();if(P)await q();if(P&&ee.ready)await gr(ee.ready,V);return ee.finish()}import{stripVTControlCharacters as t2}from"node:util";var hr="amp plugins list",n2=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Ks(P){if(!P.ampPluginListOutput)return{platform:"amp",status:"n/a"};let A=t2(P.ampPluginListOutput).split(`
27
+ `).map((q)=>n2.exec(q)?.[1]).find((q)=>q!==void 0);if(!A)return{platform:"amp",status:"n/a"};if(A!=="active")return{platform:"amp",status:"disabled",method:hr,configPath:hr,errors:[`Amp personal plugin cc-safety-net is ${A}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:hr,configPath:hr}}import{existsSync as a2,readFileSync as l2}from"node:fs";import{isAbsolute as kv,join as s2}from"node:path";function _n(P){return s2(P,".gemini","config","hooks.json")}var c2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function d2(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];return Object.values(P).flatMap((A)=>{if(!A||typeof A!=="object"||Array.isArray(A))return[];let q=A,V=q.PreToolUse;if(!Array.isArray(V))return[];return V.flatMap((ee)=>{if(!ee||typeof ee!=="object"||Array.isArray(ee))return[];let ne=ee.hooks;if(!Array.isArray(ne))return[];return ne.flatMap((ce)=>{if(!ce||typeof ce!=="object"||Array.isArray(ce))return[];let he=ce.command;if(typeof he!=="string"||!c2.test(he))return[];return[{command:he,enabled:q.enabled!==!1}]})})})}function Ys(P){let A=_n(P.environment.home);if(!a2(A))return{platform:"antigravity-cli",status:"n/a",configPath:A};let q;try{q=d2(JSON.parse(l2(A,"utf-8")))}catch(V){return{platform:"antigravity-cli",status:"n/a",configPath:A,errors:[`Failed to parse Antigravity hooks config ${A}: ${V instanceof Error?V.message:String(V)}`]}}if(q.some((V)=>V.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:A};if(q.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:A};return{platform:"antigravity-cli",status:"n/a",configPath:A}}import{join as ko}from"node:path";import{existsSync as u2,lstatSync as p2,readFileSync as f2}from"node:fs";import{join as m2}from"node:path";function Ft(P,A=(q)=>q){if(!u2(P))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(A(f2(P,"utf-8")))}}catch{return{kind:"unreadable"}}}function en(P,A){if(P==="~")return A;if(P.startsWith("~/")||P.startsWith("~\\"))return m2(A,P.slice(2));return P}function Lt(P){try{return p2(P)}catch{return}}function yr(P,A){let q=Lt(A);if(!q)return{platform:P,status:"n/a",configPath:A};if(!q.isSymbolicLink()&&q.isDirectory())return;return{platform:P,status:"n/a",configPath:A,errors:[`${A} is a symlink or not a directory; move or remove it before installing`]}}function pt(P,A){return typeof P==="object"&&P!==null?P[A]:void 0}var wo="cc-safety-net@cc-marketplace";function vr(P){return P.env.get("CLAUDE_CONFIG_DIR")||ko(P.home,".claude")}function Xs(P){return ko(vr(P),"plugins","installed_plugins.json")}function Zs(P,A){let q=pt(pt(P,"plugins"),A);return Array.isArray(q)&&q.length>0}function br(P,A){let q=Ft(Xs(P));return q.kind==="ok"&&Zs(q.value,A)}function xo(P){let A=Xs(P),q=Ft(A);if(q.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(q.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Zs(q.value,wo))return{platform:"claude-code",status:"n/a"};let V=ko(vr(P),"settings.json"),ee=Ft(V);if(ee.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(ee.kind==="ok"&&pt(pt(ee.value,"enabledPlugins"),wo)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:V,errors:[`${wo} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:A}}function Qs(P){return xo(P.environment)}var ea="Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it.";function ta(P){if(!P.codexPluginListOutput)return{platform:"codex",status:"n/a"};let A=P.codexPluginListOutput.split(`
28
+ `).find((q)=>q.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!A)return{platform:"codex",status:"n/a"};if(!A.includes("installed,"))return{platform:"codex",status:"n/a"};if(!A.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 Cr,readdirSync as g2,readFileSync as h2}from"node:fs";import{join as Rt}from"node:path";function _t(P){let A="",q=0,V=!1,ee=!1,ne=-1;while(q<P.length){let ce=P[q],he=P[q+1];if(ee){A+=ce,ee=!1,q++;continue}if(ce==='"'&&!V){V=!0,ne=-1,A+=ce,q++;continue}if(ce==='"'&&V){V=!1,A+=ce,q++;continue}if(ce==="\\"&&V){ee=!0,A+=ce,q++;continue}if(V){A+=ce,q++;continue}if(ce==="/"&&he==="/"){while(q<P.length&&P[q]!==`
29
+ `)q++;continue}if(ce==="/"&&he==="*"){q+=2;while(q<P.length-1){if(P[q]==="*"&&P[q+1]==="/"){q+=2;break}q++}continue}if(ce===","){ne=A.length,A+=ce,q++;continue}if(ce==="}"||ce==="]"){if(ne!==-1){let ye=A.slice(ne+1);if(/^\s*$/.test(ye))A=A.slice(0,ne)+ye}ne=-1,A+=ce,q++;continue}if(!/\s/.test(ce))ne=-1;A+=ce,q++}return A}function ra(P,A,q){let V=A+1,ee=!1;while(V<P.length){if(ee){ee=!1,V++;continue}if(P[V]==="\\"){ee=!0,V++;continue}if(P[V]==='"')return V+1;V++}throw Error(q)}function So(P,A,q){let V=P[A],ee=V==="["?"]":"}",ne=0,ce=A;while(ce<P.length){let he=q.skipComment?.(P,ce)??ce;if(he!==ce){ce=he;continue}if(P[ce]==='"'){ce=ra(P,ce,q.stringError);continue}if(P[ce]===V)ne++;if(P[ce]===ee){if(ne--,ne===0)return ce}ce++}throw Error(q.bracketError)}function oa(P,A){let q=P.lastIndexOf(`
30
+ `,A)+1;return/^[ \t]*/.exec(P.slice(q))?.[0]??""}function Lr(P,A){let q=A.end+(/^\s*/.exec(P.slice(A.end))?.[0].length??0);if(P[q]===","){let ce=P[q+1]===`
31
31
  `?q+2:q+1;return`${P.slice(0,A.start)}${P.slice(ce)}`}let V=P.slice(0,A.start).search(/\s*$/)-1;if(P[V]!==",")return`${P.slice(0,A.start)}${P.slice(A.end)}`;let ee=P.lastIndexOf(`
32
- `,V-1),ne=ee!==-1&&/^\s*$/.test(P.slice(ee+1,V))?ee:V;return`${P.slice(0,ne)}${P.slice(A.end)}`}function ho(P,A){if(P.startsWith("//",A)){let q=P.indexOf(`
33
- `,A+2);return q===-1?P.length:q+1}if(P.startsWith("/*",A)){let q=P.indexOf("*/",A+2);return q===-1?P.length:q+2}return A}function Ks(P,A){let q=A;while(q<P.length){if(/\s/.test(P[q]??"")){q++;continue}let V=ho(P,q);if(V===q)return q;q=V}return q}function Xs(P,A,q){let V=0,ee=0;while(ee<P.length){let ne=ho(P,ee);if(ne!==ee){ee=ne;continue}if(P[ee]==='"'){let ce=Ys(P,ee,q.stringError);if(V===1&&JSON.parse(P.slice(ee,ce))===A){let he=Ks(P,ce),ye=Ks(P,he+1);if(P[he]===":"&&P[ye]==="[")return{start:ye,end:yo(P,ye,{skipComment:ho,...q})}}ee=ce;continue}if(P[ee]==="{"||P[ee]==="[")V++;if(P[ee]==="}"||P[ee]==="]")V--;ee++}return}var jt="cc-safety-net@cc-marketplace",mr=["cc-marketplace","cc-safety-net"],Qs=["_direct","copilot-safety-net"],ea=["cc-marketplace","safety-net"],ta="safety-net@cc-marketplace";function gr(P,A){let q=A.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${q}([^a-z0-9-]|$)`,"m").test(P??"")}function na(P){return gr(P,"cc-safety-net@cc-marketplace")}function ra(P){return gr(P,"cc-marketplace")}function oa(P){return gr(P,"copilot-safety-net")}function ia(P){return gr(P,"safety-net@cc-marketplace")}function vo(P){if(!P?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(P)}function aa(P,A){if(!P)return null;let q=P.match(/(\d+)\.(\d+)\.(\d+)/);if(!q)return null;let V=[Number(q[1]),Number(q[2]),Number(q[3])];for(let ee=0;ee<A.length;ee++){let ne=V[ee]??0,ce=A[ee]??0;if(ne!==ce)return ne>ce}return!0}function r2(P){return aa(P,[0,0,422])}function o2(P){return aa(P,[1,0,8])}function Dn(P){return P.env.get("COPILOT_HOME")||St(P.home,".copilot")}function bo(P){return(P.hooks?.preToolUse??[]).some((q)=>{if(q.type!=="command")return!1;return vo(q.command)||vo(q.bash)||vo(q.powershell)})}function hr(P){return P===void 0||typeof P==="string"}function i2(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let A=P;if(A.disableAllHooks!==void 0&&typeof A.disableAllHooks!=="boolean")return!1;if(A.hooks===void 0)return!0;if(!A.hooks||typeof A.hooks!=="object"||Array.isArray(A.hooks))return!1;let q=A.hooks.preToolUse;if(q===void 0)return!0;return Array.isArray(q)&&q.every((V)=>V!==null&&typeof V==="object"&&!Array.isArray(V)&&hr(V.type)&&hr(V.command)&&hr(V.bash)&&hr(V.powershell))}function Lo(P,A){try{let q=JSON.parse(At(n2(P,"utf-8")));if(!i2(q)){A?.push(`Invalid hook config ${P}: hooks.preToolUse must be an array of hook objects`);return}return q}catch(q){A?.push(`Failed to parse ${P}: ${q instanceof Error?q.message:String(q)}`);return}}function la(P,A){try{return t2(P).filter((q)=>q.endsWith(".json")).sort((q,V)=>q.localeCompare(V))}catch(q){return A?.push(`Failed to read ${P}: ${q instanceof Error?q.message:String(q)}`),[]}}function s2(P,A){if(!yr(P))return[];let q=[];for(let V of la(P,A)){let ee=St(P,V),ne=Lo(ee,A);if(ne&&bo(ne))q.push(ee)}return q}function hn(P,A){if(!yr(P))return;let q=Lo(P,A);if(!q)return;return{path:P,config:q}}function sa(P,A,q,V){if(A){P.push(`GitHub Copilot CLI ${A} does not support ${q}; requires ${V}+`);return}P.push(`GitHub Copilot CLI version unavailable; skipping ${q} because it requires ${V}+`)}function a2(P){for(let A of P){if(A?.config.disableAllHooks===!0)return A.path;if(A?.config.disableAllHooks===!1)return}return}function l2(P,A,q,V){let ee=Dn(P),ne=St(A,".github","hooks"),ce=St(ee,"hooks"),he=St(A,".github","copilot"),ye=St(A,".claude"),be=o2(q),xe=be===!0?V:void 0,Ie=[hn(St(he,"settings.local.json"),xe),hn(St(he,"settings.json"),xe),hn(St(ye,"settings.local.json"),xe),hn(St(ye,"settings.json"),xe)],Xe=[hn(St(ee,"settings.json"),xe),hn(St(ee,"config.json"),xe)];if(be!==!1){let gt=a2([...Ie,...Xe]);if(gt){if(be===null)V.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${gt} as active`);return{activeConfigPaths:[],disabledBy:gt}}}let et=s2(ne,V),Re=r2(q),at=Re===!0?V:void 0,ct=yr(ce)?la(ce,at):[],lt=[];for(let gt of ct){let ut=St(ce,gt),yt=Lo(ut,at);if(yt&&bo(yt))lt.push(ut)}if(Re!==!0&&lt.length>0)sa(V,q,`user hook files in ${ce}`,"0.0.422"),lt.length=0;let pt=[];for(let gt of[...Ie,...Xe]){if(!gt)continue;if(!bo(gt.config))continue;if(be===!0){pt.push(gt);continue}sa(V,q,"inline hook definitions in Copilot config files","1.0.8");break}let mt=(gt)=>gt.filter((ut)=>!!ut&&pt.includes(ut)).map((ut)=>ut.path);return{activeConfigPaths:[...mt(Ie),...et,...mt(Xe),...lt]}}function ca(P){let A=[],q=l2(P.environment,P.cwd,P.copilotCliVersion,A);if(q.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:q.disabledBy,configPaths:[q.disabledBy],errors:A.length>0?A:void 0};let V=Dn(P.environment),ee=St(V,"installed-plugins",...mr),ne=yr(ee),ce=St(V,"settings.json"),he=Ft(ce,At);if(ne&&he.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};if(ne&&he.kind==="ok"&&ft(ft(he.value,"enabledPlugins"),jt)===!1)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:ce,errors:[`${jt} is installed but not enabled in Copilot CLI`]};if(ne||q.activeConfigPaths.length>0){let ye=ne,be=q.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:ye?"plugin config":"hook config",configPath:be??(ye?ee:void 0),configPaths:q.activeConfigPaths.length>0?q.activeConfigPaths:void 0,errors:A.length>0?A:void 0}}return{platform:"copilot-cli",status:"n/a",errors:A.length>0?A:void 0}}import{existsSync as v2,readFileSync as b2}from"node:fs";import{existsSync as da,mkdirSync as u2,readFileSync as p2}from"node:fs";import{dirname as f2,join as m2}from"node:path";import{renameSync as c2,writeFileSync as d2}from"node:fs";function kt(P,A){let q=`${P}.${process.pid}.tmp`;d2(q,A),c2(q,P)}var Nt=Object.fromEntries(Sn.map((P)=>[P.id,`npx -y cc-safety-net hook ${P.flags[1]}`]));var An=Nt.cursor,ua=30;function br(P){return m2(P.home,".cursor","hooks.json")}function Qt(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function wo(){return{command:An,timeout:ua,failClosed:!0}}function vr(P){return Qt(P)&&P.command===An}function g2(P){return Object.keys(P).length===3&&P.command===An&&P.timeout===ua&&P.failClosed===!0}function h2(P){try{return JSON.parse(p2(P,"utf-8"))}catch(A){if(A instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${P}: ${A.message}`);throw A}}function pa(P){let A=h2(P);if(!Qt(A))throw Error(`Cursor hooks config ${P} must be a JSON object`);if(A.version!==1)throw Error(`Cursor hooks config ${P} must set "version": 1`);if(A.hooks!==void 0&&!Qt(A.hooks))throw Error(`Cursor hooks config ${P} "hooks" must be an object`);let q=Qt(A.hooks)?A.hooks.preToolUse:void 0;if(q!==void 0&&!Array.isArray(q))throw Error(`Cursor hooks config ${P} "hooks.preToolUse" must be an array`);return A}function fa(P){let A=Qt(P.hooks)?P.hooks.preToolUse:void 0;return Array.isArray(A)?A:[]}function y2(P){if(!P.some(vr))return[...P,wo()];return P.reduce((A,q)=>{if(!vr(q))return A.result.push(q),A;if(!A.inserted)A.result.push(wo()),A.inserted=!0;return A},{result:[],inserted:!1}).result}function ma(P,A,q){let V=Qt(A.hooks)?A.hooks:{},ee={...A,hooks:{...V,preToolUse:q}};kt(P,`${JSON.stringify(ee,null,2)}
34
- `)}function ga(P){let A=br(P);if(!da(A))return u2(f2(A),{recursive:!0}),kt(A,`${JSON.stringify({version:1,hooks:{preToolUse:[wo()]}},null,2)}
35
- `),{path:A,alreadyInstalled:!1};let q=pa(A),V=fa(q),ee=V.filter(vr);if(Qt(q.hooks)&&Array.isArray(q.hooks.preToolUse)&&ee.length===1&&ee[0]!==void 0&&g2(ee[0]))return{path:A,alreadyInstalled:!0};return ma(A,q,y2(V)),{path:A,alreadyInstalled:!1}}function ha(P){let A=br(P);if(!da(A))return{path:A,alreadyInstalled:!1};let q=pa(A),V=fa(q),ee=V.filter((ne)=>!vr(ne));if(ee.length===V.length)return{path:A,alreadyInstalled:!1};return ma(A,q,ee),{path:A,alreadyInstalled:!0}}function L2(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];let A=P.hooks;if(!A||typeof A!=="object"||Array.isArray(A))return[];let q=A.preToolUse;if(!Array.isArray(q))return[];return q.filter((V)=>!!V&&typeof V==="object"&&!Array.isArray(V)&&V.command===An)}function w2(P){let A=[];if(P.length>1)A.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let q=P[0];if(q&&q.failClosed!==!0)A.push('Managed hook is missing "failClosed": true; reinstall to repair');if(q&&q.timeout!==30)A.push('Managed hook "timeout" is not 30; reinstall to repair');return A}function ya(P){let A=br(P.environment);if(!v2(A))return{platform:"cursor",status:"n/a",configPath:A};let q;try{q=JSON.parse(b2(A,"utf-8"))}catch(ne){return{platform:"cursor",status:"n/a",configPath:A,errors:[`Failed to parse Cursor hooks config ${A}: ${ne instanceof Error?ne.message:String(ne)}`]}}let V=L2(q);if(V.length===0)return{platform:"cursor",status:"n/a",configPath:A};let ee=w2(V);return{platform:"cursor",status:"configured",method:"hook config",configPath:A,errors:ee.length>0?ee:void 0}}import{existsSync as k2}from"node:fs";import{join as ko}from"node:path";var xo="gemini-safety-net";function Co(P){let A=ko(P.home,".gemini","extensions"),q=ko(A,xo);if(!k2(q))return{platform:"gemini-cli",status:"n/a"};let V=ko(A,"extension-enablement.json"),ee=Ft(V);if(ee.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let ne=ee.kind==="ok"?ft(ft(ee.value,xo),"overrides"):void 0;if(Array.isArray(ne)&&ne.some((he)=>typeof he==="string"&&he.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:V,errors:[`${xo} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:q}}function va(P){return Co(P.environment)}import{existsSync as R2,readFileSync as P2}from"node:fs";import{existsSync as La,mkdirSync as x2,readFileSync as wa,rmSync as C2}from"node:fs";import{dirname as S2,join as ba}from"node:path";var _n=Nt["grok-build"],kr=30;function xr(P){return ba(P.env.get("GROK_HOME")??ba(P.home,".grok"),"hooks","cc-safety-net.json")}function en(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function Lr(){return{hooks:[{type:"command",command:_n,timeout:kr}]}}function ka(P){return en(P)&&P.command===_n}function xa(P){return P.flatMap((A)=>{if(!en(A)||!Array.isArray(A.hooks))return[A];let q=A.hooks.filter((V)=>!ka(V));if(q.length===A.hooks.length)return[A];return q.length===0?[]:[{...A,hooks:q}]})}function Ca(P){try{let A=JSON.parse(P);return en(A)?A:null}catch{return null}}function Sa(P){let A=en(P.hooks)?P.hooks.PreToolUse:void 0;return Array.isArray(A)?A:[]}function wr(P,A,q){let V=en(A.hooks)?A.hooks:{};kt(P,`${JSON.stringify({...A,hooks:{...V,PreToolUse:q}},null,2)}
36
- `)}function Ra(P){let A=xr(P);if(!La(A))return x2(S2(A),{recursive:!0}),wr(A,{},[Lr()]),{path:A,alreadyInstalled:!1};let q=Ca(wa(A,"utf-8"));if(!q)return wr(A,{},[Lr()]),{path:A,alreadyInstalled:!1};let V=Sa(q),ee=V.filter((ne)=>en(ne)&&Array.isArray(ne.hooks)&&ne.hooks.some(ka));if(ee.length===1&&JSON.stringify(ee[0])===JSON.stringify(Lr()))return{path:A,alreadyInstalled:!0};return wr(A,q,[...xa(V),Lr()]),{path:A,alreadyInstalled:!1}}function Pa(P){let A=xr(P);if(!La(A))return{path:A,alreadyInstalled:!1};let q=Ca(wa(A,"utf-8"));if(!q)return{path:A,alreadyInstalled:!1};let V=Sa(q),ee=xa(V);if(JSON.stringify(ee)===JSON.stringify(V))return{path:A,alreadyInstalled:!1};let ne=en(q.hooks)?q.hooks:{};if(ee.length===0&&Object.keys(q).length===1&&Object.keys(ne).length===1)return C2(A),{path:A,alreadyInstalled:!0};return wr(A,q,ee),{path:A,alreadyInstalled:!0}}function Tn(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function E2(P){if(!Tn(P)||!Tn(P.hooks))return[];let A=P.hooks.PreToolUse;if(!Array.isArray(A))return[];return A.filter((q)=>Tn(q)&&Array.isArray(q.hooks)&&q.hooks.some((V)=>Tn(V)&&V.command===_n))}function D2(P){let q=(Array.isArray(P.hooks)?P.hooks.filter(Tn):[]).find((V)=>V.command===_n);return[...P.matcher===void 0||P.matcher===""||P.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...q?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...q?.timeout===kr?[]:[`Managed hook "timeout" is not ${kr}; reinstall to repair`]]}function Ea(P){let A=xr(P.environment);if(!R2(A))return{platform:"grok-build",status:"n/a",configPath:A};let q;try{q=JSON.parse(P2(A,"utf-8"))}catch(ne){return{platform:"grok-build",status:"n/a",configPath:A,errors:[`Failed to parse Grok Build hooks config ${A}: ${ne instanceof Error?ne.message:String(ne)}`]}}let V=E2(q)[0];if(!V)return{platform:"grok-build",status:"n/a",configPath:A};let ee=D2(V);return{platform:"grok-build",status:"configured",method:"hook config",configPath:A,errors:ee.length>0?ee:void 0}}import{readFileSync as Fa}from"node:fs";import{join as ja}from"node:path";var Tt="cc-safety-net",So="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",A2=30;function Da(P){return`${So}
32
+ `,V-1),ne=ee!==-1&&/^\s*$/.test(P.slice(ee+1,V))?ee:V;return`${P.slice(0,ne)}${P.slice(A.end)}`}function Co(P,A){if(P.startsWith("//",A)){let q=P.indexOf(`
33
+ `,A+2);return q===-1?P.length:q+1}if(P.startsWith("/*",A)){let q=P.indexOf("*/",A+2);return q===-1?P.length:q+2}return A}function na(P,A){let q=A;while(q<P.length){if(/\s/.test(P[q]??"")){q++;continue}let V=Co(P,q);if(V===q)return q;q=V}return q}function ia(P,A,q){let V=0,ee=0;while(ee<P.length){let ne=Co(P,ee);if(ne!==ee){ee=ne;continue}if(P[ee]==='"'){let ce=ra(P,ee,q.stringError);if(V===1&&JSON.parse(P.slice(ee,ce))===A){let he=na(P,ce),ye=na(P,he+1);if(P[he]===":"&&P[ye]==="[")return{start:ye,end:So(P,ye,{skipComment:Co,...q})}}ee=ce;continue}if(P[ee]==="{"||P[ee]==="[")V++;if(P[ee]==="}"||P[ee]==="]")V--;ee++}return}var Nt="cc-safety-net@cc-marketplace",wr=["cc-marketplace","cc-safety-net"],sa=["_direct","copilot-safety-net"],aa=["cc-marketplace","safety-net"],la="safety-net@cc-marketplace";function kr(P,A){let q=A.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${q}([^a-z0-9-]|$)`,"m").test(P??"")}function ca(P){return kr(P,"cc-safety-net@cc-marketplace")}function da(P){return kr(P,"cc-marketplace")}function ua(P){return kr(P,"copilot-safety-net")}function pa(P){return kr(P,"safety-net@cc-marketplace")}function xr(P){if(!P?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(P)}function ma(P,A){if(!P)return null;let q=P.match(/(\d+)\.(\d+)\.(\d+)/);if(!q)return null;let V=[Number(q[1]),Number(q[2]),Number(q[3])];for(let ee=0;ee<A.length;ee++){let ne=V[ee]??0,ce=A[ee]??0;if(ne!==ce)return ne>ce}return!0}function y2(P){return ma(P,[0,0,422])}function v2(P){return ma(P,[1,0,8])}function In(P){return P.env.get("COPILOT_HOME")||Rt(P.home,".copilot")}function Ro(P){return(P.hooks?.preToolUse??[]).some((q)=>{if(q.type!==void 0&&q.type!=="command")return!1;return xr(q.command)||xr(q.bash)||xr(q.powershell)||xr(q.exec&&[q.exec,...q.args??[]].join(" "))})}function Tn(P){return P===void 0||typeof P==="string"}function b2(P){return P===void 0||Array.isArray(P)&&P.every((A)=>typeof A==="string")}function L2(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let A=P;if(A.disableAllHooks!==void 0&&typeof A.disableAllHooks!=="boolean")return!1;if(A.hooks===void 0)return!0;if(!A.hooks||typeof A.hooks!=="object"||Array.isArray(A.hooks))return!1;let q=A.hooks.preToolUse;if(q===void 0)return!0;return Array.isArray(q)&&q.every((V)=>V!==null&&typeof V==="object"&&!Array.isArray(V)&&Tn(V.type)&&Tn(V.command)&&Tn(V.bash)&&Tn(V.powershell)&&Tn(V.exec)&&b2(V.args))}function Po(P,A){try{let q=JSON.parse(_t(h2(P,"utf-8")));if(!L2(q)){A?.push(`Invalid hook config ${P}: hooks.preToolUse must be an array of hook objects`);return}return q}catch(q){A?.push(`Failed to parse ${P}: ${q instanceof Error?q.message:String(q)}`);return}}function ga(P,A){try{return g2(P).filter((q)=>q.endsWith(".json")).sort((q,V)=>q.localeCompare(V))}catch(q){return A?.push(`Failed to read ${P}: ${q instanceof Error?q.message:String(q)}`),[]}}function w2(P,A){if(!Cr(P))return[];let q=[];for(let V of ga(P,A)){let ee=Rt(P,V),ne=Po(ee,A);if(ne&&Ro(ne))q.push(ee)}return q}function vn(P,A){if(!Cr(P))return;let q=Po(P,A);if(!q)return;return{path:P,config:q}}function fa(P,A,q,V){if(A){P.push(`GitHub Copilot CLI ${A} does not support ${q}; requires ${V}+`);return}P.push(`GitHub Copilot CLI version unavailable; skipping ${q} because it requires ${V}+`)}function k2(P){for(let A of P){if(A?.config.disableAllHooks===!0)return A.path;if(A?.config.disableAllHooks===!1)return}return}function x2(P,A,q,V){let ee=In(P),ne=Rt(A,".github","hooks"),ce=Rt(ee,"hooks"),he=Rt(A,".github","copilot"),ye=Rt(A,".claude"),be=v2(q),xe=be===!0?V:void 0,Ie=[vn(Rt(he,"settings.local.json"),xe),vn(Rt(he,"settings.json"),xe),vn(Rt(ye,"settings.local.json"),xe),vn(Rt(ye,"settings.json"),xe)],Xe=[vn(Rt(ee,"settings.json"),xe),vn(Rt(ee,"config.json"),xe)];if(be!==!1){let gt=k2([...Ie,...Xe]);if(gt){if(be===null)V.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${gt} as active`);return{activeConfigPaths:[],repoInlineSources:Ie,disabledBy:gt}}}let et=w2(ne,V),Re=y2(q),at=Re===!0?V:void 0,ct=Cr(ce)?ga(ce,at):[],lt=[];for(let gt of ct){let ut=Rt(ce,gt),vt=Po(ut,at);if(vt&&Ro(vt))lt.push(ut)}if(Re!==!0&&lt.length>0)fa(V,q,`user hook files in ${ce}`,"0.0.422"),lt.length=0;let ft=[];for(let gt of[...Ie,...Xe]){if(!gt)continue;if(!Ro(gt.config))continue;if(be===!0){ft.push(gt);continue}fa(V,q,"inline hook definitions in Copilot config files","1.0.8");break}let mt=(gt)=>gt.filter((ut)=>!!ut&&ft.includes(ut)).map((ut)=>ut.path);return{activeConfigPaths:[...mt(Ie),...et,...mt(Xe),...lt],repoInlineSources:Ie}}function ha(P){let A=[],q=x2(P.environment,P.cwd,P.copilotCliVersion,A);if(q.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:q.disabledBy,configPaths:[q.disabledBy],errors:A.length>0?A:void 0};let V=In(P.environment),ee=Rt(V,"installed-plugins",...wr),ne=Cr(ee),ce=Rt(V,"settings.json"),he=Ft(ce,_t),ye=(et)=>pt(pt(et,"enabledPlugins"),Nt),be=q.repoInlineSources.find((et)=>typeof ye(et?.config)==="boolean"),xe=be??(he.kind==="ok"?{path:ce,config:he.value}:void 0);if(ne&&!be&&he.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};let Ie=ne&&xe!==void 0&&ye(xe.config)===!1;if(Ie&&q.activeConfigPaths.length===0)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:xe.path,errors:[`${Nt} is installed but not enabled in Copilot CLI`]};let Xe=ne&&!Ie;if(Xe||q.activeConfigPaths.length>0){let et=q.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:Xe?"plugin config":"hook config",configPath:et??(Xe?ee:void 0),configPaths:q.activeConfigPaths.length>0?q.activeConfigPaths:void 0,errors:A.length>0?A:void 0}}return{platform:"copilot-cli",status:"n/a",errors:A.length>0?A:void 0}}import{existsSync as I2,readFileSync as $2}from"node:fs";import{existsSync as ya,mkdirSync as R2,readFileSync as P2}from"node:fs";import{dirname as E2,join as D2}from"node:path";import{renameSync as C2,writeFileSync as S2}from"node:fs";function kt(P,A){let q=`${P}.${process.pid}.tmp`;S2(q,A),C2(q,P)}var jt=Object.fromEntries(En.map((P)=>[P.id,`npx -y cc-safety-net hook ${P.flags[1]}`]));var $n=jt.cursor,va=30;function Rr(P){return D2(P.home,".cursor","hooks.json")}function tn(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function Eo(){return{command:$n,timeout:va,failClosed:!0}}function Sr(P){return tn(P)&&P.command===$n}function A2(P){return Object.keys(P).length===3&&P.command===$n&&P.timeout===va&&P.failClosed===!0}function _2(P){try{return JSON.parse(P2(P,"utf-8"))}catch(A){if(A instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${P}: ${A.message}`);throw A}}function ba(P){let A=_2(P);if(!tn(A))throw Error(`Cursor hooks config ${P} must be a JSON object`);if(A.version!==1)throw Error(`Cursor hooks config ${P} must set "version": 1`);if(A.hooks!==void 0&&!tn(A.hooks))throw Error(`Cursor hooks config ${P} "hooks" must be an object`);let q=tn(A.hooks)?A.hooks.preToolUse:void 0;if(q!==void 0&&!Array.isArray(q))throw Error(`Cursor hooks config ${P} "hooks.preToolUse" must be an array`);return A}function La(P){let A=tn(P.hooks)?P.hooks.preToolUse:void 0;return Array.isArray(A)?A:[]}function T2(P){if(!P.some(Sr))return[...P,Eo()];return P.reduce((A,q)=>{if(!Sr(q))return A.result.push(q),A;if(!A.inserted)A.result.push(Eo()),A.inserted=!0;return A},{result:[],inserted:!1}).result}function wa(P,A,q){let V=tn(A.hooks)?A.hooks:{},ee={...A,hooks:{...V,preToolUse:q}};kt(P,`${JSON.stringify(ee,null,2)}
34
+ `)}function ka(P){let A=Rr(P);if(!ya(A))return R2(E2(A),{recursive:!0}),kt(A,`${JSON.stringify({version:1,hooks:{preToolUse:[Eo()]}},null,2)}
35
+ `),{path:A,alreadyInstalled:!1};let q=ba(A),V=La(q),ee=V.filter(Sr);if(tn(q.hooks)&&Array.isArray(q.hooks.preToolUse)&&ee.length===1&&ee[0]!==void 0&&A2(ee[0]))return{path:A,alreadyInstalled:!0};return wa(A,q,T2(V)),{path:A,alreadyInstalled:!1}}function xa(P){let A=Rr(P);if(!ya(A))return{path:A,alreadyInstalled:!1};let q=ba(A),V=La(q),ee=V.filter((ne)=>!Sr(ne));if(ee.length===V.length)return{path:A,alreadyInstalled:!1};return wa(A,q,ee),{path:A,alreadyInstalled:!0}}function O2(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];let A=P.hooks;if(!A||typeof A!=="object"||Array.isArray(A))return[];let q=A.preToolUse;if(!Array.isArray(q))return[];return q.filter((V)=>!!V&&typeof V==="object"&&!Array.isArray(V)&&V.command===$n)}function F2(P){let A=[];if(P.length>1)A.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let q=P[0];if(q&&q.failClosed!==!0)A.push('Managed hook is missing "failClosed": true; reinstall to repair');if(q&&q.timeout!==30)A.push('Managed hook "timeout" is not 30; reinstall to repair');return A}function Ca(P){let A=Rr(P.environment);if(!I2(A))return{platform:"cursor",status:"n/a",configPath:A};let q;try{q=JSON.parse($2(A,"utf-8"))}catch(ne){return{platform:"cursor",status:"n/a",configPath:A,errors:[`Failed to parse Cursor hooks config ${A}: ${ne instanceof Error?ne.message:String(ne)}`]}}let V=O2(q);if(V.length===0)return{platform:"cursor",status:"n/a",configPath:A};let ee=F2(V);return{platform:"cursor",status:"configured",method:"hook config",configPath:A,errors:ee.length>0?ee:void 0}}import{existsSync as N2}from"node:fs";import{join as Do}from"node:path";var Ao="gemini-safety-net";function _o(P){let A=Do(P.home,".gemini","extensions"),q=Do(A,Ao);if(!N2(q))return{platform:"gemini-cli",status:"n/a"};let V=Do(A,"extension-enablement.json"),ee=Ft(V);if(ee.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let ne=ee.kind==="ok"?pt(pt(ee.value,Ao),"overrides"):void 0;if(Array.isArray(ne)&&ne.some((he)=>typeof he==="string"&&he.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:V,errors:[`${Ao} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:q}}function Sa(P){return _o(P.environment)}import{existsSync as U2,readFileSync as G2}from"node:fs";import{existsSync as Pa,mkdirSync as j2,readFileSync as Ea,rmSync as M2}from"node:fs";import{dirname as H2,join as Ra}from"node:path";var On=jt["grok-build"],Dr=30;function Ar(P){return Ra(P.env.get("GROK_HOME")??Ra(P.home,".grok"),"hooks","cc-safety-net.json")}function nn(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function Pr(){return{hooks:[{type:"command",command:On,timeout:Dr}]}}function Da(P){return nn(P)&&P.command===On}function Aa(P){return P.flatMap((A)=>{if(!nn(A)||!Array.isArray(A.hooks))return[A];let q=A.hooks.filter((V)=>!Da(V));if(q.length===A.hooks.length)return[A];return q.length===0?[]:[{...A,hooks:q}]})}function _a(P){try{let A=JSON.parse(P);return nn(A)?A:null}catch{return null}}function Ta(P){let A=nn(P.hooks)?P.hooks.PreToolUse:void 0;return Array.isArray(A)?A:[]}function Er(P,A,q){let V=nn(A.hooks)?A.hooks:{};kt(P,`${JSON.stringify({...A,hooks:{...V,PreToolUse:q}},null,2)}
36
+ `)}function Ia(P){let A=Ar(P);if(!Pa(A))return j2(H2(A),{recursive:!0}),Er(A,{},[Pr()]),{path:A,alreadyInstalled:!1};let q=_a(Ea(A,"utf-8"));if(!q)return Er(A,{},[Pr()]),{path:A,alreadyInstalled:!1};let V=Ta(q),ee=V.filter((ne)=>nn(ne)&&Array.isArray(ne.hooks)&&ne.hooks.some(Da));if(ee.length===1&&JSON.stringify(ee[0])===JSON.stringify(Pr()))return{path:A,alreadyInstalled:!0};return Er(A,q,[...Aa(V),Pr()]),{path:A,alreadyInstalled:!1}}function $a(P){let A=Ar(P);if(!Pa(A))return{path:A,alreadyInstalled:!1};let q=_a(Ea(A,"utf-8"));if(!q)return{path:A,alreadyInstalled:!1};let V=Ta(q),ee=Aa(V);if(JSON.stringify(ee)===JSON.stringify(V))return{path:A,alreadyInstalled:!1};let ne=nn(q.hooks)?q.hooks:{};if(ee.length===0&&Object.keys(q).length===1&&Object.keys(ne).length===1)return M2(A),{path:A,alreadyInstalled:!0};return Er(A,q,ee),{path:A,alreadyInstalled:!0}}function Fn(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function B2(P){if(!Fn(P)||!Fn(P.hooks))return[];let A=P.hooks.PreToolUse;if(!Array.isArray(A))return[];return A.filter((q)=>Fn(q)&&Array.isArray(q.hooks)&&q.hooks.some((V)=>Fn(V)&&V.command===On))}function q2(P){let q=(Array.isArray(P.hooks)?P.hooks.filter(Fn):[]).find((V)=>V.command===On);return[...P.matcher===void 0||P.matcher===""||P.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...q?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...q?.timeout===Dr?[]:[`Managed hook "timeout" is not ${Dr}; reinstall to repair`]]}function Oa(P){let A=Ar(P.environment);if(!U2(A))return{platform:"grok-build",status:"n/a",configPath:A};let q;try{q=JSON.parse(G2(A,"utf-8"))}catch(ne){return{platform:"grok-build",status:"n/a",configPath:A,errors:[`Failed to parse Grok Build hooks config ${A}: ${ne instanceof Error?ne.message:String(ne)}`]}}let V=B2(q)[0];if(!V)return{platform:"grok-build",status:"n/a",configPath:A};let ee=q2(V);return{platform:"grok-build",status:"configured",method:"hook config",configPath:A,errors:ee.length>0?ee:void 0}}import{readFileSync as qa}from"node:fs";import{join as Va}from"node:path";var It="cc-safety-net",To="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",V2=30;function Fa(P){return`${To}
37
37
  # version: ${P}
38
- `}function _2(P){return`${Da(P)}name: ${Tt}
38
+ `}function z2(P){return`${Fa(P)}name: ${It}
39
39
  version: "${P}"
40
40
  description: "Block destructive commands and secret-file access before Hermes runs a tool."
41
41
  author: "cc-safety-net"
42
42
  provides_hooks:
43
43
  - pre_tool_call
44
- `}function T2(P){return`${Da(P)}"""CC Safety Net guard for Hermes Agent.
44
+ `}function J2(P){return`${Fa(P)}"""CC Safety Net guard for Hermes Agent.
45
45
 
46
46
  Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
47
47
  adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
48
48
  when the call is allowed and an {"action": "block", ...} directive when it is denied.
49
- Hermes ignores a callback that raises, so every transport and analysis failure is turned
50
- into an explicit block here instead.
49
+ Every transport and analysis failure is returned as a block that names its cause.
51
50
  """
52
51
 
53
52
  import json
@@ -58,15 +57,15 @@ import subprocess
58
57
 
59
58
  HOOK_EVENT = "pre_tool_call"
60
59
  SUPPORTED_TOOLS = ("patch", "read_file", "terminal", "write_file")
61
- ANALYZER = [${Nt["hermes-agent"].split(" ").map((A)=>`"${A}"`).join(", ")}]
62
- TIMEOUT_SECONDS = ${A2}
60
+ ANALYZER = [${jt["hermes-agent"].split(" ").map((A)=>`"${A}"`).join(", ")}]
61
+ TIMEOUT_SECONDS = ${V2}
63
62
 
64
63
 
65
64
  def _block(detail):
66
65
  return {"action": "block", "message": "CC Safety Net failed closed: " + detail}
67
66
 
68
67
 
69
- def _terminal_cwd(task_id, process_cwd):
68
+ def _terminal_cwd(task_id):
70
69
  """Return the directory Hermes will run this terminal command in.
71
70
 
72
71
  A \`terminal\` call without \`workdir\` runs in the session's own cwd RECORD, not in the
@@ -84,10 +83,22 @@ def _terminal_cwd(task_id, process_cwd):
84
83
  return (
85
84
  get_session_cwd(get_current_session_key(default="") or (task_id or ""))
86
85
  or os.environ.get("TERMINAL_CWD")
87
- or process_cwd
86
+ or os.getcwd()
88
87
  )
89
88
 
90
89
 
90
+ def _file_tool_cwd(task_id):
91
+ """Return the directory Hermes resolves this file tool's relative paths against.
92
+
93
+ tools/file_tools.py passes \`task_id or "default"\` to \`_resolve_base_dir\`, which walks the
94
+ session's cwd record, the task's cwd override, \`TERMINAL_CWD\`, then the process directory.
95
+ tools.file_tools defines it up to v2026.8.31 and re-exports it from tools.file_tools_paths since.
96
+ """
97
+ from tools.file_tools import _resolve_base_dir
98
+
99
+ return str(_resolve_base_dir(task_id or "default"))
100
+
101
+
91
102
  def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
92
103
  if tool_name not in SUPPORTED_TOOLS:
93
104
  return None
@@ -97,20 +108,17 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
97
108
  return _block(ANALYZER[0] + " was not found on PATH.")
98
109
 
99
110
  try:
100
- cwd = os.getcwd()
111
+ cwd = _terminal_cwd(task_id) if tool_name == "terminal" else _file_tool_cwd(task_id)
101
112
  except OSError as error:
102
113
  return _block("the working directory could not be resolved (%s)." % error)
103
-
104
- if tool_name == "terminal":
105
- try:
106
- cwd = _terminal_cwd(task_id, cwd)
107
- except ImportError as error:
108
- # Without the session record we cannot tell which directory the command runs in,
109
- # and analysing the wrong one clears every path-scoped protection.
110
- return _block(
111
- "the Hermes session directory could not be read (%s). Update cc-safety-net and "
112
- "reinstall the plugin with: npx -y cc-safety-net install --hermes-agent." % error
113
- )
114
+ except ImportError as error:
115
+ # Without Hermes' own directory lookup we cannot tell which directory the call acts in,
116
+ # and analysing the wrong one clears every path-scoped protection.
117
+ return _block(
118
+ "the Hermes %s directory could not be read (%s). Update cc-safety-net and "
119
+ "reinstall the plugin with: npx -y cc-safety-net install --hermes-agent."
120
+ % ("session" if tool_name == "terminal" else "file tool", error)
121
+ )
114
122
 
115
123
  payload = json.dumps(
116
124
  {
@@ -133,8 +141,8 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
133
141
  stdout=subprocess.PIPE,
134
142
  stderr=subprocess.PIPE,
135
143
  # Decode explicitly: the analyzer writes UTF-8, and a locale decoder would raise
136
- # UnicodeDecodeError on output it cannot read — an exception Hermes swallows by
137
- # allowing the tool call. "replace" turns that into unreadable output, which blocks.
144
+ # UnicodeDecodeError on output it cannot read. "replace" turns that into unreadable
145
+ # output, which blocks with its cause named.
138
146
  encoding="utf-8",
139
147
  errors="replace",
140
148
  # Resolve the analyzer from a neutral directory: npx prefers a repository-local
@@ -203,83 +211,84 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
203
211
 
204
212
  def register(ctx):
205
213
  ctx.register_hook("pre_tool_call", _pre_tool_call)
206
- `}function $n(P){return[{name:"__init__.py",content:T2(P)},{name:"plugin.yaml",content:_2(P)}]}import{mkdirSync as $2,readdirSync as I2,readFileSync as O2,rmSync as Ro}from"node:fs";import{join as tn}from"node:path";var F2="__pycache__";function Po(P){let A=P.env.get("HERMES_HOME")?.trim();return A?A:tn(P.home,".hermes")}function Eo(P){return tn(Po(P),"plugins",Tt)}function Do(P){return P.startsWith(So)}function Ao(P,A){let q=Eo(P),V=bt(q);if(V&&(V.isSymbolicLink()||!V.isDirectory()))throw Error(`Refusing to ${A} ${q}: not a regular directory. Move or remove it and rerun ${A==="install"?"install":"uninstall"} --hermes-agent.`);return q}function Aa(P,A){let q=bt(P);if(!q)return;if(q.isSymbolicLink()||!q.isFile())throw Error(`Refusing to ${A} ${P}: not a regular file. Move or remove it.`);let V=O2(P,"utf-8");if(!Do(V))throw Error(`Refusing to ${A} unmanaged file at ${P}. Move or remove it.`);return V}function _a(P){let A=Ao(P,"install"),q=$n(wt());if(q.map((ee)=>Aa(tn(A,ee.name),"overwrite")).every((ee,ne)=>ee===q[ne]?.content))return{path:A,alreadyInstalled:!0};return $2(A,{recursive:!0}),q.forEach((ee)=>{kt(tn(A,ee.name),ee.content)}),{path:A,alreadyInstalled:!1}}function _o(P){let A=Ao(P,"remove");if(!bt(A))return[];return $n(wt()).filter((q)=>Aa(tn(A,q.name),"remove")!==void 0)}function Ta(P){let A=Ao(P,"remove");if(!bt(A))return{path:A,alreadyInstalled:!1};let q=_o(P);if(q.forEach((V)=>{Ro(tn(A,V.name))}),Ro(tn(A,F2),{recursive:!0,force:!0}),I2(A).length===0)Ro(A,{recursive:!0});return{path:A,alreadyInstalled:q.length>0}}var Cr="hermes-agent",$a=/^([^\s#][^:]*):/,j2=/^\s+([A-Za-z_][\w-]*):/,Ia=/^\s+-\s*(.*)$/;function N2(P){return P.trim().replace(/^(["'])(.*)\1$/,"$2")}function M2(P){let A=P.split(/\r?\n/),q=A.findIndex((ne)=>$a.exec(ne)?.[1]?.trim()==="plugins");if(q===-1)return[];let V=A.slice(q+1),ee=V.findIndex((ne)=>$a.test(ne));return ee===-1?V:V.slice(0,ee)}function Oa(P,A){let q=M2(P),V=q.findIndex((ce)=>j2.exec(ce)?.[1]===A);if(V===-1)return[];let ee=q.slice(V+1),ne=ee.findIndex((ce)=>!Ia.test(ce));return(ne===-1?ee:ee.slice(0,ne)).map((ce)=>N2(Ia.exec(ce)?.[1]??""))}function H2(P){try{return Fa(ja(Po(P),"config.yaml"),"utf-8")}catch{return}}function To(P){let A=H2(P)??"";return Oa(A,"enabled").includes(Tt)&&!Oa(A,"disabled").includes(Tt)}function Na(P){return/^# version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function U2(P,A){let q=bt(P);if(!q)return{error:`${A.name} is missing from ${P}; run install --hermes-agent`};if(q.isSymbolicLink()||!q.isFile())return{error:`${P} is a symlink or not a regular file; move or remove it`};try{let V=Fa(P,"utf-8");if(!Do(V))return{error:`Unmanaged ${A.name} occupies ${P}; move or remove it`};if(Na(V)===wt()&&V!==A.content)return{error:`Modified ${A.name} occupies ${P}; run install --hermes-agent to restore it`};return{content:V}}catch(V){return{error:`Failed to read ${P}: ${V instanceof Error?V.message:String(V)}`}}}function Ma(P){let A=Eo(P.environment),q=ur(Cr,A);if(q)return q;let V=$n(wt()).map((he)=>U2(ja(A,he.name),he)),ee=V.flatMap((he)=>("error"in he)?[he.error]:[]);if(ee.length>0)return{platform:Cr,status:"n/a",configPath:A,errors:ee};let ne=V.some((he)=>("content"in he)&&Na(he.content)!==wt()),ce=ne?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!To(P.environment))return{platform:Cr,status:"disabled",method:"plugin directory",configPath:A,errors:[`${Tt} is not enabled in Hermes; run \`hermes plugins enable ${Tt}\``,...ce]};return{platform:Cr,status:"configured",method:"plugin directory",configPath:A,errors:ne?ce:void 0}}import{existsSync as G2,readFileSync as B2}from"node:fs";import{join as Ha}from"node:path";var q2=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function V2(P){return Ha(P.env.get("KIMI_CODE_HOME")||Ha(P.home,".kimi-code"),"config.toml")}function In(P){let A=V2(P.environment);if(!G2(A))return{platform:"kimi-code",status:"n/a",configPath:A};try{if(!q2.test(B2(A,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:A}}catch(q){return{platform:"kimi-code",status:"n/a",configPath:A,errors:[`Failed to read ${A}: ${q instanceof Error?q.message:String(q)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:A}}import{readFileSync as Ka}from"node:fs";import{join as Fn}from"node:path";var Lt="cc-safety-net",It="index.js",yn="openclaw.plugin.json",vn="package.json";var Sr="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as W2,lstatSync as K2,readdirSync as Y2,readFileSync as Z2}from"node:fs";import{dirname as Ga,join as Gt}from"node:path";import{fileURLToPath as X2}from"node:url";import{spawn as z2}from"node:child_process";function J2(P){return P.join(" ")}function $o(P,A,q){return[`Failed to run ${J2(P)}${A===null?"":` (exit ${A})`}.`,q.trim()].filter(Boolean).join(`
207
- `)}function Io(P){let A={stdout:"",stderr:""};return P.stdout.setEncoding("utf-8"),P.stderr.setEncoding("utf-8"),P.stdout.on("data",(q)=>{A.stdout+=q}),P.stderr.on("data",(q)=>{A.stderr+=q}),A}function _t(P,A){return new Promise((q,V)=>{let ee=Xt([...P],process.env),ne=z2(ee.cmd,ee.args,{stdio:["ignore","pipe","pipe"]}),ce=Io(ne),he=()=>[ce.stdout,ce.stderr].filter(Boolean).join(`
208
- `),ye=A?.timeoutMs??120000,be=setTimeout(()=>{ne.kill(),V(Error($o(P,null,`Timed out after ${ye}ms.
209
- ${he()}`.trim())))},ye);ne.on("error",(xe)=>{clearTimeout(be),V(Error($o(P,null,`${xe.message}
210
- ${he()}`.trim())))}),ne.on("close",(xe)=>{if(clearTimeout(be),xe!==0){V(Error($o(P,xe,he())));return}q(A?.stdoutOnly?ce.stdout:he())})})}async function Oo(P){for(let A of P)await _t(A)}async function Ua(P){for(let A of P)try{await _t(A)}catch(q){console.warn(q instanceof Error?q.message:String(q))}}var Fo=Gt("openclaw",Lt),Q2=[It,yn,vn];function jo(P,A){if(P==="~")return A;if(P.startsWith("~/")||P.startsWith("~\\"))return Gt(A,P.slice(2));return P}function Ba(P){let A=P.env.get("OPENCLAW_STATE_DIR")?.trim();if(A)return jo(A,P.home);let q=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return q?Ga(jo(q,P.home)):Gt(P.home,".openclaw")}function qa(P){let A=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return A?jo(A,P.home):Gt(Ba(P),"openclaw.json")}function No(P){return Gt(Ba(P),"extensions",Lt)}function ef(P){let A=Y2(P);if(A.length===0)return!0;if(A.some((ee)=>!Q2.includes(ee)))return!1;let q=Gt(P,It),V=bt(q);return V!==void 0&&!V.isSymbolicLink()&&V.isFile()&&Z2(q,"utf-8").startsWith(Sr)}function Mo(P){let A=No(P),q=bt(A);if(!q)return;if(!q.isSymbolicLink()&&q.isDirectory()&&ef(A))return;throw Error(`Refusing to modify ${A}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Va(){let P=Ga(X2(import.meta.url));return[Gt(P,Fo),Gt(P,"..",Fo),Gt(P,"..","..","..","dist",Fo)]}function Ho(P=Va()){return P.find((A)=>W2(A)&&K2(A).isDirectory())}function tf(P=Va()){let A=Ho(P);if(!A)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return A}function za(P=tf()){return[["openclaw","plugins","install",P,"--force","--accept-capabilities"]]}function nf(P){let A=(()=>{try{return JSON.parse(P)}catch{return}})(),q=ft(ft(A,"plugin"),"status");return typeof q==="string"?q:void 0}async function Ja(){let P=nf(await _t(["openclaw","plugins","inspect",Lt,"--runtime","--json"],{stdoutOnly:!0}));if(P==="loaded")return;throw Error(`${P===void 0?`The ${Lt} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:`OpenClaw reports the ${Lt} plugin with status "${P}".`} Run \`openclaw plugins inspect ${Lt} --runtime\` for details.`)}var Rr="openclaw",On=`run \`openclaw plugins enable ${Lt}\``;function bn(P,A){let q=Fn(P,A),V=bt(q);if(!V)return{error:`${A} is missing from ${q}; run install --openclaw`};if(V.isSymbolicLink()||!V.isFile())return{error:`${q} is a symlink or not a regular file; move or remove it`};try{return{content:Ka(q,"utf-8")}}catch(ee){return{error:`Failed to read ${q}: ${ee instanceof Error?ee.message:String(ee)}`}}}function Ya(P){try{return JSON.parse(At(P))}catch{return}}function rf(P){let A=bn(P,yn);if("error"in A)return A.error;if(ft(Ya(A.content),"id")===Lt)return;return`${Fn(P,yn)} is not a valid ${Lt} manifest; run install --openclaw`}function of(P){let A=bn(P,vn);if("error"in A)return A.error;let q=ft(ft(Ya(A.content),"openclaw"),"extensions");if(Array.isArray(q)&&q.includes(`./${It}`))return;return`${Fn(P,vn)} does not point OpenClaw at ${It}; run install --openclaw`}function Wa(P){return Array.isArray(P)?P.filter((A)=>typeof A==="string"):[]}function sf(P){let A=qa(P);if(!bt(A))return`${Lt} is not enabled; ${On}`;let q=(()=>{try{return JSON.parse(At(Ka(A,"utf-8")))}catch{return}})();if(q===void 0)return`Failed to read ${A}; fix it, then ${On}`;let V=ft(q,"plugins");if(ft(V,"enabled")===!1)return`plugins.enabled is false in ${A}; no OpenClaw plugin loads`;let ee=ft(ft(ft(V,"entries"),Lt),"enabled");if(Wa(ft(V,"deny")).includes(Lt)||ee===!1)return`${Lt} is disabled in ${A}; ${On}`;let ne=Wa(ft(V,"allow"));if(ne.length>0&&!ne.includes(Lt))return`plugins.allow in ${A} does not list ${Lt}; add it, then ${On}`;if(ne.includes(Lt)||ee===!0)return;return`${Lt} is not enabled; ${On}`}function Za(P){return/^\/\/ version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function af(P,A,q){if(q===void 0)return[];let V=bn(q,It);if(!(("content"in V)&&Za(V.content)===A))return[];return[It,yn,vn].flatMap((ne)=>{let ce=bn(P,ne),he=bn(q,ne);if("error"in ce||"error"in he||ce.content===he.content)return[];return[`Modified ${ne} occupies ${Fn(P,ne)}; run install --openclaw to restore it`]})}function Xa(P){let A=No(P.environment),q=ur(Rr,A);if(q)return q;let V=bn(A,It),ne=["error"in V?V.error:V.content.startsWith(Sr)?void 0:`Unmanaged ${It} occupies ${Fn(A,It)}; move or remove it`,rf(A),of(A)].filter((xe)=>xe!==void 0),ce="content"in V?Za(V.content):void 0,he=ne.length>0?ne:af(A,ce,Ho());if(he.length>0)return{platform:Rr,status:"n/a",configPath:A,errors:he};let ye=ce===wt()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],be=sf(P.environment);if(be)return{platform:Rr,status:"disabled",method:"plugin directory",configPath:A,errors:[be,...ye]};return{platform:Rr,status:"configured",method:"plugin directory",configPath:A,errors:ye.length>0?ye:void 0}}import{existsSync as mf,readFileSync as gf}from"node:fs";import{join as hf}from"node:path";import{existsSync as Pr,readFileSync as Uo,rmSync as lf}from"node:fs";import{join as Bt}from"node:path";import{pathToFileURL as cf}from"node:url";var Er="cc-safety-net",nn=`${Er}@latest`,el=["opencode.json","opencode.jsonc"],Qa="CCSafetyNetPlugin",df={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Dr(P){return P.env.get("OPENCODE_CONFIG_DIR")??Bt(P.env.get("XDG_CONFIG_HOME")||Bt(P.home,".config"),"opencode")}function uf(P){return Bt(Dr(P),el[0])}function tl(P){return el.map((A)=>Bt(Dr(P),A))}function nl(P){return Bt(P.env.get("XDG_CACHE_HOME")||Bt(P.home,".cache"),"opencode","packages",nn)}function rl(P){lf(nl(P),{recursive:!0,force:!0})}async function ol(P){let A=(await _t(["opencode","--version"],{stdoutOnly:!0})).trim(),q=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(A),V=Number(q?.[1]),ee=Number(q?.[2]),ne=Number(q?.[3]);if(!q||V!==1&&V!==2||V===1&&(ee<18||ee===18&&ne<29)||V===2&&ee===0&&ne<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${A||"an unknown version"}.`);if(V===2){for(let ce of tl(P)){if(!Pr(ce))continue;let he=Go(Uo(ce,"utf-8"),ce);if(["plugin","plugins"].some((be)=>{let xe=ft(he,be);return Array.isArray(xe)&&xe.some((Ie)=>Bo(Ie)&&(typeof Ie==="string"?Ie:ft(Ie,"package"))!==nn)}))throw Error(`Change the cc-safety-net package spec in ${ce} to ${nn}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[["opencode","plugin","add",nn],["opencode","plugin","update",nn]],afterInstall:async()=>{let ce=await _t(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(ce))return;throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.")}}}return rl(P),{commands:[["opencode","plugin","-g","-f",nn]],afterInstall:()=>pf(P)}}async function pf(P){let A=Bt(nl(P),"node_modules",Er),q=Bt(A,"package.json");if(!Pr(q))throw Error(`The OpenCode plugin cache at ${A} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${nn}\` for details.`);let V=ft(JSON.parse(Uo(q,"utf-8")),"main");if(typeof V!=="string")throw Error(`The cached OpenCode plugin at ${A} declares no "main" entry.`);let ee=Bt(A,V);if(typeof(await import(cf(ee).href))[Qa]==="function")return;throw Error(`The cached OpenCode plugin at ${ee} does not export a callable ${Qa}, so OpenCode would load nothing and fail open.`)}function Go(P,A){try{return JSON.parse(At(P))}catch(q){if(q instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${A}: ${q.message}`);throw q}}function Bo(P){let A=typeof P==="string"?P:ft(P,"package");return typeof A==="string"&&(A===Er||A.startsWith(`${Er}@`))}function qo(P){return["plugin","plugins"].some((A)=>{let q=ft(P,A);return Array.isArray(q)&&q.some(Bo)})}function ff(P,A){let V=["plugin","plugins"].flatMap((ee)=>{let ne=Xs(P,ee,df);if(!ne)return[];let ce=[],he=0,ye=ne.start+1,be=P.slice(ne.start+1,ne.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let xe of be){if(xe[0].startsWith("//")||xe[0].startsWith("/*"))continue;let Ie=ne.start+1+xe.index;if(he===0)ye=Ie;if(xe[0]==="{"||xe[0]==="[")he++;if(xe[0]==="}"||xe[0]==="]")he--;if(he!==0||xe[0]===",")continue;let Xe=Ie+xe[0].length;if(Bo(JSON.parse(At(P.slice(ye,Xe)))))ce.push({start:ye,end:Xe})}return ce}).sort((ee,ne)=>ee.start-ne.start).reverse().reduce((ee,ne)=>{let ce=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(ee.slice(ne.end));if(ce?.[0].includes("/")){let he=ne.end+ce[0].length-1;return ee.slice(0,ne.start)+ee.slice(ne.end,he)+ee.slice(he+1)}return fr(ee,ne)},P);return Go(V,A),V}function il(P){rl(P);let A=tl(P),q=A.find((ne)=>Pr(ne)),V=[],ee=[];for(let ne of A){if(!Pr(ne))continue;try{let ce=Uo(ne,"utf-8");if(!qo(Go(ce,ne)))continue;kt(ne,ff(ce,ne)),ee.push(ne)}catch(ce){V.push(ce instanceof Error?ce.message:String(ce))}}if(V.length>0)throw Error(V.join(`
211
- `));return{path:ee[0]??q??uf(P),alreadyInstalled:ee.length>0}}function sl(P){let A=[],q=Dr(P.environment),V=["opencode.json","opencode.jsonc"];for(let ee of V){let ne=hf(q,ee);if(mf(ne))try{let ce=gf(ne,"utf-8"),he=At(ce),ye=JSON.parse(he);if(qo(ye))return{platform:"opencode",status:"configured",method:"plugin array",configPath:ne,errors:A.length>0?A:void 0}}catch(ce){A.push(`Failed to parse ${ee}: ${ce instanceof Error?ce.message:String(ce)}`)}}return{platform:"opencode",status:"n/a",errors:A.length>0?A:void 0}}import{join as yf}from"node:path";function Vo(P){return yf(P.home,".pi","agent","settings.json")}function zo(P){if(typeof P!=="string")return!1;return P==="npm:cc-safety-net"||P.startsWith("npm:cc-safety-net@")}function al(P){let A=Vo(P.environment),q=Ft(A);if(q.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(q.kind==="missing")return{platform:"pi",status:"n/a"};let V=ft(q.value,"packages");if(!Array.isArray(V))return{platform:"pi",status:"n/a"};let ee=V.find((he)=>zo(typeof he==="string"?he:ft(he,"source")));if(ee===void 0)return{platform:"pi",status:"n/a"};let ne=ft(ee,"extensions");if(Array.isArray(ne)&&ne.some((he)=>typeof he==="string"&&he.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:A,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:A}}var vf={amp:Gs,"antigravity-cli":Bs,"claude-code":Js,codex:Ws,"copilot-cli":ca,cursor:ya,"gemini-cli":va,"grok-build":Ea,"hermes-agent":Ma,"kimi-code":In,openclaw:Xa,opencode:sl,pi:al};function Ln(P,A,q){let V={...q,cwd:A,environment:P};return Zn.map((ee)=>bf(vf[ee](V)))}function bf(P){if(P.status==="not-inspected")return{platform:P.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:P.platform,detected:P.status!=="n/a",configured:P.status==="configured",inspectionStatus:P.status!=="n/a"?"verified":P.errors&&P.errors.length>0?"failed":"not-applicable",method:P.method,configPath:P.configPath,configPaths:P.configPaths,errors:P.errors}}import{join as Lf}from"node:path";var wf=Object.freeze([{command:"git reset --hard",description:"git reset --hard",expectBlocked:!0},{command:"rm -rf /",description:"rm -rf /",expectBlocked:!0},{command:"rm -rf ./node_modules",description:"rm in cwd (safe)",expectBlocked:!1}]),kf=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),xf={strict:!1,paranoidRm:!1,paranoidInterpreters:!1,worktreeMode:!1,effectiveLevel:"standard",capabilities:{fail_closed:{enabled:!1,source:"preset",sources:[]},paranoid_rm:{enabled:!1,source:"preset",sources:[]},paranoid_interpreters:{enabled:!1,source:"preset",sources:[]}}};function ll(P){let A=Lf(P.tmpdir,"cc-safety-net-self-test"),q=wf.map((V)=>{let ee=N(P,d("self-test",{command:V.command},{kind:"command",shell:"auto"},{configCwd:A,executionCwd:A},V.command),{guard:{dependencies:{loadPolicySnapshot:()=>kf,getModes:()=>xf,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),ne=V.expectBlocked?"blocked":"allowed",ce=ee.decision.kind==="deny"?"blocked":"allowed";return{command:V.command,description:V.description,expected:ne,actual:ce,passed:ne===ce,reason:ee.decision.kind==="deny"?ee.decision.reason:void 0,ruleId:ee.decision.kind==="deny"?ee.decision.ruleId:void 0}});return{passed:q.filter((V)=>V.passed).length,failed:q.filter((V)=>!V.passed).length,total:q.length,results:q}}function Jo(P){let A=xt({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},P);if(Ht(A.errors))return null;return{json:A.flags.json,skipUpdateCheck:A.flags.skipUpdateCheck}}async function cl(P,A={}){let q=await Pn(!A.json,()=>{let V=Cf(P,A);return{ready:V,finish:()=>V}},()=>Rn(),{loadingMessage:"Checking system status…"});if(A.json)console.log(JSON.stringify(q,null,2));else Sf(q);return q.engineSelfTest.failed>0||q.findings.some((V)=>V.severity==="error")?1:0}async function Cf(P,A){let q=A.cwd??process.cwd(),V=await sr(),ee=Ln(P,q,{ampPluginListOutput:V.ampPluginListOutput,codexPluginListOutput:V.codexPluginListOutput,copilotCliVersion:V.versions["copilot-cli"]}),ne=os(P,q),ce=is(P),he=E(P,{cwd:q}),ye=he.policy,be=R(ye,P.env),xe=H(ye,be.capabilities),Ie=tr(P,7),Xe=js(P,q),et=A.skipUpdateCheck?{currentVersion:wt(),latestVersion:null,updateAvailable:!1}:await Wt(),Re={hooks:ee,engineSelfTest:ll(P),userConfig:ne.userConfig,projectConfig:ne.projectConfig,configState:Ne(he),effectiveRules:ne.effectiveRules,environment:ce,effectiveSafety:{selectedPreset:ye.safety.level??"standard",level:be.effectiveLevel,capabilities:be.capabilities,ruleOverrides:ye.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(xe).filter(([,at])=>at.source==="rule_override"&&at.override==="off"&&at.inheritedEnabled&&at.changesInherited).map(([at])=>at),ruleCounts:{stored:Object.keys(ye.destructiveCommandRuleOverrides).length,effective:Object.values(xe).filter((at)=>at.changesInherited).length},...he.policyScopes?{policyScopes:he.policyScopes}:{}},...Xe.length>0?{v2Leftovers:Xe}:{},posture:bs(P,ne.userConfig.path),activity:Ie,update:et,system:V};return{...Re,findings:as(Re)}}function Sf(P){console.log(),console.log(cs(P.hooks)),console.log(),console.log(ds(P.engineSelfTest)),console.log(),console.log(us(P)),console.log(),console.log(ps(P.environment)),console.log(),console.log(fs(P)),console.log(),console.log(ms(P.findings)),console.log(),console.log(gs(P.activity)),console.log(),console.log(ys(P.system)),console.log(),console.log(hs(P.update)),console.log(vs(P))}import{existsSync as Rf}from"node:fs";var Pf=/^[A-Za-z0-9_@%+=:,./-]+$/,dl="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Wo(P){let A=xt({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},P);if(Ht(A.errors))return console.error(dl),console.error("Pass -- before a command that starts with dashes."),null;if(A.values.cwd!==void 0&&!Rf(A.values.cwd))return console.error(`Error: --cwd path does not exist: ${A.values.cwd}`),null;let q=A.positionals.length===1?A.positionals[0]:A.positionals.map((V)=>Pf.test(V)?V:`'${V.replaceAll("'","'\\''")}'`).join(" ");if(!q)return console.error("Error: No command provided"),console.error(dl),null;return{json:A.flags.json,cwd:A.values.cwd,command:q}}function ul(P){if(P)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function pl(P,A){let V=A-18;return[`${P.dtl}${P.dh.repeat(A)}${P.dtr}`,`${P.dv} Command Analysis${" ".repeat(V)}${P.dv}`,`${P.dbl}${P.dh.repeat(A)}${P.dbr}`]}function Ko(P){return JSON.stringify(P)}function fl(P,A=0){return`[${P.map((V,ee)=>ls(V,ee,A)).join(",")}]`}function jn(P,A,q=70){let V=P.split(" "),ee=[],ne="";for(let ce of V)if(ne&&ne.length+ce.length+1>q)ee.push(ne),ne=ce;else ne=ne?`${ne} ${ce}`:ce;if(ne)ee.push(ne);return ee.map((ce,he)=>he===0?ce:`${A}${ce}`)}function ml(P,A,q){let V=[];switch(P.type){case"parse":return null;case"env-strip":return V.push(""),V.push(`STEP ${A} ${q.h} Strip environment variables`),V.push(` Removed: ${P.envVars.map((ee)=>`${ee}=<redacted>`).join(", ")}`),V.push(` Tokens: ${Ko(P.output)}`),{lines:V,incrementStep:!0};case"leading-tokens-stripped":return V.push(""),V.push(`STEP ${A} ${q.h} Strip wrappers`),V.push(` Removed: ${P.removed.join(", ")}`),V.push(` Tokens: ${Ko(P.output)}`),{lines:V,incrementStep:!0};case"shell-wrapper":return V.push(""),V.push(`STEP ${A} ${q.h} Detect shell wrapper`),V.push(` Wrapper: ${P.wrapper} -c`),V.push(` Inner: ${P.innerCommand}`),{lines:V,incrementStep:!0};case"interpreter":{if(V.push(""),V.push(`STEP ${A} ${q.h} Detect interpreter`),V.push(` Interpreter: ${P.interpreter}`),V.push(` Code: ${P.codeArg}`),P.paranoidBlocked)V.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:V,incrementStep:!0}}case"busybox":return V.push(""),V.push(`STEP ${A} ${q.h} Busybox wrapper`),V.push(` Subcommand: ${P.subcommand}`),{lines:V,incrementStep:!0};case"transparent-wrapper":return V.push(""),V.push(`STEP ${A} ${q.h} Transparent wrapper`),V.push(` Wrapper: ${P.wrapper}`),V.push(` Tokens: ${Ko(P.output)}`),{lines:V,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(V.push(""),V.push(`STEP ${A} ${q.h} Match rules`),V.push(` Rule: ${P.rule}()`),P.matched)V.push(" Result: MATCHED");else V.push(" Result: No match");return{lines:V,incrementStep:!0}}case"worktree-relaxation":return V.push(""),V.push(`STEP ${A} ${q.h} Worktree relaxation`),V.push(` Mode: ${o.worktree.name}`),V.push(` Git cwd: ${P.gitCwd}`),V.push(" Result: Allowed local discard in linked worktree"),{lines:V,incrementStep:!0};case"temp-root-relaxation":return V.push(""),V.push(`STEP ${A} ${q.h} Temp-root relaxation`),V.push(` Git cwd: ${P.gitCwd}`),V.push(" Result: Allowed git discard in a temp-root repository"),{lines:V,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(P.embeddedCommandFound)return V.push(""),V.push(`STEP ${A} ${q.h} Fallback scan`),V.push(` Found: ${P.embeddedCommandFound}`),{lines:V,incrementStep:!0};return null}case"custom-rules-check":{if(P.rulesChecked){if(V.push(""),V.push(`STEP ${A} ${q.h} Custom rules`),P.matched)V.push(" Result: MATCHED");else V.push(" Result: No match");return{lines:V,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(P.matched)return V.push(""),V.push(`STEP ${A} ${q.h} Dangerous text check`),V.push(` Token: ${P.token}`),V.push(" Result: MATCHED"),{lines:V,incrementStep:!0};return null}case"strict-unparseable":return V.push(""),V.push(`STEP ${A} ${q.h} Strict mode check`),V.push(` Command: ${P.rawCommand}`),V.push(" Result: ✗ UNPARSEABLE"),{lines:V,incrementStep:!0};case"segment-skipped":return null;case"error":return V.push(""),V.push(`ERROR: ${P.message}`),{lines:V,incrementStep:!1};default:return P}}function Yo(P,A){let q=ul(A?.asciiOnly??!1),V=58,ee=[],ne=1;ee.push(...pl(q,58)),ee.push("");let ce=P.trace.steps.find((Re)=>Re.type==="error");if(ce&&ce.type==="error"){ee.push("ERROR"),ee.push(` ${ce.message}`),ee.push(""),ee.push("RESULT"),ee.push(` Status: ${P.result==="blocked"?dt.red("BLOCKED"):dt.green("ALLOWED")}`),ee.push(""),ee.push("CONFIG");let Re=P.configSource??"none";return ee.push(` Path: ${Re}`),ee.join(`
212
- `)}let he=P.trace.steps.find((Re)=>Re.type==="parse");if(he&&he.type==="parse"){ee.push("INPUT"),ee.push(` ${he.input}`),ee.push(""),ee.push(`STEP ${ne} ${q.h} Split shell commands`),ne++;for(let Re=0;Re<he.segments.length;Re++){let at=he.segments[Re];if(at){let ct=Math.random();ee.push(` Segment ${Re+1}: ${fl(at,ct)}`)}}}let ye=P.trace.segments,be=ye.length>1;for(let Re of ye){if(be){ee.push("");let pt="";if(he&&he.type==="parse"){let Xr=he.segments[Re.index];if(Xr)pt=Xr.join(" ")}let mt=54,gt=pt,ut=` Segment ${Re.index+1}: `,yt=" ";if(pt){if(ut.length+pt.length+yt.length>mt){let Hd=mt-ut.length-yt.length;gt=`${pt.substring(0,Hd-1)}…`}}let Dt=pt?`${ut}${gt}${yt}`:` Segment ${Re.index+1} `,Nd=pt?`${ut}${dt.cyan(gt)}${yt}`:Dt,$i=58-Dt.length,Ii=Math.floor($i/2),Md=$i-Ii;ee.push(`${q.sh.repeat(Ii)}${Nd}${q.sh.repeat(Md)}`)}if(Re.steps.find((pt)=>pt.type==="segment-skipped")){ee.push(""),ee.push(" (skipped — prior segment blocked)");continue}let ct=!1,lt=!1;for(let pt of Re.steps){let mt=ml(pt,ne,q);if(mt){if(lt=!0,pt.type==="recurse"){ee.push("");let gt=" RECURSING ",ut=58-gt.length-4;ee.push(` ${q.tl}${q.h}${gt}${q.h.repeat(ut)}`),ee.push(` ${q.v}`),ct=!0;continue}for(let gt of mt.lines)if(ct)ee.push(` ${q.v} ${gt}`);else ee.push(gt);if(mt.incrementStep)ne++}}if(ct)ee.push(` ${q.v}`),ee.push(` ${q.bl}${q.h.repeat(56)}`);if(!lt)ee.push(""),ee.push(` ${dt.green("✓")} Allowed (no matching rules)`)}if(ee.push(""),ee.push("RESULT"),P.result==="blocked"){if(ee.push(` Status: ${dt.red("BLOCKED")}`),P.customRule){if(ee.push(` Rule: ${P.customRule.id}`),P.customRule.rulebook)ee.push(` Rulebook: ${P.customRule.rulebook.name} ${P.customRule.rulebook.version}`);if(P.customRule.source)ee.push(` Source: ${P.customRule.source}`);if(P.customRule.override)ee.push(` Override: reason ${P.customRule.override.reason}`)}if(P.reason){let Re=jn(P.reason," ");ee.push(` Reason: ${Re[0]}`);for(let at=1;at<Re.length;at++)ee.push(Re[at]??"")}}else ee.push(` Status: ${dt.green("ALLOWED")}`);ee.push(""),ee.push("CONFIG");let xe=P.configSource??"none",Ie=P.configValid?"":" (invalid)";ee.push(` Path: ${xe}${Ie}`);let Xe=P.safetyPresetScope;ee.push(` Safety preset: ${P.selectedPreset??"standard"}${Xe?` (${rr(Xe)})`:""}`),ee.push(` Effective capabilities: ${P.effectiveLevel}`);let et=Object.entries(P.destructiveCommandRuleOverrides??{});if(ee.push(` Rule customizations: ${et.length}`),P.ruleActivation)ee.push(` Rule activation: ${P.ruleActivation.id} — ${P.ruleActivation.enabled?"on":"off"} via ${P.ruleActivation.source}`);return ee.join(`
213
- `)}function Zo(P){return JSON.stringify(P,null,2)}import{resolve as Tf}from"node:path";var Ef=["AKIA","ASIA","ghp_","gho_","ghu_","ghs_","ghr_","github_pat_","glpat-","xox","npm_","pypi-","rk_","sk-","sk_","gsk_","xai-","pplx-","bastn_","tgp_v1_","flp_","wfr_","fw_","fwp_","tp-","psk-"];function gl(P){let A=0,q={allocateSegment(){return A++},getNextSegmentIndex(){return A},recordGlobal(V){P.record({kind:"step",scope:"global",step:V})},recordSegment(V,ee=q.currentSegmentIndex){if(ee===void 0)return;P.record({kind:"step",scope:"segment",segmentIndex:ee,step:V})}};return q}function hl(P={}){let A=[],q=P.maxEvents??512,V={maxTextLength:P.maxTextLength??2048,maxListLength:P.maxListLength??128,maxObjectProperties:P.maxObjectProperties??P.maxListLength??128,maxDepth:P.maxDepth??16},ee,ne=new Set;return{record(ce){if(ee)return;if(!ce||A.length>=q)return;try{A.push(ei(Df(ce,V,ne)))}catch{}},finish(){if(ee)return ee;return ee=ei({events:Object.freeze(A)}),ee}}}function Df(P,A,q){if(P.kind!=="step")throw TypeError("invalid trace event");let{scope:V,step:ee}=P;Ar(ee,q,A);let ne=Xo(ee,A,q);if(V==="global")return{kind:"step",scope:"global",step:ne};if(V!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:P.segmentIndex,step:ne}}function Ar(P,A,q,V=0,ee=new WeakSet){if(typeof P==="string"){let he=P.slice(0,q.maxTextLength);if(!Ge(he))return;for(let ye of Ze(he))for(let be of ye.match(/[^\s"'()$]+/g)??[])A.add(yl(be));return}if(!P||typeof P!=="object"||V>=q.maxDepth||ee.has(P))return;if(ee.add(P),Array.isArray(P)){let he=Math.min(P.length,q.maxListLength);for(let ye=0;ye<he;ye++)Ar(P[ye],A,q,V+1,ee);return}let ne=0,ce=new Set;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ne>=q.maxObjectProperties)break;ne++,Ar(he,A,q);let ye=Qo(he,q,A);if(ce.has(ye))continue;ce.add(ye),Ar(P[he],A,q,V+1,ee)}}function Xo(P,A,q,V=0,ee=new WeakSet){if(typeof P==="string")return Qo(P,A,q);if(!P||typeof P!=="object")return P;if(V>=A.maxDepth)return;if(ee.has(P))return;if(ee.add(P),Array.isArray(P)){let he=[],ye=Math.min(P.length,A.maxListLength);for(let be=0;be<ye;be++)he.push(Xo(P[be],A,q,V+1,ee));return he}let ne={},ce=0;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ce>=A.maxObjectProperties)break;ce++;let ye=Qo(he,A,q);if(Object.hasOwn(ne,ye))continue;Object.defineProperty(ne,ye,{value:Xo(P[he],A,q,V+1,ee),enumerable:!0,configurable:!0,writable:!0})}return ne}function Qo(P,A,q){let V=P.slice(0,A.maxTextLength),ee=Ge(V)?Ue(V):V,ne=q.size>0?_f(ee,q):ee;return(Af(ne)?ke(ne):ne).slice(0,A.maxTextLength)}function Af(P){return P.includes("PRIVATE KEY")||P.includes("://")||P.includes("eyJ")||P.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(P)||P.length>=14&&Ef.some((A)=>P.includes(A))||P.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(P)}function _f(P,A){return P.replace(/[^\s"'()$]+/g,(q)=>A.has(yl(q))?"<redacted>":q)}function yl(P){let A=2166136261,q=2166136261;for(let V=0;V<P.length;V++)A=Math.imul(A^P.charCodeAt(V),16777619),q=Math.imul(q^P.charCodeAt(P.length-V-1),16777619);return`${A>>>0}:${q>>>0}:${P.length}`}function ei(P){if(P&&typeof P==="object"&&!Object.isFrozen(P)){for(let A of Object.values(P))ei(A);Object.freeze(P)}return P}function Nn(P,A={},q){let V=Tf(A.cwd??process.cwd()),ee=A.policySnapshot??E(q,{cwd:V,userConfigDir:A.userConfigDir}),ne=R(ee.policy,q.env),ce=Fe({policySnapshot:ee,effectiveCapabilities:ne.capabilities,strict:ne.strict,paranoidRm:ne.paranoidRm,paranoidInterpreters:ne.paranoidInterpreters,worktreeMode:ne.worktreeMode}),he={effectiveLevel:ce.effectiveLevel,selectedPreset:ee.policy.safety.level??"standard",...ee.policyScopes?{safetyPresetScope:ee.policyScopes.levelScope}:{},effectiveCapabilities:ce.effectiveCapabilities,destructiveCommandRuleOverrides:ee.policy.destructiveCommandRuleOverrides},{configSource:ye,configValid:be}=If(q,{cwd:V,userConfigDir:A.userConfigDir});if(!P||!P.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:ye,configValid:be,...he};let xe=h(P,"auto");if(xe.status==="limited")throw new y;let Ie=xe.dialect==="powershell"?h(P,"posix"):xe,Xe=st(Ie),et=hl(),Re=gl(et);Re.recordGlobal({type:"parse",input:P,segments:Xe.map((Dt)=>[...Dt])});let at=d("Bash",{command:P},{kind:"command",shell:"auto"},{configCwd:V,executionCwd:V},P),ct=B(at,{environment:q,trace:Re,dependencies:{loadPolicySnapshot:()=>ee}}),lt=ct.decision.kind==="deny"?ct.decision:null;if(lt&&(ct.stage==="policy-protection"||ct.stage==="secret-protection")){let Dt=$f(lt);return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Dt.rule,matched:!0,reason:lt.reason}]}]},result:"blocked",reason:k(lt.reason),segment:k(vl(lt,P)),...Dt.ruleId?{ruleId:k(Dt.ruleId)}:{},configSource:ye,configValid:be,...he}}let pt=Re.getNextSegmentIndex();if(lt&&pt>0&&pt<Xe.length)Re.recordSegment({type:"segment-skipped",index:pt,reason:"prior-segment-blocked"},pt);let mt=et.finish(),gt=lt?.ruleId??Of(at,ee,ne,q),ut=G.find((Dt)=>Dt.id===gt&&Dt.activationCapability),yt=ut?ce.policy.effectiveDestructiveCommandRules[ut.id]:void 0;return{trace:jf(mt),result:lt?"blocked":"allowed",reason:lt?k(lt.reason):void 0,segment:lt?k(vl(lt,P)):void 0,ruleId:lt?.ruleId?k(lt.ruleId):void 0,customRule:Ff(Nf(lt?.ruleId,ee)),configSource:ye,configValid:be,...he,...ut&&yt?{ruleActivation:{id:ut.id,...yt}}:{}}}function vl(P,A){return P.evidence?.segment??A}function $f(P){if(P.reason===$e)return{ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};if(P.reason===Me)return{ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};if(P.reason===x)return{ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};return{ruleId:P.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"}}function If(P,A){let q=M(A.cwd),V=j(P,A),ee=J(P,{cwd:A.cwd,userConfigDir:A.userConfigDir});try{if(n(ee.projectConfigTarget)!==null){if(Jt(ee.projectConfigTarget).errors.length===0)return{configSource:q,configValid:!0};return{configSource:q,configValid:!1}}}catch(ne){if(ne instanceof r)return{configSource:q,configValid:!1};throw ne}try{if(n(ee.userConfigTarget)!==null){let ne=Jt(ee.userConfigTarget);return{configSource:V,configValid:ne.errors.length===0}}return{configSource:null,configValid:!0}}catch(ne){if(ne instanceof r)return{configSource:V,configValid:!1};throw ne}}function Of(P,A,q,V){let ee=A.policy,ne=Ee({...ee,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...ee.destructiveCommandRuleOverrides,...Object.fromEntries(G.flatMap((he)=>he.activationCapability?[[he.id,"on"]]:[]))}},A.state==="degraded"?{diagnostics:A.diagnostics,reason:A.reason}:void 0),ce=B(P,{environment:V,dependencies:{loadPolicySnapshot:()=>ne,getModes:()=>({...q,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return ce.decision.kind==="deny"?ce.decision.ruleId:void 0}function Ff(P){if(!P)return;return{id:k(P.id),...P.rulebook?{rulebook:{name:k(P.rulebook.name),version:k(P.rulebook.version)}}:{},...P.source?{source:k(P.source)}:{},...P.override?{override:{type:"reason",reason:k(P.override.reason)}}:{}}}function jf(P){let A=P.events.flatMap((V)=>V.kind==="step"&&V.scope==="global"?[V.step]:[]),q=new Map;for(let V of P.events){if(V.kind!=="step"||V.scope!=="segment")continue;let ee=q.get(V.segmentIndex)??{index:V.segmentIndex,steps:[]};ee.steps.push(V.step),q.set(V.segmentIndex,ee)}return{steps:A,segments:[...q.values()]}}function Nf(P,A){let q=P?.replace(/^custom\./,"");if(!q||!A.policy.rules.some((V)=>V.name===q))return;return A.ruleMetadata[q]??Object.freeze({id:q})}function bl(P){return new Promise((A)=>{process.stdout.write(`${P}
214
- `,()=>A())})}async function Ll(P,A){let q=Wo(A);if(!q)return 1;try{let V=Nn(q.command,{cwd:q.cwd},P),ee=!!process.env.NO_COLOR||!process.stdout.isTTY;return await bl(q.json?Zo(V):Yo(V,{asciiOnly:ee})),0}catch(V){let ee=Mf(V instanceof p?V.cause:V);if(ee===void 0)throw V;if(q.json)return await bl(JSON.stringify({error:ee})),1;return console.error(ee),1}}function Mf(P){if(P instanceof y)return P.message;if(P instanceof f)return P.message;if(P instanceof s&&a[P.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var wl="2.4.12",Ot=" ",rn="cc-safety-net";function kl(P){return P.argument?`${P.flags} ${P.argument}`:P.flags}function Hf(P){return Math.max(...P.map((A)=>kl(A).length))}function Uf(P){return Math.max(...P.map((A)=>A.usage.length))}function Gf(P){return Math.max(...P.map((A)=>`${rn} ${A.usage}`.length))}function Bf(P,A){let q=`${rn} ${P.usage}`;return`${Ot}${q.padEnd(A+2)}${P.description}`}function qt(P,A){return`${Ot}${P.padEnd(Math.max(40,P.length+2))}${A}`}function wn(P,A=console.log){let q=[];if(q.push(`${rn} ${P.name}`),q.push(""),q.push(`${Ot}${P.description}`),q.push(""),q.push("USAGE:"),q.push(`${Ot}${rn} ${P.usage}`),q.push(""),P.subcommands&&P.subcommands.length>0){q.push("SUBCOMMANDS:");let V=Uf(P.subcommands);for(let ee of P.subcommands)q.push(`${Ot}${ee.usage.padEnd(V+2)}${ee.description}`);q.push("")}if(P.options.length>0){q.push("OPTIONS:");let V=Hf(P.options);for(let ee of P.options){let ne=kl(ee),ce=ee.default?`${ee.description} (default: ${ee.default})`:ee.description;q.push(`${Ot}${ne.padEnd(V+2)}${ce}`)}q.push("")}if(P.examples&&P.examples.length>0){q.push("EXAMPLES:");for(let V of P.examples)q.push(`${Ot}${V}`)}A(q.join(`
215
- `))}function ti(){let P=Gf(Qn),A=[];A.push(`${rn} v${wl}`),A.push(""),A.push("Blocks destructive commands and secret access."),A.push(""),A.push("COMMANDS:");for(let q of Qn)A.push(Bf(q,P));A.push(""),A.push("GLOBAL OPTIONS:"),A.push(`${Ot}-h, --help Show help (use with command for command-specific help)`),A.push(`${Ot}-V, --version Show version`),A.push(""),A.push("HELP:"),A.push(`${Ot}${rn} help <command> Show help for a specific command`),A.push(`${Ot}${rn} <command> --help Show help for a specific command`),A.push(""),A.push("ENVIRONMENT VARIABLES:"),A.push(qt(`${o.level.name}=standard|strict|paranoid`,"Set session safety level")),A.push(qt(`${o.worktree.name}=1`,"Allow local git discards in linked worktrees")),A.push(qt(`${o.debug.name}=1`,"Print diagnostic messages to stderr")),A.push(qt(`${o.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),A.push(qt("CC_SAFETY_NET_HOME","Override rule config home directory")),A.push(""),A.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),A.push(qt(`${o.strict.name}=1`,"Force safety.overrides.fail_closed on")),A.push(qt(`${o.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),A.push(qt(`${o.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),A.push(qt(`${o.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),A.push(""),A.push("Documentation: https://ccsafetynet.com/docs"),console.log(A.join(`
216
- `))}function xl(){console.log(wl)}function Mn(P,A=console.log){let q=er(P);if(!q)return!1;if(q.name.toLowerCase()!==P.toLowerCase())return!1;return wn(q,A),!0}import{existsSync as mi,readFileSync as bc}from"node:fs";import{join as pi}from"node:path";import*as Kt from"node:readline";function qf(P){return P==="install"?"Install":"Uninstall"}function Vf(P){return P==="install"?"Installing":"Uninstalling"}function zf(P){return P==="install"?"into":"from"}function Rl(P){return P?.available===!0}function Jf(P,A){let q=new Set(A);return P.filter((V)=>q.has(V.target)).map((V)=>V.target)}function Cl(P,A,q){if(P.every((V)=>!V.available))return A;return Array.from({length:P.length},(V,ee)=>ee+1).map((V)=>(A+V*q+P.length)%P.length).find((V)=>Rl(P[V]))}function Wf(P,A,q){if(q.ctrl&&q.name==="c")return"interrupt";if(q.name==="escape"||A==="q")return"abort";if(P==="install"&&(A==="u"||A==="U"))return"update";if(q.name==="up"||A==="k")return"up";if(q.name==="down"||A==="j")return"down";if(q.name==="space"||A===" ")return"toggle";if(q.name==="return"||q.name==="enter")return"confirm";return null}function Kf(P){return{cursor:P.findIndex((A)=>A.available),selected:[]}}function Yf(P,A,q){if(q==="confirm"||q==="update"||q==="abort"||q==="interrupt")return{state:P,done:q};if(q==="up")return{state:{...P,cursor:Cl(A,P.cursor,-1)}};if(q==="down")return{state:{...P,cursor:Cl(A,P.cursor,1)}};let V=A[P.cursor];if(!Rl(V))return{state:P};let ee=P.selected.includes(V.target)?P.selected.filter((ne)=>ne!==V.target):Jf(A,[...P.selected,V.target]);return{state:{...P,selected:ee}}}var Pl="◉",El="◯",Dl=">",Al=" ";function Zf(P,A,q,V={}){let ee=V.color!==!1,ne=ee?dt.dim:(ye)=>ye,ce=ee?dt.green:(ye)=>ye,he=ee?dt.bold:(ye)=>ye;return["",`${qf(P)} CC Safety Net ${zf(P)}:`,"",...A.map((ye,be)=>{let xe=q.selected.includes(ye.target),Ie=be===q.cursor,Xe=xe?Pl:El,et=Ie?Dl:Al,Re=ye.available?"":` (${ye.unavailableReason??"not installed"})`,at=`${Xe} ${ye.label}${Re}`,ct=!ye.available?ne(at):xe?ce(at):Ie?he(at):at;return`${et} ${ct}`}),"",P==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":A.some((ye)=>ye.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${P}. q/Esc: close`].join(`
217
- `)}var Sl=["global-hook","plugin"];function Xf(P,A,q={}){let V=q.color!==!1?dt.bold:(ne)=>ne;return["","Install the Kimi Code integration as:","",...[`Global hook — ${A?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((ne,ce)=>{let he=ce===P,ye=`${he?Pl:El} ${ne}`;return`${he?Dl:Al} ${he?V(ye):ye}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
218
- `)}function _l(P){let{input:A,output:q}=P;Kt.emitKeypressEvents(A);let V=A.isRaw===!0;A.setRawMode(!0),A.resume();let ee=0,ne=()=>{if(ee===0)return;Kt.moveCursor(q,0,-ee),Kt.cursorTo(q,0),Kt.clearScreenDown(q)},ce=()=>{ne();let he=P.render();q.write(`${he}
214
+ `}function Nn(P){return[{name:"__init__.py",content:J2(P)},{name:"plugin.yaml",content:z2(P)}]}import{mkdirSync as W2,readdirSync as K2,readFileSync as Na,rmSync as Io}from"node:fs";import{basename as Y2,dirname as X2,join as Bt}from"node:path";var Z2="__pycache__",Q2=/^[a-z0-9][a-z0-9_-]{0,63}$/;function ef(P){try{return Na(P,"utf-8").trim()}catch{return}}function $o(P){let A=P.env.get("HERMES_HOME")?.trim();if(A&&Y2(X2(A))==="profiles")return A;let q=A||Bt(P.home,".hermes"),V=Bt(q,"active_profile"),ee=ef(V),ne=ee?.toLowerCase();if(!ne||ne==="default")return q;if(!Q2.test(ne))throw Error(`Invalid Hermes profile name "${ee}" in ${V}; run \`hermes profile use <name>\` with a valid profile.`);return Bt(q,"profiles",ne)}function Oo(P){return Bt($o(P),"plugins",It)}function Fo(P){return P.startsWith(To)}function No(P,A){let q=Oo(P),V=Lt(q);if(V&&(V.isSymbolicLink()||!V.isDirectory()))throw Error(`Refusing to ${A} ${q}: not a regular directory. Move or remove it and rerun ${A==="install"?"install":"uninstall"} --hermes-agent.`);return q}function ja(P,A){let q=Lt(P);if(!q)return;if(q.isSymbolicLink()||!q.isFile())throw Error(`Refusing to ${A} ${P}: not a regular file. Move or remove it.`);let V=Na(P,"utf-8");if(!Fo(V))throw Error(`Refusing to ${A} unmanaged file at ${P}. Move or remove it.`);return V}function Ma(P){let A=No(P,"install"),q=Nn(wt());if(q.map((ee)=>ja(Bt(A,ee.name),"overwrite")).every((ee,ne)=>ee===q[ne]?.content))return{path:A,alreadyInstalled:!0};return W2(A,{recursive:!0}),q.forEach((ee)=>{kt(Bt(A,ee.name),ee.content)}),{path:A,alreadyInstalled:!1}}function jo(P){let A=No(P,"remove");if(!Lt(A))return[];return Nn(wt()).filter((q)=>ja(Bt(A,q.name),"remove")!==void 0)}function Ha(P){let A=No(P,"remove");if(!Lt(A))return{path:A,alreadyInstalled:!1};let q=jo(P);if(q.forEach((V)=>{Io(Bt(A,V.name))}),Io(Bt(A,Z2),{recursive:!0,force:!0}),K2(A).length===0)Io(A,{recursive:!0});return{path:A,alreadyInstalled:q.length>0}}var jn="hermes-agent",Ua=/^([^\s#][^:]*):/,tf=/^\s+([A-Za-z_][\w-]*):/,Ga=/^\s+-\s*(.*)$/;function nf(P){return P.trim().replace(/^(["'])(.*)\1$/,"$2")}function rf(P){let A=P.split(/\r?\n/),q=A.findIndex((ne)=>Ua.exec(ne)?.[1]?.trim()==="plugins");if(q===-1)return[];let V=A.slice(q+1),ee=V.findIndex((ne)=>Ua.test(ne));return ee===-1?V:V.slice(0,ee)}function Ba(P,A){let q=rf(P),V=q.findIndex((ce)=>tf.exec(ce)?.[1]===A);if(V===-1)return[];let ee=q.slice(V+1),ne=ee.findIndex((ce)=>!Ga.test(ce));return(ne===-1?ee:ee.slice(0,ne)).map((ce)=>nf(Ga.exec(ce)?.[1]??""))}function of(P){try{return qa(Va($o(P),"config.yaml"),"utf-8")}catch{return}}function Mo(P){let A=of(P)??"";return Ba(A,"enabled").includes(It)&&!Ba(A,"disabled").includes(It)}function za(P){return/^# version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function sf(P,A){let q=Lt(P);if(!q)return{error:`${A.name} is missing from ${P}; run install --hermes-agent`};if(q.isSymbolicLink()||!q.isFile())return{error:`${P} is a symlink or not a regular file; move or remove it`};try{let V=qa(P,"utf-8");if(!Fo(V))return{error:`Unmanaged ${A.name} occupies ${P}; move or remove it`};if(za(V)===wt()&&V!==A.content)return{error:`Modified ${A.name} occupies ${P}; run install --hermes-agent to restore it`};return{content:V}}catch(V){return{error:`Failed to read ${P}: ${V instanceof Error?V.message:String(V)}`}}}function af(P){try{return{path:Oo(P)}}catch(A){return{error:A instanceof Error?A.message:String(A)}}}function Ja(P){let A=af(P.environment);if("error"in A)return{platform:jn,status:"n/a",errors:[A.error]};let q=A.path,V=yr(jn,q);if(V)return V;let ee=Nn(wt()).map((ye)=>sf(Va(q,ye.name),ye)),ne=ee.flatMap((ye)=>("error"in ye)?[ye.error]:[]);if(ne.length>0)return{platform:jn,status:"n/a",configPath:q,errors:ne};let ce=ee.some((ye)=>("content"in ye)&&za(ye.content)!==wt()),he=ce?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Mo(P.environment))return{platform:jn,status:"disabled",method:"plugin directory",configPath:q,errors:[`${It} is not enabled in Hermes; run \`hermes plugins enable ${It}\``,...he]};return{platform:jn,status:"configured",method:"plugin directory",configPath:q,errors:ce?he:void 0}}import{existsSync as lf,readFileSync as cf}from"node:fs";import{join as Wa}from"node:path";var df=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function uf(P){return Wa(P.env.get("KIMI_CODE_HOME")||Wa(P.home,".kimi-code"),"config.toml")}function Mn(P){let A=uf(P.environment);if(!lf(A))return{platform:"kimi-code",status:"n/a",configPath:A};try{if(!df.test(cf(A,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:A}}catch(q){return{platform:"kimi-code",status:"n/a",configPath:A,errors:[`Failed to read ${A}: ${q instanceof Error?q.message:String(q)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:A}}import{readFileSync as ol}from"node:fs";import{join as Un}from"node:path";var yt="cc-safety-net",Tt="index.js",bn="openclaw.plugin.json",Ln="package.json";var _r="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as mf,lstatSync as gf,readdirSync as hf,readFileSync as yf}from"node:fs";import{dirname as Ya,join as Kt}from"node:path";import{fileURLToPath as vf}from"node:url";import{spawn as pf}from"node:child_process";function ff(P){return P.join(" ")}function Ho(P,A,q){return[`Failed to run ${ff(P)}${A===null?"":` (exit ${A})`}.`,q.trim()].filter(Boolean).join(`
215
+ `)}function Uo(P){let A={stdout:"",stderr:""};return P.stdout.setEncoding("utf-8"),P.stderr.setEncoding("utf-8"),P.stdout.on("data",(q)=>{A.stdout+=q}),P.stderr.on("data",(q)=>{A.stderr+=q}),A}function St(P,A){return new Promise((q,V)=>{let ee=Qt([...P],process.env),ne=pf(ee.cmd,ee.args,{stdio:["ignore","pipe","pipe"]}),ce=Uo(ne),he=()=>[ce.stdout,ce.stderr].filter(Boolean).join(`
216
+ `),ye=A?.timeoutMs??120000,be=setTimeout(()=>{ne.kill(),V(Error(Ho(P,null,`Timed out after ${ye}ms.
217
+ ${he()}`.trim())))},ye);ne.on("error",(xe)=>{clearTimeout(be),V(Error(Ho(P,null,`${xe.message}
218
+ ${he()}`.trim())))}),ne.on("close",(xe)=>{if(clearTimeout(be),xe!==0){V(Error(Ho(P,xe,he())));return}q(A?.stdoutOnly?ce.stdout:he())})})}async function Go(P){for(let A of P)await St(A)}async function Ka(P){for(let A of P)try{await St(A)}catch(q){console.warn(q instanceof Error?q.message:String(q))}}var Bo=Kt("openclaw",yt),rn=`run \`openclaw plugins enable ${yt}\``,bf="config reload superseded by a newer runtime config source",Lf=[Tt,bn,Ln];function Xa(P){let A=P.env.get("OPENCLAW_HOME")?.trim();return A?en(A,P.home):P.home}function Za(P){let A=Xa(P),q=P.env.get("OPENCLAW_STATE_DIR")?.trim();if(q)return en(q,A);let V=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return V?Ya(en(V,A)):Kt(A,".openclaw")}function Qa(P){let A=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return A?en(A,Xa(P)):Kt(Za(P),"openclaw.json")}function Hn(P){return Kt(Za(P),"extensions",yt)}function wf(P){let A=hf(P);if(A.length===0)return!0;if(A.some((ee)=>!Lf.includes(ee)))return!1;let q=Kt(P,Tt),V=Lt(q);return V!==void 0&&!V.isSymbolicLink()&&V.isFile()&&yf(q,"utf-8").startsWith(_r)}function qo(P){let A=Hn(P),q=Lt(A);if(!q)return;if(!q.isSymbolicLink()&&q.isDirectory()&&wf(A))return;throw Error(`Refusing to modify ${A}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function el(){let P=Ya(vf(import.meta.url));return[Kt(P,Bo),Kt(P,"..",Bo),Kt(P,"..","..","..","dist",Bo)]}function Vo(P=el()){return P.find((A)=>mf(A)&&gf(A).isDirectory())}function kf(P=el()){let A=Vo(P);if(!A)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return A}function tl(P=kf()){return[["openclaw","plugins","install",P,"--force","--accept-capabilities"]]}function xf(P){let A=(()=>{try{return JSON.parse(P)}catch{return}})(),q=pt(pt(A,"plugin"),"status");return typeof q==="string"?q:void 0}async function Cf(){await St(["openclaw","plugins","enable",yt]).catch((P)=>{if(!(P instanceof Error&&P.message.includes(bf)))throw P})}async function nl(P){let A=async()=>xf(await St(["openclaw","plugins","inspect",yt,"--runtime","--json"],{stdoutOnly:!0})),q=await A(),V=q==="disabled"&&P;if(V)await Cf();let ee=V?await A():q;if(ee==="loaded")return;throw Error(`${ee===void 0?`The ${yt} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:ee==="disabled"?`OpenClaw reports the ${yt} plugin with status "disabled"; ${rn}.`:`OpenClaw reports the ${yt} plugin with status "${ee}".`} Run \`openclaw plugins inspect ${yt} --runtime\` for details.`)}var Tr="openclaw";function wn(P,A){let q=Un(P,A),V=Lt(q);if(!V)return{error:`${A} is missing from ${q}; run install --openclaw`};if(V.isSymbolicLink()||!V.isFile())return{error:`${q} is a symlink or not a regular file; move or remove it`};try{return{content:ol(q,"utf-8")}}catch(ee){return{error:`Failed to read ${q}: ${ee instanceof Error?ee.message:String(ee)}`}}}function il(P){try{return JSON.parse(_t(P))}catch{return}}function Sf(P){let A=wn(P,bn);if("error"in A)return A.error;if(pt(il(A.content),"id")===yt)return;return`${Un(P,bn)} is not a valid ${yt} manifest; run install --openclaw`}function Rf(P){let A=wn(P,Ln);if("error"in A)return A.error;let q=pt(pt(il(A.content),"openclaw"),"extensions");if(Array.isArray(q)&&q.includes(`./${Tt}`))return;return`${Un(P,Ln)} does not point OpenClaw at ${Tt}; run install --openclaw`}function rl(P){return Array.isArray(P)?P.filter((A)=>typeof A==="string"):[]}function Pf(P){let A=Qa(P);if(!Lt(A))return`${yt} is not enabled; ${rn}`;let q=(()=>{try{return JSON.parse(_t(ol(A,"utf-8")))}catch{return}})();if(q===void 0)return`Failed to read ${A}; fix it, then ${rn}`;let V=pt(q,"plugins");if(pt(V,"enabled")===!1)return`plugins.enabled is false in ${A}; no OpenClaw plugin loads`;let ee=pt(pt(pt(V,"entries"),yt),"enabled");if(rl(pt(V,"deny")).includes(yt)||ee===!1)return`${yt} is disabled in ${A}; ${rn}`;let ne=rl(pt(V,"allow"));if(ne.length>0&&!ne.includes(yt))return`plugins.allow in ${A} does not list ${yt}; add it, then ${rn}`;if(ne.includes(yt)||ee===!0)return;return`${yt} is not enabled; ${rn}`}function sl(P){return/^\/\/ version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function Ef(P,A,q){if(q===void 0)return[];let V=wn(q,Tt);if(!(("content"in V)&&sl(V.content)===A))return[];return[Tt,bn,Ln].flatMap((ne)=>{let ce=wn(P,ne),he=wn(q,ne);if("error"in ce||"error"in he||ce.content===he.content)return[];return[`Modified ${ne} occupies ${Un(P,ne)}; run install --openclaw to restore it`]})}function al(P){let A=Hn(P.environment),q=yr(Tr,A);if(q)return q;let V=wn(A,Tt),ne=["error"in V?V.error:V.content.startsWith(_r)?void 0:`Unmanaged ${Tt} occupies ${Un(A,Tt)}; move or remove it`,Sf(A),Rf(A)].filter((xe)=>xe!==void 0),ce="content"in V?sl(V.content):void 0,he=ne.length>0?ne:Ef(A,ce,Vo());if(he.length>0)return{platform:Tr,status:"n/a",configPath:A,errors:he};let ye=ce===wt()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],be=Pf(P.environment);if(be)return{platform:Tr,status:"disabled",method:"plugin directory",configPath:A,errors:[be,...ye]};return{platform:Tr,status:"configured",method:"plugin directory",configPath:A,errors:ye.length>0?ye:void 0}}import{existsSync as Nf,readFileSync as jf}from"node:fs";import{basename as Mf}from"node:path";import{existsSync as Ir,readFileSync as zo,rmSync as Df}from"node:fs";import{join as Mt}from"node:path";import{pathToFileURL as Af}from"node:url";var Gn="cc-safety-net",on=`${Gn}@latest`,Jo=["opencode.json","opencode.jsonc"],_f=60,Tf=250,ll="CCSafetyNetPlugin",If={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function cl(P){return Mt(P.env.get("XDG_CONFIG_HOME")||Mt(P.home,".config"),"opencode")}function Wo(P){return P.env.get("OPENCODE_CONFIG_DIR")||cl(P)}function Ko(P){return Jo.map((A)=>Mt(Wo(P),A))}function Yo(P){return[...new Set([Wo(P),cl(P)])].flatMap((A)=>Jo.map((q)=>Mt(A,q)))}function dl(P){return Mt(P.env.get("XDG_CACHE_HOME")||Mt(P.home,".cache"),"opencode","packages",on)}function ul(P){Df(dl(P),{recursive:!0,force:!0})}async function pl(P){let A=(await St(["opencode","--version"],{stdoutOnly:!0})).trim(),q=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(A),V=Number(q?.[1]),ee=Number(q?.[2]),ne=Number(q?.[3]);if(!q||V!==1&&V!==2||V===1&&(ee<18||ee===18&&ne<29)||V===2&&ee===0&&ne<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${A||"an unknown version"}.`);if(V===2){for(let ce of Ko(P)){if(!Ir(ce))continue;let he=Zo(zo(ce,"utf-8"),ce);if(["plugin","plugins"].some((be)=>{let xe=pt(he,be);return Array.isArray(xe)&&xe.some((Ie)=>$r(Ie)&&(typeof Ie==="string"?Ie:pt(Ie,"package"))!==on)}))throw Error(`Change the cc-safety-net package spec in ${ce} to ${on}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[],afterInstall:async()=>{if((await St(["opencode","plugin","add",on],{stdoutOnly:!0})).includes("is already configured in"))await St(["opencode","plugin","update",on]);let he=await gl();if(!/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(he))throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.");let ye=["--param",`location[directory]=${process.cwd()}`];await St(["opencode","api","integration.list",...ye]);let be=await St(["opencode","api","plugin.list",...ye],{stdoutOnly:!0}),xe=Xo(be);if(xe)throw Error(xe);if(!fl(be).some(ml))throw Error("OpenCode lists no active cc-safety-net for this directory. Run `opencode api plugin.list` for details.")}}}return ul(P),{commands:[["opencode","plugin","-g","-f",on]],afterInstall:()=>Of(P)}}function fl(P){return $f(P).filter((A)=>pt(A,"id")===Gn||$r(pt(pt(A,"source"),"target"))).map((A)=>pt(A,"state"))}function ml(P){return pt(P,"status")==="active"}function Xo(P){let A=fl(P);if(A.some(ml))return;let q=A.find((V)=>pt(V,"status")==="failed");if(!q)return;return`OpenCode reports cc-safety-net failed: ${String(pt(q,"error")).split(`
219
+ `)[0]}`}function $f(P){if(!P)return[];try{let A=pt(JSON.parse(P),"data");return Array.isArray(A)?A:[]}catch{return[]}}async function gl(P=1){let A=await St(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s|\scc-safety-net@latest\s*$/m.test(A)||P===_f)return A;return await new Promise((q)=>setTimeout(q,Tf)),gl(P+1)}async function Of(P){let A=Mt(dl(P),"node_modules",Gn),q=Mt(A,"package.json");if(!Ir(q))throw Error(`The OpenCode plugin cache at ${A} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${on}\` for details.`);let V=pt(JSON.parse(zo(q,"utf-8")),"main");if(typeof V!=="string")throw Error(`The cached OpenCode plugin at ${A} declares no "main" entry.`);let ee=Mt(A,V);if(typeof(await import(Af(ee).href))[ll]==="function")return;throw Error(`The cached OpenCode plugin at ${ee} does not export a callable ${ll}, so OpenCode would load nothing and fail open.`)}function Zo(P,A){try{return JSON.parse(_t(P))}catch(q){if(q instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${A}: ${q.message}`);throw q}}function $r(P){let A=typeof P==="string"?P:pt(P,"package");return typeof A==="string"&&(A===Gn||A.startsWith(`${Gn}@`))}function Qo(P){return["plugin","plugins"].some((A)=>{let q=pt(P,A);return Array.isArray(q)&&q.some($r)})}function Ff(P,A){let V=["plugin","plugins"].flatMap((ee)=>{let ne=ia(P,ee,If);if(!ne)return[];let ce=[],he=0,ye=ne.start+1,be=P.slice(ne.start+1,ne.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let xe of be){if(xe[0].startsWith("//")||xe[0].startsWith("/*"))continue;let Ie=ne.start+1+xe.index;if(he===0)ye=Ie;if(xe[0]==="{"||xe[0]==="[")he++;if(xe[0]==="}"||xe[0]==="]")he--;if(he!==0||xe[0]===",")continue;let Xe=Ie+xe[0].length;if($r(JSON.parse(_t(P.slice(ye,Xe)))))ce.push({start:ye,end:Xe})}return ce}).sort((ee,ne)=>ee.start-ne.start).reverse().reduce((ee,ne)=>{let ce=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(ee.slice(ne.end));if(ce?.[0].includes("/")){let he=ne.end+ce[0].length-1;return ee.slice(0,ne.start)+ee.slice(ne.end,he)+ee.slice(he+1)}return Lr(ee,ne)},P);return Zo(V,A),V}function hl(P){ul(P);let A=Yo(P),q=A.find((ne)=>Ir(ne)),V=[],ee=[];for(let ne of A){if(!Ir(ne))continue;try{let ce=zo(ne,"utf-8");if(!Qo(Zo(ce,ne)))continue;kt(ne,Ff(ce,ne)),ee.push(ne)}catch(ce){V.push(ce instanceof Error?ce.message:String(ce))}}if(V.length>0)throw Error(V.join(`
220
+ `));return{path:ee[0]??q??Mt(Wo(P),Jo[0]),alreadyInstalled:ee.length>0}}function kn(P){let A=[];for(let q of P.openCodeVersion?.startsWith("2.")?Ko(P.environment):Yo(P.environment))if(Nf(q))try{let V=jf(q,"utf-8"),ee=_t(V),ne=JSON.parse(ee);if(Qo(ne)){let ce=Xo(P.openCodePluginListOutput);if(ce)return{platform:"opencode",status:"disabled",method:"opencode api plugin.list",configPath:q,errors:[...A,ce]};return{platform:"opencode",status:"configured",method:"plugin array",configPath:q,errors:A.length>0?A:void 0}}}catch(V){A.push(`Failed to parse ${Mf(q)}: ${V instanceof Error?V.message:String(V)}`)}return{platform:"opencode",status:"n/a",errors:A.length>0?A:void 0}}import{join as yl}from"node:path";function ei(P){let A=P.env.get("PI_CODING_AGENT_DIR");return yl(A?en(A,P.home):yl(P.home,".pi","agent"),"settings.json")}function ti(P){if(typeof P!=="string")return!1;return P==="npm:cc-safety-net"||P.startsWith("npm:cc-safety-net@")}function vl(P){let A=ei(P.environment),q=Ft(A);if(q.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(q.kind==="missing")return{platform:"pi",status:"n/a"};let V=pt(q.value,"packages");if(!Array.isArray(V))return{platform:"pi",status:"n/a"};let ee=V.find((he)=>ti(typeof he==="string"?he:pt(he,"source")));if(ee===void 0)return{platform:"pi",status:"n/a"};let ne=pt(ee,"extensions");if(Array.isArray(ne)&&ne.some((he)=>typeof he==="string"&&he.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:A,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:A}}var Hf={amp:Ks,"antigravity-cli":Ys,"claude-code":Qs,codex:ta,"copilot-cli":ha,cursor:Ca,"gemini-cli":Sa,"grok-build":Oa,"hermes-agent":Ja,"kimi-code":Mn,openclaw:al,opencode:kn,pi:vl};function xn(P,A,q){let V={...q,cwd:A,environment:P};return rr.map((ee)=>Uf(Hf[ee](V)))}function Uf(P){if(P.status==="not-inspected")return{platform:P.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:P.platform,detected:P.status!=="n/a",configured:P.status==="configured",inspectionStatus:P.status!=="n/a"?"verified":P.errors&&P.errors.length>0?"failed":"not-applicable",method:P.method,configPath:P.configPath,configPaths:P.configPaths,errors:P.errors}}import{join as Gf}from"node:path";var Bf=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}]),qf=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),Vf={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 bl(P){let A=Gf(P.tmpdir,"cc-safety-net-self-test"),q=Bf.map((V)=>{let ee=N(P,d("self-test",{command:V.command},{kind:"command",shell:"auto"},{configCwd:A,executionCwd:A},V.command),{guard:{dependencies:{loadPolicySnapshot:()=>qf,getModes:()=>Vf,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),ne=V.expectBlocked?"blocked":"allowed",ce=ee.decision.kind==="deny"?"blocked":"allowed";return{command:V.command,description:V.description,expected:ne,actual:ce,passed:ne===ce,reason:ee.decision.kind==="deny"?ee.decision.reason:void 0,ruleId:ee.decision.kind==="deny"?ee.decision.ruleId:void 0}});return{passed:q.filter((V)=>V.passed).length,failed:q.filter((V)=>!V.passed).length,total:q.length,results:q}}function ni(P){let A=xt({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},P);if(Ut(A.errors))return null;return{json:A.flags.json,skipUpdateCheck:A.flags.skipUpdateCheck}}async function Ll(P,A={}){let q=await An(!A.json,()=>{let V=zf(P,A);return{ready:V,finish:()=>V}},()=>Dn(),{loadingMessage:"Checking system status…"});if(A.json)console.log(JSON.stringify(q,null,2));else Jf(q);return q.engineSelfTest.failed>0||q.findings.some((V)=>V.severity==="error")?1:0}async function zf(P,A){let q=A.cwd??process.cwd(),V=await pr((at)=>kn({environment:P,cwd:q,openCodeVersion:at}).status!=="n/a",void 0,q),ee=xn(P,q,{ampPluginListOutput:V.ampPluginListOutput,codexPluginListOutput:V.codexPluginListOutput,copilotCliVersion:V.versions["copilot-cli"],openCodeVersion:V.versions.opencode,openCodePluginListOutput:V.openCodePluginListOutput}),ne=us(P,q),ce=ps(P),he=E(P,{cwd:q}),ye=he.policy,be=R(ye,P.env),xe=H(ye,be.capabilities),Ie=ar(P,7),Xe=qs(P,q),et=A.skipUpdateCheck?{currentVersion:wt(),latestVersion:null,updateAvailable:!1}:await Wt(),Re={hooks:ee,engineSelfTest:bl(P),userConfig:ne.userConfig,projectConfig:ne.projectConfig,configState:Ne(he),effectiveRules:ne.effectiveRules,environment:ce,effectiveSafety:{selectedPreset:ye.safety.level??"standard",level:be.effectiveLevel,capabilities:be.capabilities,ruleOverrides:ye.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(xe).filter(([,at])=>at.source==="rule_override"&&at.override==="off"&&at.inheritedEnabled&&at.changesInherited).map(([at])=>at),ruleCounts:{stored:Object.keys(ye.destructiveCommandRuleOverrides).length,effective:Object.values(xe).filter((at)=>at.changesInherited).length},...he.policyScopes?{policyScopes:he.policyScopes}:{}},...Xe.length>0?{v2Leftovers:Xe}:{},posture:Rs(P,ne.userConfig.path),activity:Ie,update:et,system:V};return{...Re,findings:ms(Re)}}function Jf(P){console.log(),console.log(hs(P.hooks)),console.log(),console.log(ys(P.engineSelfTest)),console.log(),console.log(vs(P)),console.log(),console.log(bs(P.environment)),console.log(),console.log(Ls(P)),console.log(),console.log(ws(P.findings)),console.log(),console.log(ks(P.activity)),console.log(),console.log(Cs(P.system)),console.log(),console.log(xs(P.update)),console.log(Ss(P))}import{existsSync as Wf}from"node:fs";var Kf=/^[A-Za-z0-9_@%+=:,./-]+$/,wl="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function ri(P){let A=xt({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},P);if(Ut(A.errors))return console.error(wl),console.error("Pass -- before a command that starts with dashes."),null;if(A.values.cwd!==void 0&&!Wf(A.values.cwd))return console.error(`Error: --cwd path does not exist: ${A.values.cwd}`),null;let q=A.positionals.length===1?A.positionals[0]:A.positionals.map((V)=>Kf.test(V)?V:`'${V.replaceAll("'","'\\''")}'`).join(" ");if(!q)return console.error("Error: No command provided"),console.error(wl),null;return{json:A.flags.json,cwd:A.values.cwd,command:q}}function kl(P){if(P)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function xl(P,A){let V=A-18;return[`${P.dtl}${P.dh.repeat(A)}${P.dtr}`,`${P.dv} Command Analysis${" ".repeat(V)}${P.dv}`,`${P.dbl}${P.dh.repeat(A)}${P.dbr}`]}function oi(P){return JSON.stringify(P)}function Cl(P,A=0){return`[${P.map((V,ee)=>gs(V,ee,A)).join(",")}]`}function Bn(P,A,q=70){let V=P.split(" "),ee=[],ne="";for(let ce of V)if(ne&&ne.length+ce.length+1>q)ee.push(ne),ne=ce;else ne=ne?`${ne} ${ce}`:ce;if(ne)ee.push(ne);return ee.map((ce,he)=>he===0?ce:`${A}${ce}`)}function Sl(P,A,q){let V=[];switch(P.type){case"parse":return null;case"env-strip":return V.push(""),V.push(`STEP ${A} ${q.h} Strip environment variables`),V.push(` Removed: ${P.envVars.map((ee)=>`${ee}=<redacted>`).join(", ")}`),V.push(` Tokens: ${oi(P.output)}`),{lines:V,incrementStep:!0};case"leading-tokens-stripped":return V.push(""),V.push(`STEP ${A} ${q.h} Strip wrappers`),V.push(` Removed: ${P.removed.join(", ")}`),V.push(` Tokens: ${oi(P.output)}`),{lines:V,incrementStep:!0};case"shell-wrapper":return V.push(""),V.push(`STEP ${A} ${q.h} Detect shell wrapper`),V.push(` Wrapper: ${P.wrapper} -c`),V.push(` Inner: ${P.innerCommand}`),{lines:V,incrementStep:!0};case"interpreter":{if(V.push(""),V.push(`STEP ${A} ${q.h} Detect interpreter`),V.push(` Interpreter: ${P.interpreter}`),V.push(` Code: ${P.codeArg}`),P.paranoidBlocked)V.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:V,incrementStep:!0}}case"busybox":return V.push(""),V.push(`STEP ${A} ${q.h} Busybox wrapper`),V.push(` Subcommand: ${P.subcommand}`),{lines:V,incrementStep:!0};case"transparent-wrapper":return V.push(""),V.push(`STEP ${A} ${q.h} Transparent wrapper`),V.push(` Wrapper: ${P.wrapper}`),V.push(` Tokens: ${oi(P.output)}`),{lines:V,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(V.push(""),V.push(`STEP ${A} ${q.h} Match rules`),V.push(` Rule: ${P.rule}()`),P.matched)V.push(" Result: MATCHED");else V.push(" Result: No match");return{lines:V,incrementStep:!0}}case"worktree-relaxation":return V.push(""),V.push(`STEP ${A} ${q.h} Worktree relaxation`),V.push(` Mode: ${o.worktree.name}`),V.push(` Git cwd: ${P.gitCwd}`),V.push(" Result: Allowed local discard in linked worktree"),{lines:V,incrementStep:!0};case"temp-root-relaxation":return V.push(""),V.push(`STEP ${A} ${q.h} Temp-root relaxation`),V.push(` Git cwd: ${P.gitCwd}`),V.push(" Result: Allowed git discard in a temp-root repository"),{lines:V,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(P.embeddedCommandFound)return V.push(""),V.push(`STEP ${A} ${q.h} Fallback scan`),V.push(` Found: ${P.embeddedCommandFound}`),{lines:V,incrementStep:!0};return null}case"custom-rules-check":{if(P.rulesChecked){if(V.push(""),V.push(`STEP ${A} ${q.h} Custom rules`),P.matched)V.push(" Result: MATCHED");else V.push(" Result: No match");return{lines:V,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(P.matched)return V.push(""),V.push(`STEP ${A} ${q.h} Dangerous text check`),V.push(` Token: ${P.token}`),V.push(" Result: MATCHED"),{lines:V,incrementStep:!0};return null}case"strict-unparseable":return V.push(""),V.push(`STEP ${A} ${q.h} Strict mode check`),V.push(` Command: ${P.rawCommand}`),V.push(" Result: ✗ UNPARSEABLE"),{lines:V,incrementStep:!0};case"segment-skipped":return null;case"error":return V.push(""),V.push(`ERROR: ${P.message}`),{lines:V,incrementStep:!1};default:return P}}function ii(P,A){let q=kl(A?.asciiOnly??!1),V=58,ee=[],ne=1;ee.push(...xl(q,58)),ee.push("");let ce=P.trace.steps.find((Re)=>Re.type==="error");if(ce&&ce.type==="error"){ee.push("ERROR"),ee.push(` ${ce.message}`),ee.push(""),ee.push("RESULT"),ee.push(` Status: ${P.result==="blocked"?dt.red("BLOCKED"):dt.green("ALLOWED")}`),ee.push(""),ee.push("CONFIG");let Re=P.configSource??"none";return ee.push(` Path: ${Re}`),ee.join(`
221
+ `)}let he=P.trace.steps.find((Re)=>Re.type==="parse");if(he&&he.type==="parse"){ee.push("INPUT"),ee.push(` ${he.input}`),ee.push(""),ee.push(`STEP ${ne} ${q.h} Split shell commands`),ne++;for(let Re=0;Re<he.segments.length;Re++){let at=he.segments[Re];if(at){let ct=Math.random();ee.push(` Segment ${Re+1}: ${Cl(at,ct)}`)}}}let ye=P.trace.segments,be=ye.length>1;for(let Re of ye){if(be){ee.push("");let ft="";if(he&&he.type==="parse"){let io=he.segments[Re.index];if(io)ft=io.join(" ")}let mt=54,gt=ft,ut=` Segment ${Re.index+1}: `,vt=" ";if(ft){if(ut.length+ft.length+vt.length>mt){let Xd=mt-ut.length-vt.length;gt=`${ft.substring(0,Xd-1)}…`}}let At=ft?`${ut}${gt}${vt}`:` Segment ${Re.index+1} `,Kd=ft?`${ut}${dt.cyan(gt)}${vt}`:At,Hi=58-At.length,Ui=Math.floor(Hi/2),Yd=Hi-Ui;ee.push(`${q.sh.repeat(Ui)}${Kd}${q.sh.repeat(Yd)}`)}if(Re.steps.find((ft)=>ft.type==="segment-skipped")){ee.push(""),ee.push(" (skipped — prior segment blocked)");continue}let ct=!1,lt=!1;for(let ft of Re.steps){let mt=Sl(ft,ne,q);if(mt){if(lt=!0,ft.type==="recurse"){ee.push("");let gt=" RECURSING ",ut=58-gt.length-4;ee.push(` ${q.tl}${q.h}${gt}${q.h.repeat(ut)}`),ee.push(` ${q.v}`),ct=!0;continue}for(let gt of mt.lines)if(ct)ee.push(` ${q.v} ${gt}`);else ee.push(gt);if(mt.incrementStep)ne++}}if(ct)ee.push(` ${q.v}`),ee.push(` ${q.bl}${q.h.repeat(56)}`);if(!lt)ee.push(""),ee.push(` ${dt.green("✓")} Allowed (no matching rules)`)}if(ee.push(""),ee.push("RESULT"),P.result==="blocked"){if(ee.push(` Status: ${dt.red("BLOCKED")}`),P.customRule){if(ee.push(` Rule: ${P.customRule.id}`),P.customRule.rulebook)ee.push(` Rulebook: ${P.customRule.rulebook.name} ${P.customRule.rulebook.version}`);if(P.customRule.source)ee.push(` Source: ${P.customRule.source}`);if(P.customRule.override)ee.push(` Override: reason ${P.customRule.override.reason}`)}if(P.reason){let Re=Bn(P.reason," ");ee.push(` Reason: ${Re[0]}`);for(let at=1;at<Re.length;at++)ee.push(Re[at]??"")}}else ee.push(` Status: ${dt.green("ALLOWED")}`);ee.push(""),ee.push("CONFIG");let xe=P.configSource??"none",Ie=P.configValid?"":" (invalid)";ee.push(` Path: ${xe}${Ie}`);let Xe=P.safetyPresetScope;ee.push(` Safety preset: ${P.selectedPreset??"standard"}${Xe?` (${cr(Xe)})`:""}`),ee.push(` Effective capabilities: ${P.effectiveLevel}`);let et=Object.entries(P.destructiveCommandRuleOverrides??{});if(ee.push(` Rule customizations: ${et.length}`),P.ruleActivation)ee.push(` Rule activation: ${P.ruleActivation.id} — ${P.ruleActivation.enabled?"on":"off"} via ${P.ruleActivation.source}`);return ee.join(`
222
+ `)}function si(P){return JSON.stringify(P,null,2)}import{resolve as em}from"node:path";var Yf=["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 Rl(P){let A=0,q={allocateSegment(){return A++},getNextSegmentIndex(){return A},recordGlobal(V){P.record({kind:"step",scope:"global",step:V})},recordSegment(V,ee=q.currentSegmentIndex){if(ee===void 0)return;P.record({kind:"step",scope:"segment",segmentIndex:ee,step:V})}};return q}function Pl(P={}){let A=[],q=P.maxEvents??512,V={maxTextLength:P.maxTextLength??2048,maxListLength:P.maxListLength??128,maxObjectProperties:P.maxObjectProperties??P.maxListLength??128,maxDepth:P.maxDepth??16},ee,ne=new Set;return{record(ce){if(ee)return;if(!ce||A.length>=q)return;try{A.push(ci(Xf(ce,V,ne)))}catch{}},finish(){if(ee)return ee;return ee=ci({events:Object.freeze(A)}),ee}}}function Xf(P,A,q){if(P.kind!=="step")throw TypeError("invalid trace event");let{scope:V,step:ee}=P;Or(ee,q,A);let ne=ai(ee,A,q);if(V==="global")return{kind:"step",scope:"global",step:ne};if(V!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:P.segmentIndex,step:ne}}function Or(P,A,q,V=0,ee=new WeakSet){if(typeof P==="string"){let he=P.slice(0,q.maxTextLength);if(!Ge(he))return;for(let ye of Ze(he))for(let be of ye.match(/[^\s"'()$]+/g)??[])A.add(El(be));return}if(!P||typeof P!=="object"||V>=q.maxDepth||ee.has(P))return;if(ee.add(P),Array.isArray(P)){let he=Math.min(P.length,q.maxListLength);for(let ye=0;ye<he;ye++)Or(P[ye],A,q,V+1,ee);return}let ne=0,ce=new Set;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ne>=q.maxObjectProperties)break;ne++,Or(he,A,q);let ye=li(he,q,A);if(ce.has(ye))continue;ce.add(ye),Or(P[he],A,q,V+1,ee)}}function ai(P,A,q,V=0,ee=new WeakSet){if(typeof P==="string")return li(P,A,q);if(!P||typeof P!=="object")return P;if(V>=A.maxDepth)return;if(ee.has(P))return;if(ee.add(P),Array.isArray(P)){let he=[],ye=Math.min(P.length,A.maxListLength);for(let be=0;be<ye;be++)he.push(ai(P[be],A,q,V+1,ee));return he}let ne={},ce=0;for(let he in P){if(!Object.hasOwn(P,he))continue;if(ce>=A.maxObjectProperties)break;ce++;let ye=li(he,A,q);if(Object.hasOwn(ne,ye))continue;Object.defineProperty(ne,ye,{value:ai(P[he],A,q,V+1,ee),enumerable:!0,configurable:!0,writable:!0})}return ne}function li(P,A,q){let V=P.slice(0,A.maxTextLength),ee=Ge(V)?Ue(V):V,ne=q.size>0?Qf(ee,q):ee;return(Zf(ne)?ke(ne):ne).slice(0,A.maxTextLength)}function Zf(P){return P.includes("PRIVATE KEY")||P.includes("://")||P.includes("eyJ")||P.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(P)||P.length>=14&&Yf.some((A)=>P.includes(A))||P.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(P)}function Qf(P,A){return P.replace(/[^\s"'()$]+/g,(q)=>A.has(El(q))?"<redacted>":q)}function El(P){let A=2166136261,q=2166136261;for(let V=0;V<P.length;V++)A=Math.imul(A^P.charCodeAt(V),16777619),q=Math.imul(q^P.charCodeAt(P.length-V-1),16777619);return`${A>>>0}:${q>>>0}:${P.length}`}function ci(P){if(P&&typeof P==="object"&&!Object.isFrozen(P)){for(let A of Object.values(P))ci(A);Object.freeze(P)}return P}function qn(P,A={},q){let V=em(A.cwd??process.cwd()),ee=A.policySnapshot??E(q,{cwd:V,userConfigDir:A.userConfigDir}),ne=R(ee.policy,q.env),ce=Fe({policySnapshot:ee,effectiveCapabilities:ne.capabilities,strict:ne.strict,paranoidRm:ne.paranoidRm,paranoidInterpreters:ne.paranoidInterpreters,worktreeMode:ne.worktreeMode}),he={effectiveLevel:ce.effectiveLevel,selectedPreset:ee.policy.safety.level??"standard",...ee.policyScopes?{safetyPresetScope:ee.policyScopes.levelScope}:{},effectiveCapabilities:ce.effectiveCapabilities,destructiveCommandRuleOverrides:ee.policy.destructiveCommandRuleOverrides},{configSource:ye,configValid:be}=nm(q,{cwd:V,userConfigDir:A.userConfigDir});if(!P||!P.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:ye,configValid:be,...he};let xe=h(P,"auto");if(xe.status==="limited")throw new y;let Ie=xe.dialect==="powershell"?h(P,"posix"):xe,Xe=st(Ie),et=Pl(),Re=Rl(et);Re.recordGlobal({type:"parse",input:P,segments:Xe.map((At)=>[...At])});let at=d("Bash",{command:P},{kind:"command",shell:"auto"},{configCwd:V,executionCwd:V},P),ct=B(at,{environment:q,trace:Re,dependencies:{loadPolicySnapshot:()=>ee}}),lt=ct.decision.kind==="deny"?ct.decision:null;if(lt&&(ct.stage==="policy-protection"||ct.stage==="secret-protection")){let At=tm(lt);return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:At.rule,matched:!0,reason:lt.reason}]}]},result:"blocked",reason:k(lt.reason),segment:k(Dl(lt,P)),...At.ruleId?{ruleId:k(At.ruleId)}:{},configSource:ye,configValid:be,...he}}let ft=Re.getNextSegmentIndex();if(lt&&ft>0&&ft<Xe.length)Re.recordSegment({type:"segment-skipped",index:ft,reason:"prior-segment-blocked"},ft);let mt=et.finish(),gt=lt?.ruleId??rm(at,ee,ne,q),ut=G.find((At)=>At.id===gt&&At.activationCapability),vt=ut?ce.policy.effectiveDestructiveCommandRules[ut.id]:void 0;return{trace:im(mt),result:lt?"blocked":"allowed",reason:lt?k(lt.reason):void 0,segment:lt?k(Dl(lt,P)):void 0,ruleId:lt?.ruleId?k(lt.ruleId):void 0,customRule:om(sm(lt?.ruleId,ee)),configSource:ye,configValid:be,...he,...ut&&vt?{ruleActivation:{id:ut.id,...vt}}:{}}}function Dl(P,A){return P.evidence?.segment??A}function tm(P){if(P.reason===$e)return{ruleId:"policy-protection",rule:"policy-protection:findPolicyConfigMutationTargetInSemanticFacts"};if(P.reason===Me)return{ruleId:"policy-apply-protection",rule:"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts"};if(P.reason===x)return{ruleId:"git-metadata-protection",rule:"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts"};return{ruleId:P.ruleId,rule:"secret-protection:findSensitiveTargetInSemanticFacts"}}function nm(P,A){let q=M(A.cwd),V=j(P,A),ee=J(P,{cwd:A.cwd,userConfigDir:A.userConfigDir});try{if(n(ee.projectConfigTarget)!==null){if(Jt(ee.projectConfigTarget).errors.length===0)return{configSource:q,configValid:!0};return{configSource:q,configValid:!1}}}catch(ne){if(ne instanceof r)return{configSource:q,configValid:!1};throw ne}try{if(n(ee.userConfigTarget)!==null){let ne=Jt(ee.userConfigTarget);return{configSource:V,configValid:ne.errors.length===0}}return{configSource:null,configValid:!0}}catch(ne){if(ne instanceof r)return{configSource:V,configValid:!1};throw ne}}function rm(P,A,q,V){let ee=A.policy,ne=Ee({...ee,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...ee.destructiveCommandRuleOverrides,...Object.fromEntries(G.flatMap((he)=>he.activationCapability?[[he.id,"on"]]:[]))}},A.state==="degraded"?{diagnostics:A.diagnostics,reason:A.reason}:void 0),ce=B(P,{environment:V,dependencies:{loadPolicySnapshot:()=>ne,getModes:()=>({...q,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return ce.decision.kind==="deny"?ce.decision.ruleId:void 0}function om(P){if(!P)return;return{id:k(P.id),...P.rulebook?{rulebook:{name:k(P.rulebook.name),version:k(P.rulebook.version)}}:{},...P.source?{source:k(P.source)}:{},...P.override?{override:{type:"reason",reason:k(P.override.reason)}}:{}}}function im(P){let A=P.events.flatMap((V)=>V.kind==="step"&&V.scope==="global"?[V.step]:[]),q=new Map;for(let V of P.events){if(V.kind!=="step"||V.scope!=="segment")continue;let ee=q.get(V.segmentIndex)??{index:V.segmentIndex,steps:[]};ee.steps.push(V.step),q.set(V.segmentIndex,ee)}return{steps:A,segments:[...q.values()]}}function sm(P,A){let q=P?.replace(/^custom\./,"");if(!q||!A.policy.rules.some((V)=>V.name===q))return;return A.ruleMetadata[q]??Object.freeze({id:q})}function Al(P){return new Promise((A)=>{process.stdout.write(`${P}
223
+ `,()=>A())})}async function _l(P,A){let q=ri(A);if(!q)return 1;try{let V=qn(q.command,{cwd:q.cwd},P),ee=!!process.env.NO_COLOR||!process.stdout.isTTY;return await Al(q.json?si(V):ii(V,{asciiOnly:ee})),0}catch(V){let ee=am(V instanceof p?V.cause:V);if(ee===void 0)throw V;if(q.json)return await Al(JSON.stringify({error:ee})),1;return console.error(ee),1}}function am(P){if(P instanceof y)return P.message;if(P instanceof f)return P.message;if(P instanceof s&&a[P.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var Tl="2.4.13",Ot=" ",sn="cc-safety-net";function Il(P){return P.argument?`${P.flags} ${P.argument}`:P.flags}function lm(P){return Math.max(...P.map((A)=>Il(A).length))}function cm(P){return Math.max(...P.map((A)=>A.usage.length))}function dm(P){return Math.max(...P.map((A)=>`${sn} ${A.usage}`.length))}function um(P,A){let q=`${sn} ${P.usage}`;return`${Ot}${q.padEnd(A+2)}${P.description}`}function qt(P,A){return`${Ot}${P.padEnd(Math.max(40,P.length+2))}${A}`}function Cn(P,A=console.log){let q=[];if(q.push(`${sn} ${P.name}`),q.push(""),q.push(`${Ot}${P.description}`),q.push(""),q.push("USAGE:"),q.push(`${Ot}${sn} ${P.usage}`),q.push(""),P.subcommands&&P.subcommands.length>0){q.push("SUBCOMMANDS:");let V=cm(P.subcommands);for(let ee of P.subcommands)q.push(`${Ot}${ee.usage.padEnd(V+2)}${ee.description}`);q.push("")}if(P.options.length>0){q.push("OPTIONS:");let V=lm(P.options);for(let ee of P.options){let ne=Il(ee),ce=ee.default?`${ee.description} (default: ${ee.default})`:ee.description;q.push(`${Ot}${ne.padEnd(V+2)}${ce}`)}q.push("")}if(P.examples&&P.examples.length>0){q.push("EXAMPLES:");for(let V of P.examples)q.push(`${Ot}${V}`)}A(q.join(`
224
+ `))}function di(){let P=dm(ir),A=[];A.push(`${sn} v${Tl}`),A.push(""),A.push("Blocks destructive commands and secret access."),A.push(""),A.push("COMMANDS:");for(let q of ir)A.push(um(q,P));A.push(""),A.push("GLOBAL OPTIONS:"),A.push(`${Ot}-h, --help Show help (use with command for command-specific help)`),A.push(`${Ot}-V, --version Show version`),A.push(""),A.push("HELP:"),A.push(`${Ot}${sn} help <command> Show help for a specific command`),A.push(`${Ot}${sn} <command> --help Show help for a specific command`),A.push(""),A.push("ENVIRONMENT VARIABLES:"),A.push(qt(`${o.level.name}=standard|strict|paranoid`,"Set session safety level")),A.push(qt(`${o.worktree.name}=1`,"Allow local git discards in linked worktrees")),A.push(qt(`${o.debug.name}=1`,"Print diagnostic messages to stderr")),A.push(qt(`${o.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),A.push(qt("CC_SAFETY_NET_HOME","Override rule config home directory")),A.push(""),A.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),A.push(qt(`${o.strict.name}=1`,"Force safety.overrides.fail_closed on")),A.push(qt(`${o.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),A.push(qt(`${o.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),A.push(qt(`${o.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),A.push(""),A.push("Documentation: https://ccsafetynet.com/docs"),console.log(A.join(`
225
+ `))}function $l(){console.log(Tl)}function Vn(P,A=console.log){let q=sr(P);if(!q)return!1;if(q.name.toLowerCase()!==P.toLowerCase())return!1;return Cn(q,A),!0}import{existsSync as Br,readFileSync as Ac}from"node:fs";import{join as Gr}from"node:path";import*as Yt from"node:readline";function pm(P){return P==="install"?"Install":"Uninstall"}function fm(P){return P==="install"?"Installing":"Uninstalling"}function mm(P){return P==="install"?"into":"from"}function Nl(P){return P?.available===!0}function gm(P,A){let q=new Set(A);return P.filter((V)=>q.has(V.target)).map((V)=>V.target)}function Ol(P,A,q){if(P.every((V)=>!V.available))return A;return Array.from({length:P.length},(V,ee)=>ee+1).map((V)=>(A+V*q+P.length)%P.length).find((V)=>Nl(P[V]))}function hm(P,A,q){if(q.ctrl&&q.name==="c")return"interrupt";if(q.name==="escape"||A==="q")return"abort";if(P==="install"&&(A==="u"||A==="U"))return"update";if(q.name==="up"||A==="k")return"up";if(q.name==="down"||A==="j")return"down";if(q.name==="space"||A===" ")return"toggle";if(q.name==="return"||q.name==="enter")return"confirm";return null}function ym(P){return{cursor:P.findIndex((A)=>A.available),selected:[]}}function vm(P,A,q){if(q==="confirm"||q==="update"||q==="abort"||q==="interrupt")return{state:P,done:q};if(q==="up")return{state:{...P,cursor:Ol(A,P.cursor,-1)}};if(q==="down")return{state:{...P,cursor:Ol(A,P.cursor,1)}};let V=A[P.cursor];if(!Nl(V))return{state:P};let ee=P.selected.includes(V.target)?P.selected.filter((ne)=>ne!==V.target):gm(A,[...P.selected,V.target]);return{state:{...P,selected:ee}}}var jl="◉",Ml="◯",Hl=">",Ul=" ";function bm(P,A,q,V={}){let ee=V.color!==!1,ne=ee?dt.dim:(ye)=>ye,ce=ee?dt.green:(ye)=>ye,he=ee?dt.bold:(ye)=>ye;return["",`${pm(P)} CC Safety Net ${mm(P)}:`,"",...A.map((ye,be)=>{let xe=q.selected.includes(ye.target),Ie=be===q.cursor,Xe=xe?jl:Ml,et=Ie?Hl:Ul,Re=ye.available?"":` (${ye.unavailableReason??"not installed"})`,at=`${Xe} ${ye.label}${Re}`,ct=!ye.available?ne(at):xe?ce(at):Ie?he(at):at;return`${et} ${ct}`}),"",P==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":A.some((ye)=>ye.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${P}. q/Esc: close`].join(`
226
+ `)}var Fl=["global-hook","plugin"];function Lm(P,A,q={}){let V=q.color!==!1?dt.bold:(ne)=>ne;return["","Install the Kimi Code integration as:","",...[`Global hook — ${A?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((ne,ce)=>{let he=ce===P,ye=`${he?jl:Ml} ${ne}`;return`${he?Hl:Ul} ${he?V(ye):ye}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
227
+ `)}function Gl(P){let{input:A,output:q}=P;Yt.emitKeypressEvents(A);let V=A.isRaw===!0;A.setRawMode(!0),A.resume();let ee=0,ne=()=>{if(ee===0)return;Yt.moveCursor(q,0,-ee),Yt.cursorTo(q,0),Yt.clearScreenDown(q)},ce=()=>{ne();let he=P.render();q.write(`${he}
219
228
  `),ee=he.split(`
220
- `).length};return new Promise((he)=>{let ye=(xe)=>{A.off("keypress",be),A.setRawMode(V),A.pause(),ne(),he(xe)};function be(xe,Ie){P.onKey(xe,Ie,{finish:ye,draw:ce})}A.on("keypress",be),ce()})}function Tl(P={}){let A=0;return _l({input:P.input??process.stdin,output:P.output??process.stdout,render:()=>Xf(A,P.globalHookInstalled===!0),onKey:(q,V,ee)=>{if(V.ctrl&&V.name==="c"){ee.finish(null),(P.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(V.name==="escape"||q==="q")return ee.finish(null);if(V.name==="return"||V.name==="enter")return ee.finish(Sl[A]);if(V.name==="up"||V.name==="down"||q==="k"||q==="j")A=(A+1)%Sl.length,ee.draw()}})}function ni(P=process.stdin,A=process.stdout){return Boolean(P.isTTY&&A.isTTY&&typeof P.setRawMode==="function")}function $l(P,A,q={}){let V=q.output??process.stdout,ee=Kf(A);return _l({input:q.input??process.stdin,output:V,render:()=>Zf(P,A,ee),onKey:(ne,ce,he)=>{let ye=Wf(P,ne,ce);if(!ye)return;let be=Yf(ee,A,ye);if(ee=be.state,be.done==="interrupt"){he.finish(null),(q.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(be.done==="abort")return he.finish(null);if(be.done==="update")return he.finish("update");if(be.done==="confirm"){if(ee.selected.length===0){V.write("\x07"),he.draw();return}he.finish([...ee.selected]),V.write(`${Vf(P)} selected integrations...
221
- `);return}he.draw()}})}import{existsSync as Il,lstatSync as em,mkdirSync as tm,mkdtempSync as nm,readdirSync as rm,readFileSync as xn,rmSync as Tr}from"node:fs";import{basename as om,dirname as im,join as Et}from"node:path";import{fileURLToPath as sm}from"node:url";var ri="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",on="cc-safety-net",sn="cc-safety-net/index.ts";import{spawn as Qf}from"node:child_process";var oi=(P,A)=>{let q=Xt([...P],process.env);return new Promise((V)=>{let ee=Qf(q.cmd,q.args,{cwd:A,stdio:["ignore","pipe","pipe"]}),ne=Io(ee),ce=!1,he=setTimeout(()=>{ce=!0,ee.kill()},120000);ee.on("error",(ye)=>{clearTimeout(he),V({status:null,errorCode:ye.code,stdout:ne.stdout,stderr:[ye.message,ne.stderr].filter(Boolean).join(`
222
- `)})}),ee.on("close",(ye)=>{clearTimeout(he),V({status:ce?null:ye,errorCode:ce?"ETIMEDOUT":void 0,stdout:ne.stdout,stderr:ne.stderr})})})};var kn="cc-safety-net.ts",ii=Et("amp",sn);function am(P){return Et(P.home,".config","amp","plugins","cc-safety-net.ts")}function lm(){let P=im(sm(import.meta.url)),A=Et(P,ii),q=Et(P,"..",ii),V=Et(P,"..","..","..","dist",ii);return[A,q,V]}function cm(P=lm()){let A=P.find((q)=>Il(q)&&em(q).isFile());if(!A)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return A}function Ol(P){try{return JSON.parse(P)}catch{return}}function $r(P){return P.subarray(0,Buffer.byteLength(ri)).toString("utf-8")===ri}async function Hn(P,A,q){let V=await P(A,q);if(V.status===0)return V;throw Error([`Failed to run ${A.join(" ")}${V.status===null?"":` (exit ${V.status})`}.`,[V.stdout,V.stderr].filter(Boolean).join(`
229
+ `).length};return new Promise((he)=>{let ye=(xe)=>{A.off("keypress",be),A.setRawMode(V),A.pause(),ne(),he(xe)};function be(xe,Ie){P.onKey(xe,Ie,{finish:ye,draw:ce})}A.on("keypress",be),ce()})}function Bl(P={}){let A=0;return Gl({input:P.input??process.stdin,output:P.output??process.stdout,render:()=>Lm(A,P.globalHookInstalled===!0),onKey:(q,V,ee)=>{if(V.ctrl&&V.name==="c"){ee.finish(null),(P.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(V.name==="escape"||q==="q")return ee.finish(null);if(V.name==="return"||V.name==="enter")return ee.finish(Fl[A]);if(V.name==="up"||V.name==="down"||q==="k"||q==="j")A=(A+1)%Fl.length,ee.draw()}})}function ui(P=process.stdin,A=process.stdout){return Boolean(P.isTTY&&A.isTTY&&typeof P.setRawMode==="function")}function ql(P,A,q={}){let V=q.output??process.stdout,ee=ym(A);return Gl({input:q.input??process.stdin,output:V,render:()=>bm(P,A,ee),onKey:(ne,ce,he)=>{let ye=hm(P,ne,ce);if(!ye)return;let be=vm(ee,A,ye);if(ee=be.state,be.done==="interrupt"){he.finish(null),(q.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(be.done==="abort")return he.finish(null);if(be.done==="update")return he.finish("update");if(be.done==="confirm"){if(ee.selected.length===0){V.write("\x07"),he.draw();return}he.finish([...ee.selected]),V.write(`${fm(P)} selected integrations...
230
+ `);return}he.draw()}})}import{existsSync as Vl,lstatSync as km,mkdirSync as xm,mkdtempSync as Cm,readdirSync as Sm,readFileSync as Rn,rmSync as Nr}from"node:fs";import{basename as Rm,dirname as Pm,join as Dt}from"node:path";import{fileURLToPath as Em}from"node:url";var pi="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",an="cc-safety-net",ln="cc-safety-net/index.ts";import{spawn as wm}from"node:child_process";var fi=(P,A)=>{let q=Qt([...P],process.env);return new Promise((V)=>{let ee=wm(q.cmd,q.args,{cwd:A,stdio:["ignore","pipe","pipe"]}),ne=Uo(ee),ce=!1,he=setTimeout(()=>{ce=!0,ee.kill()},120000);ee.on("error",(ye)=>{clearTimeout(he),V({status:null,errorCode:ye.code,stdout:ne.stdout,stderr:[ye.message,ne.stderr].filter(Boolean).join(`
231
+ `)})}),ee.on("close",(ye)=>{clearTimeout(he),V({status:ce?null:ye,errorCode:ce?"ETIMEDOUT":void 0,stdout:ne.stdout,stderr:ne.stderr})})})};var Sn="cc-safety-net.ts",mi=Dt("amp",ln);function Dm(P){return Dt(P.home,".config","amp","plugins","cc-safety-net.ts")}function Am(){let P=Pm(Em(import.meta.url)),A=Dt(P,mi),q=Dt(P,"..",mi),V=Dt(P,"..","..","..","dist",mi);return[A,q,V]}function _m(P=Am()){let A=P.find((q)=>Vl(q)&&km(q).isFile());if(!A)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return A}function zl(P){try{return JSON.parse(P)}catch{return}}function jr(P){return P.subarray(0,Buffer.byteLength(pi)).toString("utf-8")===pi}async function zn(P,A,q){let V=await P(A,q);if(V.status===0)return V;throw Error([`Failed to run ${A.join(" ")}${V.status===null?"":` (exit ${V.status})`}.`,[V.stdout,V.stderr].filter(Boolean).join(`
223
232
  `).trim()].filter(Boolean).join(`
224
- `))}async function Fl(P){let A=await P(["amp","plugins","repositories","--json"]);if(A.status===null)throw Error(`${A.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${A.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
233
+ `))}async function Jl(P){let A=await P(["amp","plugins","repositories","--json"]);if(A.status===null)throw Error(`${A.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${A.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
225
234
  ${A.stderr}`.trim());if(A.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${A.status}). Sign in with "amp login" and rerun install --amp.
226
235
  ${[A.stdout,A.stderr].filter(Boolean).join(`
227
- `)}`.trim());let q=Ol(A.stdout),V=(Array.isArray(q)?q:[]).filter((ee)=>ft(ee,"scope")==="user"&&ft(ee,"exists")===!0&&ft(ee,"viewerCanWrite")===!0).map((ee)=>ft(ee,"cloneRef")).find((ee)=>typeof ee==="string"&&ee.length>0);if(!V)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return V}async function jl(P,A,q){let V=nm(Et(A.tmpdir,"cc-safety-net-amp-"));try{return await Hn(P,["amp","clone","user-plugins",V]),await q(V)}finally{Tr(V,{recursive:!0,force:!0})}}function si(P){return`rerun ${P==="overwrite"?"install":"uninstall"} --amp`}function Nl(P,A,q){let V=Et(P,A),ee=bt(V);if(!ee)return;if(ee.isSymbolicLink()||!ee.isFile())throw Error(`Refusing to ${q} ${A} in your Amp personal plugins repository: not a regular file. Remove it there and ${si(q)}.`);let ne=xn(V);if($r(ne))return ne;throw Error(`Refusing to ${q} unmanaged file ${A} in your Amp personal plugins repository. Remove it there and ${si(q)}.`)}function Ml(P,A){let q=Et(P,on),V=bt(q);if(!V)return;if(V.isSymbolicLink()||!V.isDirectory())throw Error(`Refusing to ${A} ${on} in your Amp personal plugins repository: not a regular directory. Remove it there and ${si(A)}.`);return Nl(P,sn,A)}function dm(P){let A=Et(P,kn),q=bt(A);if(!q||q.isSymbolicLink()||!q.isFile())return;let V=xn(A);return $r(V)?V:void 0}async function Hl(P,A,q,V){if(await Hn(P,q,A),(await Hn(P,["git","status","--porcelain"],A)).stdout.trim()==="")return!1;return await Hn(P,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",V],A),await Hn(P,["git","push","origin","HEAD"],A),!0}function _r(P,A){um(P,A),pm(P,A)}function Ul(P,A){if(A==="keep")return;throw Error(`Local Amp plugin ${P} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function um(P,A){let q=am(P),V=bt(q);if(!V)return;if(!V.isSymbolicLink()&&V.isFile()&&$r(xn(q))){Tr(q);return}Ul(q,A)}function pm(P,A){let q=Et(P.home,".config","amp","plugins",on),V=bt(q);if(!V)return;if(!V.isSymbolicLink()&&V.isDirectory()&&fm(q)){Tr(q,{recursive:!0});return}Ul(q,A)}function fm(P){let A=om(sn);if(rm(P).join("\x00")!==A)return!1;let q=Et(P,A),V=bt(q);return!!V&&!V.isSymbolicLink()&&V.isFile()&&$r(xn(q))}function mm(P){let A=u(P);if(!Il(A))return"";let q=Ol(xn(A,"utf-8"));if(!q||typeof q!=="object"||Array.isArray(q))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(C(q,P.home))};
228
- `}async function Gl(P,A=cm(),q=oi){let V=Buffer.concat([xn(A),Buffer.from(mm(P),"utf-8")]),ee=await Fl(q);return jl(q,P,async(ne)=>{let ce=`${ee}/${on}`,he=Ml(ne,"overwrite"),ye=Nl(ne,kn,"overwrite");if(he?.equals(V)&&!ye)return _r(P,"fail"),{path:ce,alreadyInstalled:!0};if(tm(Et(ne,on),{recursive:!0}),kt(Et(ne,sn),V),ye)Tr(Et(ne,kn));let be=await Hl(q,ne,["git","add","--",sn,...ye?[kn]:[]],`chore: update cc-safety-net plugin to v${wt()}`);return _r(P,"fail"),{path:ce,alreadyInstalled:!be}})}async function Bl(P,A=oi){let q=await Fl(A);return jl(A,P,async(V)=>{let ee=Ml(V,"remove"),ne=dm(V),ce=`${q}/${ne&&!ee?kn:on}`;if(!ee&&!ne)return _r(P,"keep"),{path:ce,alreadyInstalled:!1};return await Hl(A,V,["git","rm","--",...ee?[sn]:[],...ne?[kn]:[]],`chore: remove cc-safety-net plugin v${wt()}`),_r(P,"keep"),{path:ce,alreadyInstalled:!0}})}import{existsSync as ql,mkdirSync as gm,readFileSync as hm}from"node:fs";import{dirname as ym}from"node:path";var ai=Nt["antigravity-cli"],an="cc-safety-net";function ln(P){return Boolean(P)&&typeof P==="object"&&!Array.isArray(P)}function Or(){return{PreToolUse:[{hooks:[{type:"command",command:ai,timeout:30}]}]}}function Vl(P){try{let A=JSON.parse(hm(P,"utf-8"));if(!A||typeof A!=="object"||Array.isArray(A))throw Error("Antigravity hooks config must be a JSON object");return A}catch(A){if(A instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${P}: ${A.message}`);throw A}}function zl(P){let A=P[an];if(A===void 0){let V=Or();return P[an]=V,{definition:V,preToolUse:V.PreToolUse??[]}}if(!ln(A))throw Error(`Antigravity hooks config entry "${an}" must be an object`);let q=Array.isArray(A.PreToolUse)?A.PreToolUse:[];return A.PreToolUse=q,{definition:A,preToolUse:q}}function Jl(P){if(!Array.isArray(P.PreToolUse))return!1;return P.PreToolUse.some((A)=>ln(A)&&Array.isArray(A.hooks)&&A.hooks.some((q)=>ln(q)&&q.command===ai))}function vm(P){return Object.values(P).some((A)=>ln(A)&&A.enabled!==!1&&Jl(A))}function bm(P){if(P[an]===void 0)return!1;let A=zl(P);if(A.definition.enabled!==!1||!Jl(A.definition))return!1;return A.definition.enabled=!0,!0}function Lm(P){if(P[an]===void 0){P[an]=Or();return}let A=zl(P);A.definition.enabled=!0,A.preToolUse.push(Or().PreToolUse?.[0]??{hooks:[]})}function wm(P){let A=!1;for(let q of Object.values(P)){if(!ln(q)||!Array.isArray(q.PreToolUse))continue;q.PreToolUse=q.PreToolUse.flatMap((V)=>{if(!ln(V)||!Array.isArray(V.hooks))return[V];let ee=V.hooks.filter((ne)=>!ln(ne)||ne.command!==ai);if(ee.length!==V.hooks.length)A=!0;return ee.length===0?[]:[{...V,hooks:ee}]})}return A}function Ir(P,A){kt(P,`${JSON.stringify(A,null,2)}
229
- `)}function Wl(P){let A=En(P.home);if(gm(ym(A),{recursive:!0}),!ql(A))return Ir(A,{[an]:Or()}),{path:A,alreadyInstalled:!1};let q=Vl(A);if(vm(q))return{path:A,alreadyInstalled:!0};if(bm(q))return Ir(A,q),{path:A,alreadyInstalled:!1};return Lm(q),Ir(A,q),{path:A,alreadyInstalled:!1}}function Kl(P){let A=En(P.home);if(!ql(A))return{path:A,alreadyInstalled:!1};let q=Vl(A);if(!wm(q))return{path:A,alreadyInstalled:!1};return Ir(A,q),{path:A,alreadyInstalled:!0}}import{existsSync as km,readdirSync as xm,rmSync as Cm}from"node:fs";import{join as Sm}from"node:path";function Yl(P,A=process.platform,q){if(!km(P))return;let V=A==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);xm(P).filter((ee)=>ee!==q&&V.test(ee)).forEach((ee)=>{Cm(Sm(P,ee),{recursive:!0,force:!0})})}import{spawn as Rm}from"node:child_process";var Mt=$t.map((P)=>({target:P.id,flag:P.flag,label:vt(P.id),probeCommand:P.probeCommand}));function li(P){let A=new Set(P);return Mt.map((q)=>q.target).filter((q)=>A.has(q))}async function Zl(P,A){for(let q of P)await A(q)}var Pm=5000;function ci(P,A=Pm){return new Promise((q)=>{let V=Xt([...P],process.env),ee=Rm(V.cmd,V.args,{env:process.env,stdio:"ignore"}),ne=!1,ce=(ye)=>{if(ne)return;ne=!0,clearTimeout(he),q(ye)},he=setTimeout(()=>{ee.kill(),ce(!1)},A);ee.on("error",()=>ce(!1)),ee.on("close",(ye)=>ce(ye===0))})}function Xl(P=ci,A={}){let q=new Set(A.configuredTargets??[]);return Promise.all(Mt.map(async(V)=>({target:V.target,flag:V.flag,label:V.label,...ec(A.action,await P(V.probeCommand),q.has(V.target))})))}function Ql(P,A){let q=new Set(A.configuredTargets??[]);return P.map((V)=>({...V,...ec(A.action,V.available,q.has(V.target))}))}function ec(P,A,q){if(P==="uninstall")return q?{available:!0}:{available:!1,unavailableReason:"not installed"};if(P==="install"&&q)return{available:!1,unavailableReason:"already installed"};if(!A)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as tc,readdirSync as Em,rmSync as Dm}from"node:fs";import{join as Cn}from"node:path";function Fr(P,A=process.platform){let q=Cn(P.env.get("npm_config_cache")||(A==="win32"?Cn(P.env.get("LOCALAPPDATA")||Cn(P.home,"AppData","Local"),"npm-cache"):Cn(P.home,".npm")),"_npx");if(!tc(q))return;Em(q).filter((V)=>tc(Cn(q,V,"node_modules","cc-safety-net"))).forEach((V)=>{Dm(Cn(q,V),{recursive:!0,force:!0})})}import{existsSync as ac,mkdirSync as _m,readFileSync as lc}from"node:fs";import{dirname as Tm,join as sc}from"node:path";function Am(P,A){if(P[A]!=="#")return A;let q=P.indexOf(`
230
- `,A+1);return q===-1?P.length:q+1}function di(P,A,q){let V=new RegExp(`^(\\s*)${A}\\s*=\\s*\\[`),ee=0;for(let ne of P.split(`
231
- `)){if(/^\s*\[/.test(ne))return;let ce=V.exec(ne);if(ce){let he=ee+ce[0].lastIndexOf("[");return{start:he,end:yo(P,he,{skipComment:Am,...q})}}ee+=ne.length+1}return}function nc(P,A,q){let V=P.slice(0,A.end).trimEnd(),ee=Zs(P,A.end),ne=ee===""?" ":`${ee} `,ce=!V.endsWith("[")&&!V.endsWith(",");return`${V}${ce?",":""}
232
- ${ne}${q}${P.slice(A.end)}`}function rc(P,A,q){let V=P.indexOf(q,A.start);if(V===-1||V>A.end)return P;return fr(P,{start:V,end:V+q.length})}function oc(P,A){let q=new RegExp(`^\\s*${A}\\s*=\\s*\\[\\s*]\\s*(?:#.*)?$`),V=P.split(`
236
+ `)}`.trim());let q=zl(A.stdout),V=(Array.isArray(q)?q:[]).filter((ee)=>pt(ee,"scope")==="user"&&pt(ee,"exists")===!0&&pt(ee,"viewerCanWrite")===!0).map((ee)=>pt(ee,"cloneRef")).find((ee)=>typeof ee==="string"&&ee.length>0);if(!V)throw Error('Your Amp account has no writable Personal Plugins repository. Sign in with "amp login", open Amp once to create it, and rerun install --amp.');return V}async function Wl(P,A,q){let V=Cm(Dt(A.tmpdir,"cc-safety-net-amp-"));try{return await zn(P,["amp","clone","user-plugins",V]),await q(V)}finally{Nr(V,{recursive:!0,force:!0})}}function gi(P){return`rerun ${P==="overwrite"?"install":"uninstall"} --amp`}function Kl(P,A,q){let V=Dt(P,A),ee=Lt(V);if(!ee)return;if(ee.isSymbolicLink()||!ee.isFile())throw Error(`Refusing to ${q} ${A} in your Amp personal plugins repository: not a regular file. Remove it there and ${gi(q)}.`);let ne=Rn(V);if(jr(ne))return ne;throw Error(`Refusing to ${q} unmanaged file ${A} in your Amp personal plugins repository. Remove it there and ${gi(q)}.`)}function Yl(P,A){let q=Dt(P,an),V=Lt(q);if(!V)return;if(V.isSymbolicLink()||!V.isDirectory())throw Error(`Refusing to ${A} ${an} in your Amp personal plugins repository: not a regular directory. Remove it there and ${gi(A)}.`);return Kl(P,ln,A)}function Tm(P){let A=Dt(P,Sn),q=Lt(A);if(!q||q.isSymbolicLink()||!q.isFile())return;let V=Rn(A);return jr(V)?V:void 0}async function Xl(P,A,q,V){if(await zn(P,q,A),(await zn(P,["git","status","--porcelain"],A)).stdout.trim()==="")return!1;return await zn(P,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",V],A),await zn(P,["git","push","origin","HEAD"],A),!0}function Fr(P,A){Im(P,A),$m(P,A)}function Zl(P,A){if(A==="keep")return;throw Error(`Local Amp plugin ${P} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function Im(P,A){let q=Dm(P),V=Lt(q);if(!V)return;if(!V.isSymbolicLink()&&V.isFile()&&jr(Rn(q))){Nr(q);return}Zl(q,A)}function $m(P,A){let q=Dt(P.home,".config","amp","plugins",an),V=Lt(q);if(!V)return;if(!V.isSymbolicLink()&&V.isDirectory()&&Om(q)){Nr(q,{recursive:!0});return}Zl(q,A)}function Om(P){let A=Rm(ln);if(Sm(P).join("\x00")!==A)return!1;let q=Dt(P,A),V=Lt(q);return!!V&&!V.isSymbolicLink()&&V.isFile()&&jr(Rn(q))}function Fm(P){let A=u(P);if(!Vl(A))return"";let q=zl(Rn(A,"utf-8"));if(!q||typeof q!=="object"||Array.isArray(q))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(C(q,P.home))};
237
+ `}async function Ql(P,A=_m(),q=fi){let V=Buffer.concat([Rn(A),Buffer.from(Fm(P),"utf-8")]),ee=await Jl(q);return Wl(q,P,async(ne)=>{let ce=`${ee}/${an}`,he=Yl(ne,"overwrite"),ye=Kl(ne,Sn,"overwrite");if(he?.equals(V)&&!ye)return Fr(P,"fail"),{path:ce,alreadyInstalled:!0};if(xm(Dt(ne,an),{recursive:!0}),kt(Dt(ne,ln),V),ye)Nr(Dt(ne,Sn));let be=await Xl(q,ne,["git","add","--",ln,...ye?[Sn]:[]],`chore: update cc-safety-net plugin to v${wt()}`);return Fr(P,"fail"),{path:ce,alreadyInstalled:!be}})}async function ec(P,A=fi){let q=await Jl(A);return Wl(A,P,async(V)=>{let ee=Yl(V,"remove"),ne=Tm(V),ce=`${q}/${ne&&!ee?Sn:an}`;if(!ee&&!ne)return Fr(P,"keep"),{path:ce,alreadyInstalled:!1};return await Xl(A,V,["git","rm","--",...ee?[ln]:[],...ne?[Sn]:[]],`chore: remove cc-safety-net plugin v${wt()}`),Fr(P,"keep"),{path:ce,alreadyInstalled:!0}})}import{existsSync as tc,mkdirSync as Nm,readFileSync as jm}from"node:fs";import{dirname as Mm}from"node:path";var hi=jt["antigravity-cli"],cn="cc-safety-net";function dn(P){return Boolean(P)&&typeof P==="object"&&!Array.isArray(P)}function Hr(){return{PreToolUse:[{hooks:[{type:"command",command:hi,timeout:30}]}]}}function nc(P){try{let A=JSON.parse(jm(P,"utf-8"));if(!A||typeof A!=="object"||Array.isArray(A))throw Error("Antigravity hooks config must be a JSON object");return A}catch(A){if(A instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${P}: ${A.message}`);throw A}}function rc(P){let A=P[cn];if(A===void 0){let V=Hr();return P[cn]=V,{definition:V,preToolUse:V.PreToolUse??[]}}if(!dn(A))throw Error(`Antigravity hooks config entry "${cn}" must be an object`);let q=Array.isArray(A.PreToolUse)?A.PreToolUse:[];return A.PreToolUse=q,{definition:A,preToolUse:q}}function oc(P){if(!Array.isArray(P.PreToolUse))return!1;return P.PreToolUse.some((A)=>dn(A)&&Array.isArray(A.hooks)&&A.hooks.some((q)=>dn(q)&&q.command===hi))}function Hm(P){return Object.values(P).some((A)=>dn(A)&&A.enabled!==!1&&oc(A))}function Um(P){if(P[cn]===void 0)return!1;let A=rc(P);if(A.definition.enabled!==!1||!oc(A.definition))return!1;return A.definition.enabled=!0,!0}function Gm(P){if(P[cn]===void 0){P[cn]=Hr();return}let A=rc(P);A.definition.enabled=!0,A.preToolUse.push(Hr().PreToolUse?.[0]??{hooks:[]})}function Bm(P){let A=!1;for(let q of Object.values(P)){if(!dn(q)||!Array.isArray(q.PreToolUse))continue;q.PreToolUse=q.PreToolUse.flatMap((V)=>{if(!dn(V)||!Array.isArray(V.hooks))return[V];let ee=V.hooks.filter((ne)=>!dn(ne)||ne.command!==hi);if(ee.length!==V.hooks.length)A=!0;return ee.length===0?[]:[{...V,hooks:ee}]})}return A}function Mr(P,A){kt(P,`${JSON.stringify(A,null,2)}
238
+ `)}function ic(P){let A=_n(P.home);if(Nm(Mm(A),{recursive:!0}),!tc(A))return Mr(A,{[cn]:Hr()}),{path:A,alreadyInstalled:!1};let q=nc(A);if(Hm(q))return{path:A,alreadyInstalled:!0};if(Um(q))return Mr(A,q),{path:A,alreadyInstalled:!1};return Gm(q),Mr(A,q),{path:A,alreadyInstalled:!1}}function sc(P){let A=_n(P.home);if(!tc(A))return{path:A,alreadyInstalled:!1};let q=nc(A);if(!Bm(q))return{path:A,alreadyInstalled:!1};return Mr(A,q),{path:A,alreadyInstalled:!0}}import{existsSync as qm,readdirSync as Vm,rmSync as zm}from"node:fs";import{join as Jm}from"node:path";function ac(P,A=process.platform,q){if(!qm(P))return;let V=A==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);Vm(P).filter((ee)=>ee!==q&&V.test(ee)).forEach((ee)=>{zm(Jm(P,ee),{recursive:!0,force:!0})})}import{spawn as Wm}from"node:child_process";var Ht=$t.map((P)=>({target:P.id,flag:P.flag,label:bt(P.id),probeCommand:P.probeCommand}));function yi(P){let A=new Set(P);return Ht.map((q)=>q.target).filter((q)=>A.has(q))}async function lc(P,A){for(let q of P)await A(q)}var Km=5000;function vi(P,A=Km){return new Promise((q)=>{let V=Qt([...P],process.env),ee=Wm(V.cmd,V.args,{env:process.env,stdio:"ignore"}),ne=!1,ce=(ye)=>{if(ne)return;ne=!0,clearTimeout(he),q(ye)},he=setTimeout(()=>{ee.kill(),ce(!1)},A);ee.on("error",()=>ce(!1)),ee.on("close",(ye)=>ce(ye===0))})}function cc(P=vi,A={}){let q=new Set(A.configuredTargets??[]);return Promise.all(Ht.map(async(V)=>({target:V.target,flag:V.flag,label:V.label,...uc(A.action,await P(V.probeCommand),q.has(V.target))})))}function dc(P,A){let q=new Set(A.configuredTargets??[]);return P.map((V)=>({...V,...uc(A.action,V.available,q.has(V.target))}))}function uc(P,A,q){if(P==="uninstall")return q?{available:!0}:{available:!1,unavailableReason:"not installed"};if(P==="install"&&q)return{available:!1,unavailableReason:"already installed"};if(!A)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}import{existsSync as pc,readdirSync as Ym,rmSync as Xm}from"node:fs";import{join as Pn}from"node:path";function Ur(P,A=process.platform){let q=Pn(P.env.get("npm_config_cache")||(A==="win32"?Pn(P.env.get("LOCALAPPDATA")||Pn(P.home,"AppData","Local"),"npm-cache"):Pn(P.home,".npm")),"_npx");if(!pc(q))return;Ym(q).filter((V)=>pc(Pn(q,V,"node_modules","cc-safety-net"))).forEach((V)=>{Xm(Pn(q,V),{recursive:!0,force:!0})})}import{existsSync as vc,mkdirSync as Qm,readFileSync as bc}from"node:fs";import{dirname as eg,join as yc}from"node:path";function Zm(P,A){if(P[A]!=="#")return A;let q=P.indexOf(`
239
+ `,A+1);return q===-1?P.length:q+1}function bi(P,A,q){let V=new RegExp(`^(\\s*)${A}\\s*=\\s*\\[`),ee=0;for(let ne of P.split(`
240
+ `)){if(/^\s*\[/.test(ne))return;let ce=V.exec(ne);if(ce){let he=ee+ce[0].lastIndexOf("[");return{start:he,end:So(P,he,{skipComment:Zm,...q})}}ee+=ne.length+1}return}function fc(P,A,q){let V=P.slice(0,A.end).trimEnd(),ee=oa(P,A.end),ne=ee===""?" ":`${ee} `,ce=!V.endsWith("[")&&!V.endsWith(",");return`${V}${ce?",":""}
241
+ ${ne}${q}${P.slice(A.end)}`}function mc(P,A,q){let V=P.indexOf(q,A.start);if(V===-1||V>A.end)return P;return Lr(P,{start:V,end:V+q.length})}function gc(P,A){let q=new RegExp(`^\\s*${A}\\s*=\\s*\\[\\s*]\\s*(?:#.*)?$`),V=P.split(`
233
242
  `),ee=V.findIndex((he)=>/^\s*\[/.test(he)),ne=ee===-1?V:V.slice(0,ee),ce=ee===-1?[]:V.slice(ee);return[...ne.filter((he)=>!q.test(he)),...ce].join(`
234
- `)}function ic(P,A,q){let V=new RegExp(`^\\s*\\[\\[${A}]]\\s*$`,"m");return P.split(/(?=^\s*\[)/m).filter((ee)=>!V.test(ee)||!ee.includes(q)).join("").trimEnd()}var Un=Nt["kimi-code"],ui=`[[hooks]]
243
+ `)}function hc(P,A,q){let V=new RegExp(`^\\s*\\[\\[${A}]]\\s*$`,"m");return P.split(/(?=^\s*\[)/m).filter((ee)=>!V.test(ee)||!ee.includes(q)).join("").trimEnd()}var Jn=jt["kimi-code"],Li=`[[hooks]]
235
244
  event = "PreToolUse"
236
- command = "${Un}"`,cc=`{ event = "PreToolUse", command = "${Un}" }`,dc={stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"};function uc(P){return sc(P.env.get("KIMI_CODE_HOME")??sc(P.home,".kimi-code"),"config.toml")}function $m(P){let A=di(P,"hooks",dc);if(A&&P.slice(A.start+1,A.end).trim())return nc(P,A,cc);let q=oc(P,"hooks").trimEnd();if(q==="")return`${ui}
245
+ command = "${Jn}"`,Lc=`{ event = "PreToolUse", command = "${Jn}" }`,wc={stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"};function kc(P){return yc(P.env.get("KIMI_CODE_HOME")??yc(P.home,".kimi-code"),"config.toml")}function tg(P){let A=bi(P,"hooks",wc);if(A&&P.slice(A.start+1,A.end).trim())return fc(P,A,Lc);let q=gc(P,"hooks").trimEnd();if(q==="")return`${Li}
237
246
  `;return`${q}
238
247
 
239
- ${ui}
240
- `}function pc(P){let A=uc(P);if(_m(Tm(A),{recursive:!0}),!ac(A))return kt(A,`${ui}
241
- `),{path:A,alreadyInstalled:!1};let q=lc(A,"utf-8");if(q.includes(Un))return{path:A,alreadyInstalled:!0};return kt(A,$m(q)),{path:A,alreadyInstalled:!1}}function fc(P){let A=uc(P);if(!ac(A))return{path:A,alreadyInstalled:!1};let q=lc(A,"utf-8");if(!q.includes(Un))return{path:A,alreadyInstalled:!1};let V=di(q,"hooks",dc),ee=V?rc(q,V,cc):`${ic(q,"hooks",Un)}
242
- `;return kt(A,ee),{path:A,alreadyInstalled:!0}}var fi="safety-net@cc-marketplace",mc=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gc=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function gi(P){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Lc(P){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Im(P){return/^Marketplace `cc-marketplace`\s*$/m.test(P??"")}var wc={"claude-code":{installCommands:(P)=>{let A=pr(P,"cc-safety-net@cc-marketplace");return{commands:[...A?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...go(P).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:pr(P,fi)?[["claude","plugin","uninstall",fi]]:[],update:A}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(P,A)=>{let q=A??await _t(["codex","plugin","list"]),V=Lc(q);return{commands:[V||Im(q)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:gi(q)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:V}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:"Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."},"copilot-cli":{installCommands:async()=>{let P=await _t(["copilot","plugin","list"]),A=[...oa(P)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...ia(P)?[["copilot","plugin","uninstall",ta]]:[]];if(na(P))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",jt]],cleanupCommands:A,update:!0};return{commands:[ra(await _t(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",jt]],cleanupCommands:A}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(P)=>{let A=Co(P);if(A.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(A.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:Mo,installCommands:()=>({commands:za()}),uninstallCommands:[["openclaw","plugins","uninstall",Lt,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
243
- `)},opencode:{installCommands:ol},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function kc(P,A=(q)=>q){try{let q=JSON.parse(A(bc(P,"utf-8")));if(!q||typeof q!=="object"||Array.isArray(q))throw Error(`Settings file ${P} must be a JSON object`);return q}catch(q){if(q instanceof SyntaxError)throw Error(`Failed to parse ${P}: ${q.message}`);throw q}}function Om(P){let A=pi(Dn(P),"settings.json");if(!mi(A))return;let q=kc(A,At),V=q.enabledPlugins;if(!V||typeof V!=="object"||Array.isArray(V))return;if(V[jt]!==!1)return;let ee=bc(A,"utf-8"),ne=ee.replace(new RegExp(`("${jt}"\\s*:\\s*)false`),"$1true");return V[jt]=!0,kt(A,ne!==ee?ne:`${JSON.stringify(q,null,2)}
244
- `),`Enabled ${jt} plugin in ${A}`}function Fm(P){let A=Vo(P);if(!mi(A))return;let q=kc(A);if(!Array.isArray(q.packages))return;let V=q.packages.find((ee)=>!!ee&&typeof ee==="object"&&!Array.isArray(ee)&&zo(ee.source)&&("extensions"in ee));if(!V)return;return delete V.extensions,kt(A,`${JSON.stringify(q,null,2)}
245
- `),`Enabled npm:cc-safety-net extensions in ${A}`}function hc(P,A){let q=xt({label:A,booleans:Object.fromEntries(Mt.map((ne)=>[ne.target,[ne.flag]]))},P),V=q.errors[0];if(V)throw Error(V);let ee=Mt.filter((ne)=>q.flags[ne.target]).map((ne)=>ne.target);if(ee.length!==1)throw Error(`Choose exactly one ${A} target: ${Mt.map((ne)=>ne.flag).join(", ")}`);return ee[0]}async function xc(P,A=mn){let[q,V,ee]=await Promise.all([A(["amp","plugins","list"],30000),A(["codex","plugin","list"],30000),A(["copilot","--binary-version"])]);return{codexPluginListOutput:V,hooks:Ln(P,process.cwd(),{ampPluginListOutput:q,codexPluginListOutput:V,copilotCliVersion:ee})}}async function jm(P,A,q=mn){let V=await xc(P,q);return V.hooks.filter((ee)=>A==="install"?ee.configured:ee.detected||ee.inspectionStatus==="not-inspected").filter((ee)=>ee.platform!=="codex"||!gi(V.codexPluginListOutput)||Lc(V.codexPluginListOutput)).map((ee)=>ee.platform)}function Nm(P,A,q,V){if(q.length>0)return{finish:async()=>[hc(q,A)]};if(!V.selectTargets&&!ni(V.input,V.output))return{finish:async()=>[hc(q,A)]};let ee=V.detectConfiguredTargets??(()=>jm(P,A,V.fetchVersion)),ne=Promise.all([Xl(V.probeTargets),ee()]);return{ready:ne,finish:async()=>{let[ce,he]=await ne,ye=Ql(ce,{action:A,configuredTargets:he}),be=V.selectTargets?await V.selectTargets(A,vc(A,ye)):await $l(A,vc(A,ye),{input:V.input,output:V.output});if(be==="update")return be;if(!be||be.length===0)return null;return li(be)}}}async function Mm(P,A,q=!1,V){let ee=wc[P];ee.beforeInstall?.(A);let ne=typeof ee.installCommands==="function"?await ee.installCommands(A,V):{commands:ee.installCommands};return await Oo(ne.commands),await Ua(ne.cleanupCommands??[]),await ne.afterInstall?.(),[`${ne.update||q?"Updated":"Installed"} ${vt(P)} integration`,ee.postInstallMessage].filter(Boolean).join(`
246
- `)}async function Hm(P){let A=wc[P];if(!A.uninstallCommands)throw Error(`${vt(P)} uninstall is not supported`);return await Oo(A.uninstallCommands),`Uninstalled ${vt(P)} integration`}function Um(P){let A=il(P);return A.alreadyInstalled?`Uninstalled OpenCode plugin from ${A.path}`:`OpenCode plugin not installed in ${A.path}`}var Cc={"antigravity-cli":{install:Wl,uninstall:Kl},cursor:{install:ga,uninstall:ha},"grok-build":{install:Ra,uninstall:Pa},"kimi-code":{install:pc,uninstall:fc}};function Gm(P,A,q,V=!1){if(P==="install"&&!V)Fr(q);let ee=Cc[A][P](q),ne=vt(A),ce=P!=="install"?"Uninstalled":V?"Updated":"Installed";return P==="install"&&ee.alreadyInstalled?V?`${ne} hook up to date in ${ee.path}`:`${ne} hook already installed in ${ee.path}`:P==="uninstall"&&!ee.alreadyInstalled?`${ne} hook not installed in ${ee.path}`:`${ce} ${ne} hook ${P==="install"?"in":"from"} ${ee.path}`}var Sc={amp:{install:Gl,uninstall:Bl,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:_a,uninstall:Ta,afterInstall:async(P)=>{let A=To(P);return await _t(["hermes","plugins","enable",Tt,"--no-allow-tool-override"]),!A},beforeUninstall:async(P)=>{_o(P);try{await _t(["hermes","plugins","disable",Tt])}catch(A){console.warn(`${A instanceof Error?A.message:String(A)}
247
- Removing the plugin files anyway; ${Tt} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Bm(P,A,q,V=!1){let ee=Sc[A];if(P==="uninstall")await ee.beforeUninstall?.(q);let ne=P==="install"?await ee.install(q):await ee.uninstall(q),ce=P==="install"&&await ee.afterInstall?.(q),he=vt(A),ye=!ce&&(P==="install"&&ne.alreadyInstalled||P==="uninstall"&&!ne.alreadyInstalled);return[ye?P==="install"?`${he} plugin ${V?"up to date":"already installed"} at ${ne.path}`:`${he} plugin not installed at ${ne.path}`:`${P!=="install"?"Uninstalled":V?"Updated":"Installed"} ${he} plugin ${P==="install"?"at":"from"} ${ne.path}`,ye?void 0:ee.restartNote].filter(Boolean).join(`
248
- `)}var qm={"copilot-cli":{afterInstall:Om},"hermes-agent":{beforeInstall:(P,A)=>{if(!A)Fr(P)}},openclaw:{afterInstall:async()=>{await Ja();return},beforeUninstall:Mo},pi:{afterInstall:Fm}};function Vm(P){return P in Cc}function zm(P){return P in Sc}var yc=["Install CC Safety Net as a native Kimi Code plugin:",""," 1. Start Kimi Code and run: /plugins install https://github.com/kenryu42/cc-safety-net"," Confirm the trust prompt; it defaults to cancel."," 2. Run /reload, or start a new session.","","Note: Kimi Code hooks are fail-open. When the hook process cannot start, crashes, or times","out, Kimi Code allows the tool call."].join(`
249
- `);function Jm(P){if(In({environment:P,cwd:process.cwd()}).status!=="configured")return yc;return[yc,"",dt.red(["CAUTION: the global Kimi Code hook is installed and will run alongside the plugin.","After the plugin is active, remove it with: cc-safety-net uninstall --kimi-code"].join(`
248
+ ${Li}
249
+ `}function xc(P){let A=kc(P);if(Qm(eg(A),{recursive:!0}),!vc(A))return kt(A,`${Li}
250
+ `),{path:A,alreadyInstalled:!1};let q=bc(A,"utf-8");if(q.includes(Jn))return{path:A,alreadyInstalled:!0};return kt(A,tg(q)),{path:A,alreadyInstalled:!1}}function Cc(P){let A=kc(P);if(!vc(A))return{path:A,alreadyInstalled:!1};let q=bc(A,"utf-8");if(!q.includes(Jn))return{path:A,alreadyInstalled:!1};let V=bi(q,"hooks",wc),ee=V?mc(q,V,Lc):`${hc(q,"hooks",Jn)}
251
+ `;return kt(A,ee),{path:A,alreadyInstalled:!0}}var wi="safety-net@cc-marketplace",Sc=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),Rc=new Set(["antigravity-cli","cursor","grok-build","hermes-agent","kimi-code"]);function ki(P){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(P??"")}function _c(P){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(P??"")}function ng(P){return/^Marketplace `cc-marketplace`\s*$/m.test(P??"")}var Tc={"claude-code":{installCommands:(P)=>{let A=br(P,"cc-safety-net@cc-marketplace");return{commands:[...A?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...xo(P).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:br(P,wi)?[["claude","plugin","uninstall",wi]]:[],update:A}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(P,A)=>{let q=A??await St(["codex","plugin","list"]),V=_c(q);return{commands:[V||ng(q)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:ki(q)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:V}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:ea},"copilot-cli":{installCommands:async()=>{let P=await St(["copilot","plugin","list"]),A=[...ua(P)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...pa(P)?[["copilot","plugin","uninstall",la]]:[]];if(ca(P))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",Nt]],cleanupCommands:A,update:!0};return{commands:[da(await St(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",Nt]],cleanupCommands:A}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(P)=>{let A=_o(P);if(A.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(A.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:qo,installCommands:(P)=>{let A=!Br(Gr(Hn(P),Tt));return{commands:tl(),afterInstall:()=>nl(A)}},uninstallCommands:[["openclaw","plugins","uninstall",yt,"--force"]],postInstallMessage:["Restart the OpenClaw Gateway to apply the change.","If plugins.allow is set in openclaw.json, it must also list cc-safety-net."].join(`
252
+ `)},opencode:{installCommands:pl},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]}};function Ic(P,A=(q)=>q){try{let q=JSON.parse(A(Ac(P,"utf-8")));if(!q||typeof q!=="object"||Array.isArray(q))throw Error(`Settings file ${P} must be a JSON object`);return q}catch(q){if(q instanceof SyntaxError)throw Error(`Failed to parse ${P}: ${q.message}`);throw q}}function rg(P){let A=Gr(In(P),"settings.json");if(!Br(A))return;let q=Ic(A,_t),V=q.enabledPlugins;if(!V||typeof V!=="object"||Array.isArray(V))return;if(V[Nt]!==!1)return;let ee=Ac(A,"utf-8"),ne=ee.replace(new RegExp(`("${Nt}"\\s*:\\s*)false`),"$1true");return V[Nt]=!0,kt(A,ne!==ee?ne:`${JSON.stringify(q,null,2)}
253
+ `),`Enabled ${Nt} plugin in ${A}`}function og(P){let A=ei(P);if(!Br(A))return;let q=Ic(A);if(!Array.isArray(q.packages))return;let V=q.packages.find((ee)=>!!ee&&typeof ee==="object"&&!Array.isArray(ee)&&ti(ee.source)&&("extensions"in ee));if(!V)return;return delete V.extensions,kt(A,`${JSON.stringify(q,null,2)}
254
+ `),`Enabled npm:cc-safety-net extensions in ${A}`}function Pc(P,A){let q=xt({label:A,booleans:Object.fromEntries(Ht.map((ne)=>[ne.target,[ne.flag]]))},P),V=q.errors[0];if(V)throw Error(V);let ee=Ht.filter((ne)=>q.flags[ne.target]).map((ne)=>ne.target);if(ee.length!==1)throw Error(`Choose exactly one ${A} target: ${Ht.map((ne)=>ne.flag).join(", ")}`);return ee[0]}async function $c(P,A=hn){let[q,V,ee]=await Promise.all([A(["amp","plugins","list"],30000),A(["codex","plugin","list"],30000),A(["copilot","--binary-version"])]);return{codexPluginListOutput:V,hooks:xn(P,process.cwd(),{ampPluginListOutput:q,codexPluginListOutput:V,copilotCliVersion:ee})}}async function ig(P,A,q=hn){let V=await $c(P,q);return V.hooks.filter((ee)=>A==="install"?ee.configured:ee.detected||ee.inspectionStatus==="not-inspected").filter((ee)=>ee.platform!=="codex"||!ki(V.codexPluginListOutput)||_c(V.codexPluginListOutput)).map((ee)=>ee.platform)}function sg(P,A,q,V){if(q.length>0)return{finish:async()=>[Pc(q,A)]};if(!V.selectTargets&&!ui(V.input,V.output))return{finish:async()=>[Pc(q,A)]};let ee=V.detectConfiguredTargets??(()=>ig(P,A,V.fetchVersion)),ne=Promise.all([cc(V.probeTargets),ee()]);return{ready:ne,finish:async()=>{let[ce,he]=await ne,ye=dc(ce,{action:A,configuredTargets:he}),be=V.selectTargets?await V.selectTargets(A,Dc(A,ye)):await ql(A,Dc(A,ye),{input:V.input,output:V.output});if(be==="update")return be;if(!be||be.length===0)return null;return yi(be)}}}async function ag(P,A,q=!1,V){let ee=Tc[P];ee.beforeInstall?.(A);let ne=typeof ee.installCommands==="function"?await ee.installCommands(A,V):{commands:ee.installCommands};return await Go(ne.commands),await Ka(ne.cleanupCommands??[]),await ne.afterInstall?.(),[`${ne.update||q?"Updated":"Installed"} ${bt(P)} integration`,ee.postInstallMessage].filter(Boolean).join(`
255
+ `)}async function lg(P){let A=Tc[P];if(!A.uninstallCommands)throw Error(`${bt(P)} uninstall is not supported`);return await Go(A.uninstallCommands),`Uninstalled ${bt(P)} integration`}function cg(P){let A=hl(P);return A.alreadyInstalled?`Uninstalled OpenCode plugin from ${A.path}`:`OpenCode plugin not installed in ${A.path}`}var Oc={"antigravity-cli":{install:ic,uninstall:sc},cursor:{install:ka,uninstall:xa},"grok-build":{install:Ia,uninstall:$a},"kimi-code":{install:xc,uninstall:Cc}};function dg(P,A,q,V=!1){if(P==="install"&&!V)Ur(q);let ee=Oc[A][P](q),ne=bt(A),ce=P!=="install"?"Uninstalled":V?"Updated":"Installed";return P==="install"&&ee.alreadyInstalled?V?`${ne} hook up to date in ${ee.path}`:`${ne} hook already installed in ${ee.path}`:P==="uninstall"&&!ee.alreadyInstalled?`${ne} hook not installed in ${ee.path}`:`${ce} ${ne} hook ${P==="install"?"in":"from"} ${ee.path}`}var Fc={amp:{install:Ql,uninstall:ec,restartNote:'Amp personal plugins apply to every Amp session, including Orb threads. Restart Amp or run "plugins: reload" to apply the change.'},"hermes-agent":{install:Ma,uninstall:Ha,afterInstall:async(P)=>{let A=Mo(P);return await St(["hermes","plugins","enable",It,"--no-allow-tool-override"]),!A},beforeUninstall:async(P)=>{jo(P);try{await St(["hermes","plugins","disable",It])}catch(A){console.warn(`${A instanceof Error?A.message:String(A)}
256
+ Removing the plugin files anyway; ${It} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function ug(P,A,q,V=!1){let ee=Fc[A];if(P==="uninstall")await ee.beforeUninstall?.(q);let ne=P==="install"?await ee.install(q):await ee.uninstall(q),ce=P==="install"&&await ee.afterInstall?.(q),he=bt(A),ye=!ce&&(P==="install"&&ne.alreadyInstalled||P==="uninstall"&&!ne.alreadyInstalled);return[ye?P==="install"?`${he} plugin ${V?"up to date":"already installed"} at ${ne.path}`:`${he} plugin not installed at ${ne.path}`:`${P!=="install"?"Uninstalled":V?"Updated":"Installed"} ${he} plugin ${P==="install"?"at":"from"} ${ne.path}`,ye?void 0:ee.restartNote].filter(Boolean).join(`
257
+ `)}var pg={"copilot-cli":{afterInstall:rg},"hermes-agent":{beforeInstall:(P,A)=>{if(!A)Ur(P)}},openclaw:{beforeUninstall:qo},pi:{afterInstall:og}};function fg(P){return P in Oc}function mg(P){return P in Fc}var Ec=["Install CC Safety Net as a native Kimi Code plugin:",""," 1. Start Kimi Code and run: /plugins install https://github.com/kenryu42/cc-safety-net"," Confirm the trust prompt; it defaults to cancel."," 2. Run /reload, or start a new session.","","Note: Kimi Code hooks are fail-open. When the hook process cannot start, crashes, or times","out, Kimi Code allows the tool call."].join(`
258
+ `);function gg(P){if(Mn({environment:P,cwd:process.cwd()}).status!=="configured")return Ec;return[Ec,"",dt.red(["CAUTION: the global Kimi Code hook is installed and will run alongside the plugin.","After the plugin is active, remove it with: cc-safety-net uninstall --kimi-code"].join(`
250
259
  `))].join(`
251
- `)}function vc(P,A){return A.map((q)=>P==="install"&&q.target==="kimi-code"&&q.unavailableReason==="already installed"?{...q,available:!0,unavailableReason:void 0,label:`${q.label} (global hook installed)`}:q)}function Wm(P,A){if(P.selectKimiInstallMethod)return P.selectKimiInstallMethod();if(!ni(P.input,P.output))return Promise.resolve("global-hook");return Tl({input:P.input,output:P.output,globalHookInstalled:In({environment:A,cwd:process.cwd()}).status==="configured"})}async function Rc(P,A,q,V=!1,ee){let ne=qm[A];if(P==="install")ne?.beforeInstall?.(q,V);if(P==="uninstall")ne?.beforeUninstall?.(q);if(Vm(A))return Gm(P,A,q,V);if(zm(A))return Bm(P,A,q,V);if(P==="uninstall")return A==="opencode"?Um(q):Hm(A);return[await Mm(A,q,V,ee),await ne?.afterInstall?.(q)].filter(Boolean).join(`
252
- `)}function Km(P){let A=xt({label:"update"},P).errors[0];if(A)throw Error(A)}async function Ym(P,A=mn){let q=await xc(P,A),V=pi(Dn(P),"installed-plugins");return{targets:li([...q.hooks.filter((ne)=>ne.platform!=="copilot-cli"&&ne.detected).map((ne)=>ne.platform),...[mr,ea,Qs].flatMap((ne)=>mi(pi(V,...ne))?["copilot-cli"]:[]),...pr(P,fi)?["claude-code"]:[],...gi(q.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:q.codexPluginListOutput}}async function Zm(P){let A=c(),q=P.output??process.stdout,V=(P.scriptPath??process.argv[1]??"").split(/[\\/]/),ee=V.find((et)=>/^bunx-\d+-/.test(et)),ne=ee!==void 0||V.includes("_npx")?null:(P.checkLatestVersion??Wt)(),ce=async()=>{let et=ne&&await ne;if(et?.updateAvailable)q.write(`
260
+ `)}function Dc(P,A){return A.map((q)=>P==="install"&&q.target==="kimi-code"&&q.unavailableReason==="already installed"?{...q,available:!0,unavailableReason:void 0,label:`${q.label} (global hook installed)`}:q)}function hg(P,A){if(P.selectKimiInstallMethod)return P.selectKimiInstallMethod();if(!ui(P.input,P.output))return Promise.resolve("global-hook");return Bl({input:P.input,output:P.output,globalHookInstalled:Mn({environment:A,cwd:process.cwd()}).status==="configured"})}async function Nc(P,A,q,V=!1,ee){let ne=pg[A];if(P==="install")ne?.beforeInstall?.(q,V);if(P==="uninstall")ne?.beforeUninstall?.(q);if(fg(A))return dg(P,A,q,V);if(mg(A))return ug(P,A,q,V);if(P==="uninstall")return A==="opencode"?cg(q):lg(A);return[await ag(A,q,V,ee),await ne?.afterInstall?.(q)].filter(Boolean).join(`
261
+ `)}function yg(P){let A=xt({label:"update"},P).errors[0];if(A)throw Error(A)}async function vg(P,A=hn){let q=await $c(P,A),V=Gr(In(P),"installed-plugins");return{targets:yi([...q.hooks.filter((ne)=>ne.platform!=="copilot-cli"&&ne.detected).map((ne)=>ne.platform),...[wr,aa,sa].flatMap((ne)=>Br(Gr(V,...ne))?["copilot-cli"]:[]),...br(P,wi)?["claude-code"]:[],...ki(q.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:q.codexPluginListOutput}}async function bg(P){let A=c(),q=P.output??process.stdout,V=(P.scriptPath??process.argv[1]??"").split(/[\\/]/),ee=V.find((et)=>/^bunx-\d+-/.test(et)),ne=ee!==void 0||V.includes("_npx")?null:(P.checkLatestVersion??Wt)(),ce=async()=>{let et=ne&&await ne;if(et?.updateAvailable)q.write(`
253
262
  Update available: cc-safety-net ${et.currentVersion} → ${et.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
254
- `)},he=Ym(A,P.fetchVersion??mn).then(async(et)=>{let Re=new Set(et.targets);return{targets:et.targets,codexPluginListOutput:et.codexPluginListOutput,available:new Map(await Promise.all(Mt.filter((at)=>Re.has(at.target)&&mc.has(at.target)).map(async(at)=>[at.target,await ci(at.probeCommand)])))}}),ye=await Pn(P.showBanner??!0,()=>({ready:he,finish:()=>he}),()=>Rn({input:P.input??process.stdin,output:q}),{loadingMessage:"Checking installed integrations…",output:q}),be=await Promise.resolve().then(()=>(Yl(A.tmpdir,process.platform,ee),null)).catch((et)=>Gn(et));if(ye.targets.length===0){if(q.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),be!==null)console.error(be);return await ce(),be===null?0:1}let xe=ye.targets.some((et)=>gc.has(et))?await Promise.resolve().then(()=>(Fr(A),null)).catch((et)=>Gn(et)):null,Ie=await cr(Promise.all(ye.targets.map((et)=>{if(mc.has(et)&&!ye.available.get(et))return Promise.resolve({message:`${vt(et)} not found; skipped`,failed:!1});if(xe!==null&&gc.has(et))return Promise.resolve({message:xe,failed:!0});return Rc("install",et,A,!0,ye.codexPluginListOutput).then((Re)=>({message:Re,failed:!1}),(Re)=>({message:Gn(Re),failed:!0}))})),{loadingMessage:`Updating ${ye.targets.length} integration${ye.targets.length===1?"":"s"}…`,output:q}),Xe=be===null?Ie:[...Ie,{message:be,failed:!0}];return Xe.forEach((et)=>et.failed?console.error(et.message):q.write(`${et.message}
255
- `)),await ce(),Xe.some((et)=>et.failed)?1:0}function hi(P,A={}){return Promise.resolve().then(()=>Km(P)).then(()=>Zm(A)).catch((q)=>(console.error(Gn(q)),1))}async function Bn(P,A,q={}){try{let V=c(),ee=await Pn(!0,()=>Nm(V,P,A,q),()=>Rn({input:q.input??process.stdin,output:q.output??process.stdout}),{loadingMessage:P==="install"?"Checking available integrations…":"Checking installed integrations…",output:q.output??process.stdout});if(!ee)return(q.output??process.stdout).write(`Cancelled: nothing was ${P}ed.
256
- `),0;if(ee==="update")return(q.runUpdate??(()=>hi([],{fetchVersion:q.fetchVersion,input:q.input,output:q.output,showBanner:!1})))();let ne=q.output??process.stdout;return await Zl(ee,async(ce)=>{if(ce==="kimi-code"&&P==="install"){let ye=await Wm(q,V);if(ye===null){ne.write(`Cancelled: Kimi Code integration was not installed.
257
- `);return}if(ye==="plugin"){ne.write(`${Jm(V)}
258
- `);return}}let he=await cr(Rc(P,ce,V),{loadingMessage:`${P==="install"?"Installing":"Uninstalling"} ${vt(ce)} integration…`,output:ne});ne.write(`${he}
259
- `)}),0}catch(V){return console.error(Gn(V)),1}}function Gn(P){let A=P instanceof Error?P.message:String(P),q=typeof P==="object"&&P!==null&&"code"in P?P.code:null;if(q==="EACCES"||q==="EPERM")return`${A}
263
+ `)},he=vg(A,P.fetchVersion??hn).then(async(et)=>{let Re=new Set(et.targets);return{targets:et.targets,codexPluginListOutput:et.codexPluginListOutput,available:new Map(await Promise.all(Ht.filter((at)=>Re.has(at.target)&&Sc.has(at.target)).map(async(at)=>[at.target,await vi(at.probeCommand)])))}}),ye=await An(P.showBanner??!0,()=>({ready:he,finish:()=>he}),()=>Dn({input:P.input??process.stdin,output:q}),{loadingMessage:"Checking installed integrations…",output:q}),be=await Promise.resolve().then(()=>(ac(A.tmpdir,process.platform,ee),null)).catch((et)=>Wn(et));if(ye.targets.length===0){if(q.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),be!==null)console.error(be);return await ce(),be===null?0:1}let xe=ye.targets.some((et)=>Rc.has(et))?await Promise.resolve().then(()=>(Ur(A),null)).catch((et)=>Wn(et)):null,Ie=await gr(Promise.all(ye.targets.map((et)=>{if(Sc.has(et)&&!ye.available.get(et))return Promise.resolve({message:`${bt(et)} not found; skipped`,failed:!1});if(xe!==null&&Rc.has(et))return Promise.resolve({message:xe,failed:!0});return Nc("install",et,A,!0,ye.codexPluginListOutput).then((Re)=>({message:Re,failed:!1}),(Re)=>({message:Wn(Re),failed:!0}))})),{loadingMessage:`Updating ${ye.targets.length} integration${ye.targets.length===1?"":"s"}…`,output:q}),Xe=be===null?Ie:[...Ie,{message:be,failed:!0}];return Xe.forEach((et)=>et.failed?console.error(et.message):q.write(`${et.message}
264
+ `)),await ce(),Xe.some((et)=>et.failed)?1:0}function xi(P,A={}){return Promise.resolve().then(()=>yg(P)).then(()=>bg(A)).catch((q)=>(console.error(Wn(q)),1))}async function Kn(P,A,q={}){try{let V=c(),ee=await An(!0,()=>sg(V,P,A,q),()=>Dn({input:q.input??process.stdin,output:q.output??process.stdout}),{loadingMessage:P==="install"?"Checking available integrations…":"Checking installed integrations…",output:q.output??process.stdout});if(!ee)return(q.output??process.stdout).write(`Cancelled: nothing was ${P}ed.
265
+ `),0;if(ee==="update")return(q.runUpdate??(()=>xi([],{fetchVersion:q.fetchVersion,input:q.input,output:q.output,showBanner:!1})))();let ne=q.output??process.stdout;return await lc(ee,async(ce)=>{if(ce==="kimi-code"&&P==="install"){let ye=await hg(q,V);if(ye===null){ne.write(`Cancelled: Kimi Code integration was not installed.
266
+ `);return}if(ye==="plugin"){ne.write(`${gg(V)}
267
+ `);return}}let he=await gr(Nc(P,ce,V),{loadingMessage:`${P==="install"?"Installing":"Uninstalling"} ${bt(ce)} integration…`,output:ne});ne.write(`${he}
268
+ `)}),0}catch(V){return console.error(Wn(V)),1}}function Wn(P){let A=P instanceof Error?P.message:String(P),q=typeof P==="object"&&P!==null&&"code"in P?P.code:null;if(q==="EACCES"||q==="EPERM")return`${A}
260
269
  Check file permissions for the target config file and parent directory.`;if(q==="ENOENT")return`${A}
261
270
  Check that the target config path and parent directory exist.`;if(q==="ENOTDIR")return`${A}
262
- Check that every parent path component is a directory.`;return A}import{mkdirSync as rg}from"node:fs";import{dirname as og}from"node:path";import{createInterface as ig}from"node:readline";import{existsSync as Ec,readFileSync as Xm}from"node:fs";function cn(P,A){let q=Ye(P,A);return{policy:q.policy,errors:ie(qe(q.issues,Je,(V)=>V.kind==="custom")," "," ")}}function qn(P,A){return cn(P,A).errors}function Pc(P,A){return{"safety.level":P.safety.level,...yi("safety.overrides",P.safety.overrides),"workflow.worktree_mode":String(P.workflow.worktree_mode),"destructive_command_protection.enabled":String(P.destructive_command_protection.enabled),...yi("destructive_command_protection.overrides",P.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":vi(P.destructive_command_protection.allow_paths),"secret_protection.enabled":String(P.secret_protection.enabled),...yi("secret_protection.overrides",P.secret_protection.overrides),"secret_protection.deny_paths":vi(P.secret_protection.deny_paths),"secret_protection.allow_paths":vi(P.secret_protection.allow_paths),...A?{"audit.retention_days":String(P.audit.retention_days)}:{}}}function jr(P,A,q){let V=Pc(P,q),ee=Pc(A,q);return[...new Set([...Object.keys(V),...Object.keys(ee)])].flatMap((ne)=>V[ne]===ee[ne]?[]:[{field:ne,before:V[ne],after:ee[ne]}])}function Vn(P,A){let q=u(P,A);if(!Ec(q))return{baseline:C(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,P.home),diagnostics:[]};let V=dn(q),ee=cn(V.value,P.home);return{baseline:ee.policy,diagnostics:V.errors.length>0?V.errors:ee.errors}}function dn(P){if(!Ec(P))return{errors:[`${P}: file not found`]};try{return{value:JSON.parse(Xm(P,"utf-8")),errors:[]}}catch(A){let q=A instanceof Error?A.message:String(A);return{errors:[`${P}: ${A instanceof SyntaxError?`Invalid JSON: ${q}`:q}`]}}}function Nr(P,A){let q=Qm(P)?P:{};return{version:A.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((V)=>q[V]!==void 0).map((V)=>[V,q[V]]))}}function yi(P,A){return Object.fromEntries(Object.entries(A).flatMap(([q,V])=>V===void 0?[]:[[`${P}.${q}`,String(V)]]))}function vi(P){return P.length===0?"(none)":P.join(", ")}function Qm(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{chmodSync as eg,existsSync as Dc,mkdirSync as tg,readFileSync as Ac}from"node:fs";import{dirname as ng}from"node:path";function _c(P,A={}){let q=u(P,A);if(!Dc(q))return{path:q,exists:!1,raw:"",policy:W(),errors:[]};let V=Ac(q,"utf-8");if(!V.trim())return{path:q,exists:!0,raw:V,policy:W(),errors:["Config file is empty"]};try{let ee=cn(JSON.parse(V),P.home);return{path:q,exists:!0,raw:V,policy:ee.policy,errors:ee.errors}}catch(ee){return{path:q,exists:!0,raw:V,policy:W(),errors:[`Invalid JSON: ${ee instanceof Error?ee.message:String(ee)}`]}}}function Vt(P,A,q={}){let V=u(P,q),ee=cn(A,P.home);if(ee.errors.length>0)return{path:V,policy:W(),errors:ee.errors};let ne=ee.policy;return tg(ng(V),{recursive:!0,mode:448}),g(re(V),`${JSON.stringify(ne,null,2)}
263
- `,384),eg(V,384),{path:V,policy:ne,errors:[]}}function Tc(P,A){let q=cn(A,P.home);if(q.errors.length>0)return{errors:q.errors};return{preview:Ae(q.policy,P.env),errors:[]}}function $c(P,A={}){let q=u(P,A);if(!Dc(q))return Vt(P,X,A);let V=Ac(q,"utf-8");if(!V.trim())return Vt(P,X,A);try{return Vt(P,C(JSON.parse(V),P.home),A)}catch{return Vt(P,X,A)}}var Ic=new Set(["check","apply"]),Oc="(unset)";async function jc(P,A,q={}){let V=xt({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},A),ee=V.positionals[0],ne=[...V.errors,...ee&&!Ic.has(ee)?[`Unknown policy subcommand: ${ee}`]:[],...ee&&Ic.has(ee)&&!V.positionals[1]?[`policy ${ee} requires a file`]:[],...V.positionals.slice(2).map((Re)=>`Unexpected policy argument: ${Re}`)];if(ne.length>0){for(let Re of ne)console.error(Re);return 1}let ce=V.positionals[1];if(!ee||!ce)return wn(Xn,console.error),1;let he=V.flags.global?u(P):b(q.cwd??process.cwd()),ye=dn(ce),be=[...ye.errors,...qn(ye.value,P.home).map((Re)=>`${ce}: ${Re}`),...!V.flags.global&&lg(ye.value)&&ye.value.audit!==void 0?[`${ce}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(be.length>0){for(let Re of be)console.error(Re);return 1}let xe=C(ye.value,P.home);if(console.log(`Scope: ${V.flags.global?"user":"project"} (${he})`),console.log(`Proposal: ${ce}`),V.flags.global)Fc(C(dn(he).value,P.home),xe,!0);if(!V.flags.global){let Re=Vn(P).baseline;console.log("Effective policy (user + project merged):"),Fc(Z(Re,ae(dn(he).value,P.home).policy).policy,Z(Re,ae(ye.value,P.home).policy).policy,!1)}if(ee==="check")return 0;let Ie=q.input??process.stdin,Xe=q.output??process.stdout;if(!Ie.isTTY||!Xe.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${ce}${V.flags.global?" --global":""}`),1;if(!await sg(`Apply this policy to ${he}? [y/N] `,Ie,Xe))return console.log("Cancelled; nothing was written."),0;return ag(P,he,ye.value,xe,V.flags.global),console.log(`Policy applied: ${he}`),0}function sg(P,A,q){let V=ig({input:A,output:q,terminal:!1});return new Promise((ee)=>{V.once("close",()=>ee(!1)),V.question(P,(ne)=>{ee(/^y(es)?$/i.test(ne.trim())),V.close()})})}function ag(P,A,q,V,ee){if(ee){Vt(P,V);return}rg(og(A),{recursive:!0}),Rt(A,Nr(q,V))}function Fc(P,A,q){let V=jr(P,A,q);if(V.length===0){console.log("No changes.");return}console.log(`Changes (${V.length}):`);for(let ee of V)console.log(` ${ee.field}: ${ee.before??Oc} -> ${ee.after??Oc}`)}function lg(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{join as wh}from"node:path";var Nc="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Mr(P,A){if(!P.ok){Bc(P);return}Uc(P,A)}function Hc(P,A,q){if(P.ok)console.log(q);if(!P.add){Mr(P,`Added rulebook source: ${A}`);return}if(!P.ok){Bc(P);return}if(P.add.added.length>0)console.log(`Added ${P.add.added.length} ${P.add.added.length===1?"rulebook":"rulebooks"} from ${P.add.source} at ${P.add.ref}:`),P.add.added.forEach((V)=>{console.log(` - ${V}`)});if(P.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${P.add.source} at ${P.add.ref}: ${P.add.alreadyConfigured.join(", ")}`);if(P.add.commits.length>0)console.log(`Vendored at ${P.add.commits.map((V)=>V.slice(0,7)).join(", ")}.`);Uc(P,"Rule config updated.")}function Uc(P,A){for(let q of P.changes??[])console.log(q);console.log(A),console.log(""),cg(P.entries)}function cg(P){if(P.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${P.length}):`);for(let A of P)console.log(` - ${A.name} ${A.version} (${dg(A.ruleCount)})`),console.log(` Source: ${A.spec}`)}function dg(P){return`${P} ${P===1?"rule":"rules"}`}function Gc(P){un("Active sources",P.rulebooks,(A)=>[`[${A.source}] ${A.name} ${A.version}`,` Source: ${A.spec}`]),un("Active rules",P.rules,(A)=>[`[${pg(P,A.name)}] ${A.name}`,...ug(A),` Reason: ${A.reason}`]),un("Disabled rules",Mc(P,"off"),(A)=>[A.key]),un("Reason overrides",Mc(P,"reason"),(A)=>[A.key,` Reason: ${A.value.reason}`]),un("Transparent wrappers",P.transparent_wrappers,(A)=>[A]),un("Issues",P.errors,(A)=>[A]),un("Warnings",P.warnings,(A)=>[A])}function un(P,A,q){if(A.length===0){console.log(`${P}: (none)`);return}console.log(`${P} (${A.length}):`);for(let V of A){let[ee,...ne]=q(V);console.log(` - ${ee}`);for(let ce of ne)console.log(` ${ce}`)}}function ug(P){if(!P.match)return[` Command: ${P.subcommand?`${P.command} ${P.subcommand}`:P.command}`,` Block args: ${P.block_args.join(", ")}`];return[` Command: ${[P.command,...P.match.command_path].join(" ")}`,...P.match.any_args?[` Any args: ${P.match.any_args.join(", ")}`]:[],...P.match.exclude_args?[` Exclude args: ${P.match.exclude_args.join(", ")}`]:[]]}function pg(P,A){return P.rulebooks.find((q)=>q.rules.includes(A))?.source??"project"}function Mc(P,A){return Object.entries({...P.userConfig?.overrides,...P.projectConfig?.overrides}).filter((q)=>{if(A==="off")return q[1]==="off";return!!q[1]&&typeof q[1]==="object"}).map(([q,V])=>({key:q,value:V}))}function Bc(P){for(let A of P.errors)console.error(A)}import{dirname as pd,join as Jr}from"node:path";import{join as xi,resolve as Cg}from"node:path";function bi(P){let A=m(P);if(A.errors.length>0)return{ok:!1,result:{ok:!1,errors:A.errors,entries:[]}};return{ok:!0,config:A.config??it}}function qc(P){Rt(P,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function Vc(P){Rt(P,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Br}from"node:path";var fg="custom.";function Hr(P){if(P.rulebook_version!==2)return[];let A=P.rules.map((q)=>({name:q.name,command:q.command,block_args:[],match:q.match,reason:q.reason,intent:q.intent}));return(P.tests??[]).flatMap((q,V)=>{let ee=Li(h(q.command));if(ee.length===0)return[`tests[${V}]: could not parse fixture command: ${q.command}`];let ne=ee.reduce((ce,he)=>ce??_(he,A)?.id.slice(fg.length),void 0);if(q.expect==="blocked"){if(ne===q.rule)return[];let ce=ne?`"${ne}" matched first`:"no rule matched";return[`tests[${V}]: expected "${q.rule}" to block "${q.command}" but ${ce}`]}return ne?[`tests[${V}]: expected "${q.command}" to be allowed but "${ne}" matched`]:[]})}function Li(P){return P.nodes.flatMap((A)=>{if(A.kind==="group"||A.kind==="function")return Li(A.body);if(A.kind!=="command")return[];let q=ge(Q(A.dialect,A.words)).words.map(t);return[...q.length>0?[q]:[],...A.nested.flatMap((V)=>Li(V))]})}var Ur=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Gr(P={}){return{requests:0,responseBytes:0,maxRequests:P.maxRequests??Ur.maxRequests,maxResponseBytes:P.maxResponseBytes??Ur.maxResponseBytes}}function zt(P){return{controller:new AbortController,budget:Gr(),resolveUrl:P}}function zc(P){return P instanceof Error&&P.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Jc(P){if(P.requests>=P.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.requests++}function Wc(P,A){if(A>P.maxResponseBytes-P.responseBytes)throw P.responseBytes+=A,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.responseBytes+=A}var Zc=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Kc(P,A,q=v(Br(Br(A)),"rules policy"),V=zt()){if(S(P))return yg(P,V);return hg(P,A,q)}async function Xc(P,A,q,V,ee,ne){if(!S(P))return Kc(P,A,q,V);let ce=ee?null:mg(P,A,q);if(ce)return ce;if(!ee&&!ne)throw Error(`${P} is not vendored; run rule update ${P} to vendor it`);return Kc(P,A,q,V)}function mg(P,A,q=v(Br(Br(A)),"rules policy")){let V=I(P),ee=O(A,V.name),ne=n(i(q,ee));if(ne===null)return null;let ce=se(wi(ne,`Invalid rulebook ${ee}.`));if(ce.name!==V.name)throw Error(`rulebook name "${ce.name}" in ${ee} must match "${V.name}"`);return{spec:P,rulebook:ce,content:ne}}async function Qc(P,A={}){if(!K(P))throw Error(`Invalid GitHub repository source: ${P}`);let[q,V]=P.split("/");if(!q||!V)throw Error(`Invalid GitHub repository source: ${P}`);if(A.ref!==void 0&&!oe(A.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${A.ref}`);let ee=A.operation??zt(),ne=A.ref??await gg(q,V,P,ee),ce=await td(q,V,ne,P,ee),he=await qr(`https://api.github.com/repos/${q}/${V}/git/trees/${ce}?recursive=1`,"tree",ee),ye=he.response;if(!ye.ok)throw Error(`Failed to inspect ${P}: GitHub tree returned ${ye.status}`);let be=JSON.parse(he.content);if(!Array.isArray(be?.tree))throw Error(`Failed to inspect ${P}: unexpected GitHub tree response`);let xe=be.tree,Ie=[...new Set(xe.flatMap((Xe)=>{if(!Xe||typeof Xe!=="object")return[];let et=Xe;if(et.type!=="blob"||typeof et.path!=="string")return[];let Re=et.path.match(rt);return Re?.[1]?[Re[1]]:[]}))].sort();if(Ie.length===0)throw Error(`No rulebooks found in ${P} under ${de}/`);return{source:P,owner:q,repo:V,ref:ne,commit:ce,names:Ie}}async function gg(P,A,q,V){let ee=await qr(`https://api.github.com/repos/${P}/${A}`,"metadata",V),ne=ee.response;if(!ne.ok)throw Error(`Failed to inspect ${q}: GitHub returned ${ne.status}`);let he=JSON.parse(ee.content)?.default_branch;if(typeof he!=="string"||he==="")throw Error(`Failed to inspect ${q}: missing default branch`);if(!oe(he))throw Error(`GitHub returned an invalid default branch: ${he}`);return he}function hg(P,A,q){ot(P);let V=O(A,P),ee=n(i(q,V));if(ee===null)throw Error(`Rulebook source not found: ${P}`);let ne=ed(wi(ee,"Invalid local rulebook source."));if(ne.name!==P)throw Error(`rulebook name "${ne.name}" must match local source "${P}"`);return{spec:P,rulebook:ne,content:ee}}async function yg(P,A){let q=I(P),V=await td(q.owner,q.repo,q.ref,P,A),ee=await qr(`https://raw.githubusercontent.com/${q.owner}/${q.repo}/${V}/${q.path}`,"raw",A),ne=ee.response;if(!ne.ok)throw Error(`Failed to fetch ${P}: GitHub raw returned ${ne.status}`);let ce=ee.content,he=ed(wi(ce,"Invalid GitHub rulebook response."));if(he.name!==q.name)throw Error(`rulebook name "${he.name}" must match GitHub source "${q.name}"`);return{spec:P,rulebook:he,content:ce}}function ed(P){let A=se(P),q=Hr(A);if(q.length>0)throw Error(q.join("; "));return A}function wi(P,A){try{return JSON.parse(P)}catch{throw Error(A)}}async function td(P,A,q,V,ee){let ne=await qr(`https://api.github.com/repos/${P}/${A}/commits/${encodeURIComponent(q)}`,"commit",ee),ce=ne.response;if(!ce.ok)throw Error(`Failed to resolve ${V}: GitHub returned ${ce.status}`);let he=JSON.parse(ne.content);if(typeof he?.sha!=="string"||he.sha==="")throw Error(`Failed to resolve commit for ${V}`);return he.sha}async function vg(P,A,q={}){if(q.signal?.aborted)throw q.signal.reason;let V=q.budget??Gr(),ee=new AbortController,ne=()=>ee.abort(q.signal?.reason);q.signal?.addEventListener("abort",ne,{once:!0});let ce=!1,he=setTimeout(()=>{if(ee.signal.aborted)return;ce=!0,ee.abort()},q.timeoutMs??Zc.timeoutMs);try{if(q.signal?.aborted)throw q.signal.reason;Jc(V);let ye=await fetch(P,{signal:ee.signal,redirect:"error"});if(!ye.ok)return nd(ye),{response:ye,content:""};return{response:ye,content:await bg(ye,A,V,()=>ee.abort())}}catch(ye){if(ce)throw Error("GitHub request timed out",{cause:ye});if(q.signal?.aborted)throw q.signal.reason;throw ye}finally{clearTimeout(he),q.signal?.removeEventListener("abort",ne)}}function qr(P,A,q){return vg(q.resolveUrl?.(P)??P,A,{budget:q.budget,signal:q.controller.signal})}async function bg(P,A,q=Gr(),V){let ee=Zc[`${A}Bytes`],ne=Number(P.headers.get("content-length"));if(Number.isFinite(ne)&&ne>ee)throw nd(P),Error(`GitHub ${A} response exceeds ${ee} bytes`);if(!P.body)return"";let ce=P.body.getReader(),he=[],ye=0;while(!0){let be=await ce.read();if(be.done)break;try{Wc(q,be.value.byteLength)}catch(xe){throw V?.(),Yc(ce),xe}if(ye+=be.value.byteLength,ye>ee)throw V?.(),Yc(ce),Error(`GitHub ${A} response exceeds ${ee} bytes`);he.push(Buffer.from(be.value))}return Buffer.concat(he,ye).toString("utf-8")}function nd(P){if(!P.body)return;rd(()=>P.body?.cancel())}function Yc(P){rd(()=>P.cancel())}function rd(P){try{Promise.resolve(P()).catch(()=>{})}catch{}}var Lg=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function od(P,A){let q=ad(P.rules,A);if(q.length>0)return{ok:!0,specs:q};return sd(P.rules,A)}function id(P,A){let q=ad(P,A);if(q.length>0)return{ok:!0,specs:q};let V=kg(P,A);if(V.length>0)return{ok:!0,specs:V};let ee=xg(P,A);if(!ee.ok)return ee;if(ee.specs.length>0)return{ok:!0,specs:ee.specs};return sd(P,A)}function sd(P,A){let q=P.filter((V)=>ki(V)?.name===A);if(q.length===1)return{ok:!0,specs:q};return wg(A,q)}function wg(P,A){return{ok:!1,result:{ok:!1,errors:A.length===0?[`No configured rulebook matches ${P}`]:[`Ambiguous rulebook match ${P}: ${A.join(", ")}`],entries:[]}}}function ad(P,A){return P.filter((q)=>q===A)}function kg(P,A){let q=A.match(Lg),V=q?.[1],ee=q?.[2],ne=q?.[3];if(!V||!ee||!ne||!oe(ne))return[];return ld(P,(ce)=>ce.owner===V&&ce.repo===ee&&ce.ref===ne)}function xg(P,A){if(!K(A))return{ok:!0,specs:[]};let[q,V]=A.split("/"),ee=ld(P,(ce)=>ce.owner===q&&ce.repo===V);if(new Set(ee.map((ce)=>ki(ce)?.ref).filter((ce)=>!!ce)).size<2)return{ok:!0,specs:ee};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${A}. Use an explicit ref:`,` cc-safety-net rule remove ${A}#<ref>`],entries:[]}}}function ki(P){try{return I(P)}catch{return null}}function ld(P,A){return P.filter((q)=>{let V=ki(q);return V?A(V):!1})}async function zr(P,A={}){let q=Ci(A);return Sg(P,q,await Vr(P,q,zt()))}function Sg(P,A,q){if(!q.ok)return q;let V=Pt(P,A),ee=[...new Set(U(V.configPath,V.filesystemScope))];if(ee.length===0)return q;return{ok:!1,errors:ee,entries:q.entries}}async function Vr(P,A,q,V={},ee=new Set,ne=new Set){try{let ce=Pt(P,A),he=bi(ce.configTarget);if(!he.ok)return he.result;let ye=he.config,be=A.only?od(ye,A.only):{ok:!0,specs:ye.rules};if(!be.ok)return be.result;let xe=new Set([...A.refresh?be.specs:[],...ee]),Ie=(ut)=>Xc(ut,ce.configDir,ce.filesystemScope,q,xe.has(ut),!A.refresh||xe.has(ut)),Xe=await Fg(ye.rules,A.refresh?(ut)=>Ie(ut).then((yt)=>({ok:!0,item:yt})).catch((yt)=>{if(zc(yt))throw yt;return{ok:!1,spec:ut,message:yt instanceof Error?yt.message:String(yt)}}):async(ut)=>({ok:!0,item:await Ie(ut)}),q),et=Xe.filter((ut)=>!ut.ok),Re=Xe.filter((ut)=>ut.ok).map((ut)=>ut.item),at=Re.flatMap((ut)=>Rg(ut,ye.rules)),ct=Re.flatMap((ut)=>Pg(ut,ne,ce)),lt=new Set([...at,...ct].map((ut)=>ut.spec)),pt=[...et,...at,...ct],mt=[],gt=Dg(mt,()=>Re.flatMap((ut)=>lt.has(ut.spec)||pt.length>0&&ne.has(ut.spec)?[]:Eg(ut,ce,V,mt)));return{ok:pt.length===0,errors:pt.map((ut)=>`Failed to update ${ut.spec}: ${ut.message}`),entries:Re.map(_g),changes:gt}}catch(ce){return Jn(ce)}}function Rg(P,A){if(!S(P.spec))return[];let q=Pe(P.spec),V=A.filter((ee)=>ee!==P.spec&&Pe(ee).toLowerCase()===q.toLowerCase());if(V.length===0)return[];return[{ok:!1,spec:P.spec,message:`rulebook name "${q}" is also claimed by ${V.join(", ")}; rename one of them`}]}function Pg(P,A,q){if(!A.has(P.spec)||!S(P.spec))return[];let V=O(q.configDir,P.rulebook.name),ee=n(i(q.filesystemScope,V));if(ee===null||ee===P.content)return[];return[{ok:!1,spec:P.spec,message:`${V} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Eg(P,A,q,V){if(!S(P.spec))return[];let ee=O(A.configDir,P.rulebook.name),ne=i(A.filesystemScope,ee),ce=n(ne);if(ce===P.content)return[];return V?.push({target:ne,previous:ce}),g(ne,P.content,void 0,q._testAfterPolicyRename),Ag(P,ce)}function Dg(P,A){try{return A()}catch(q){for(let V of[...P].reverse()){if(V.previous===null){F(V.target);continue}g(V.target,V.previous)}throw q}}function Ag(P,A){if(A===null)return[`Vendored ${P.spec} (${P.rulebook.version})`];let q=me(A),V="problem"in q?null:q.rulebook,ee=new Map(V?.rules.map((ce)=>[ce.name,JSON.stringify(ce)])??[]),ne=new Set(P.rulebook.rules.map((ce)=>ce.name));return[`Updated ${P.spec} (${V?.version??"unreadable"} -> ${P.rulebook.version})`,...[...ne].filter((ce)=>!ee.has(ce)).map((ce)=>` + ${ce}`),...[...ee.keys()].filter((ce)=>!ne.has(ce)).map((ce)=>` - ${ce}`),...P.rulebook.rules.filter((ce)=>{let he=ee.get(ce.name);return he!==void 0&&he!==JSON.stringify(ce)}).map((ce)=>` ~ ${ce.name}`)]}function _g(P){return{spec:P.spec,name:P.rulebook.name,version:P.rulebook.version,ruleCount:P.rulebook.rules.length}}async function cd(P,A,q={}){return Tg(P,A,Ng(q),zt())}async function Tg(P,A,q,V,ee={}){let ne=null,ce=!1;try{let he=Pt(P,q),ye=n(he.configTarget);ne={target:he.configTarget,content:ye};let be=bi(he.configTarget);if(!be.ok)return be.result;let xe=be.config,Ie=K(A);$g(A,q,Ie);let Xe=Ie?await Qc(A,{ref:q.ref,operation:V}):null,et=Xe?Ig(Xe,q.rulebooks):[],Re=Xe?et.map((mt)=>Og(xe.rules,Xe,mt)??`${A}#${Xe.ref}/${mt}`):[A],at=Re.filter((mt)=>!xe.rules.includes(mt)),ct=[...xe.rules,...at];if(ct.length>pe)return jg();if(ct.length!==xe.rules.length)ce=!0,Rt(he.configTarget,{version:1,rules:ct,overrides:xe.overrides??{},transparent_wrappers:xe.transparent_wrappers??[]},void 0,ee._testAfterPolicyRename);let lt=await Vr(P,q,V,ee,new Set(at),new Set(at));if(!lt.ok)zn(he.configTarget,ye);if(!lt.ok||!Xe)return lt;let pt=et.filter((mt,gt)=>at.includes(Re[gt]??""));return{...lt,add:{source:A,ref:Xe.ref,selected:et,added:pt,alreadyConfigured:et.filter((mt)=>!pt.includes(mt)),commits:at.length>0?[Xe.commit]:[]}}}catch(he){if(ce&&ne)try{zn(ne.target,ne.content)}catch(ye){return Jn(ye)}return Jn(he)}}function $g(P,A,q){if(!q&&A.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!q&&A.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${P}`);if(A.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let V=A.rulebooks?.filter((ee)=>!l.test(ee))??[];if(V.length>0)throw Error(`Invalid rulebook names: ${V.join(", ")}`)}function Ig(P,A){let q=A?[...new Set(A)]:P.names,V=q.filter((ee)=>!P.names.includes(ee));if(V.length>0)throw Error(`Rulebooks not found in ${P.source} at ${P.ref}: ${V.join(", ")}
264
- Available rulebooks: ${P.names.join(", ")}`);return q}function Og(P,A,q){let V=`${A.source}#${A.ref}/${q}`;if(P.includes(V))return V;let ee=`${A.source}#${A.commit}/${q}`;return P.find((ne)=>ne===ee)}async function Fg(P,A,q=zt()){if(P.length>pe)throw Error(fe);let V=[],ee=0,ne,ce=Array.from({length:Math.min(P.length,Ur.concurrency)},async()=>{while(!ne){let he=ee;if(he>=P.length)return;ee++;try{V[he]=await A(P[he],he,q.controller.signal)}catch(ye){if(!ne)ne={value:ye},ee=P.length,q.controller.abort(ye);return}}});if(await Promise.all(ce),ne)throw ne.value;return V}function jg(){return{ok:!1,errors:[fe],entries:[]}}function Ci(P){return{cwd:P.cwd,userConfigDir:P.userConfigDir,userConfigPath:P.userConfigPath,projectConfigPath:P.projectConfigPath,global:P.global,only:P.only,refresh:P.refresh}}function Ng(P){return{...Ci(P),ref:P.ref,rulebooks:P.rulebooks}}function Mg(P){return{...Ci(P),deleteSource:P.deleteSource}}async function dd(P,A,q={}){try{return await Hg(P,A,Mg(q),{})}catch(V){return Jn(V)}}async function Hg(P,A,q,V){let ee=Pt(P,q),ne=m(ee.configTarget);if(ne.errors.length>0)return{ok:!1,errors:ne.errors,entries:[]};if(!ne.config)return{ok:!1,errors:[`No config found at ${ee.configPath}`],entries:[]};let ce=id(ne.config.rules,A);if(!ce.ok)return ce.result;let he=q.deleteSource?Ug(ee.configDir,ce.specs,ee.filesystemScope):{ok:!0,dirs:[]};if(!he.ok)return he.result;let ye=n(ee.configTarget);if(ye===null)return Jn(Error("Rules config is unavailable."));try{Rt(ee.configTarget,{version:1,rules:ne.config.rules.filter((Ie)=>!ce.specs.includes(Ie)),overrides:ne.config.overrides??{},transparent_wrappers:ne.config.transparent_wrappers??[]},void 0,V._testAfterPolicyRename)}catch(Ie){throw zn(ee.configTarget,ye),Ie}let be=await Vr(P,q,zt(),V);if(!be.ok)return zn(ee.configTarget,ye),be;let xe=Gg(he.dirs,V,ee.filesystemScope);if(!xe.ok){zn(ee.configTarget,ye);let Ie=await Vr(P,q,zt(),V);if(!Ie.ok)return{ok:!1,errors:[...xe.result.errors,...Ie.errors],entries:Ie.entries};return xe.result}return be}function Ug(P,A,q){let V=A.flatMap((he)=>l.test(he)?[]:["--delete-source can only delete local rulebook sources"]),ee=A.map((he)=>xi(P,he)),ne=V.length>0?[]:ee.flatMap((he)=>ud(he,q)),ce=[...V,...ne];return ce.length>0?{ok:!1,result:{ok:!1,errors:ce,entries:[]}}:{ok:!0,dirs:ee}}function ud(P,A){let q=Cg(P),V=i(A,q),ee=le(V);if(!ee)return[`Local rulebook source directory not found: ${P}`];let ne=ee.find((ce)=>ce.name==="rulebook.json");if(!ne)return[`Local rulebook source directory is missing rulebook.json: ${P}`];if(ne.kind!=="file")throw new r(A.label);if(n(i(A,xi(q,"rulebook.json"))),ee.length>1)return[`Local rulebook source directory contains extra files: ${P}. delete manually if you really want to remove the directory.`];return[]}function Gg(P,A,q){let V=P.flatMap((ee)=>{try{if(!le(i(q,ee)))return[];let ne=ud(ee,q);if(ne.length>0)return ne;return Bg(ee,A,q),[]}catch(ne){return[`Failed to delete local rulebook source ${ee}: ${ne instanceof Error?ne.message:String(ne)}`]}});return V.length>0?{ok:!1,result:{ok:!1,errors:V,entries:[]}}:{ok:!0}}function Bg(P,A,q){if(A._testDeleteLocalSourceDir){A._testDeleteLocalSourceDir(P);return}F(i(q,xi(P,ue))),nt(i(q,P))}function zn(P,A){if(A===null){F(P);return}g(P,A)}function Jn(P){return{ok:!1,errors:[P instanceof Error?P.message:String(P)],entries:[]}}var qg=".safety-net.json",Vg="~/.cc-safety-net/config.json";async function gd(P,A){return[await fd(P,{legacyPath:$s({cwd:A.cwd}),configPath:M(A.cwd),defaultRulebookName:"project-rules",migratedFrom:qg,cleanup:A.cleanup,syncOptions:{cwd:A.cwd}}),await fd(P,{legacyPath:nr(P),configPath:j(P),defaultRulebookName:"user-rules",migratedFrom:Vg,cleanup:A.cleanup,syncOptions:{cwd:A.cwd,global:!0}})].every((V)=>V)?0:1}async function fd(P,A){let q=Pt(P,A.syncOptions),V=i(q.filesystemScope,A.legacyPath),ee=n(V);if(ee===null)return console.log(`No legacy config found at ${A.legacyPath}`),!0;let ne=Jg(ee);if(!ne.ok){for(let et of ne.errors)console.error(et);return!1}let ce=m(q.configTarget);if(ce.errors.length>0){for(let et of ce.errors)console.error(et);return!1}let he=ce.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},ye=Wg(pd(A.configPath),he.rules,A.defaultRulebookName,A.migratedFrom,q.filesystemScope),be=Jr(pd(A.configPath),ye,"rulebook.json"),xe=i(q.filesystemScope,be),Ie=[md(q.configTarget),md(xe)],Xe=await zg(P,A,q.configTarget,xe,ye,ne.config.rules,he.rules.includes(ye)?he.rules:[...he.rules,ye],he.overrides??{},he.transparent_wrappers??[]);if(!Xe.ok){Zg(Ie);for(let et of Xe.errors)console.error(et);return!1}if(!A.cleanup)return console.log(`Migrated legacy config at ${A.legacyPath}. Legacy file is no longer used.`),!0;if(!Yg(q.configTarget,xe,ye,A.migratedFrom,ne.config.rules))return console.error(`Migration cleanup verification failed for ${A.legacyPath}`),!1;return F(V),console.log(`Deleted legacy config at ${A.legacyPath}`),!0}async function zg(P,A,q,V,ee,ne,ce,he,ye){try{return Rt(q,{version:1,rules:ce,overrides:he,transparent_wrappers:ye}),Rt(V,Kg(ee,A.migratedFrom,ne)),await zr(P,A.syncOptions)}catch(be){return{ok:!1,errors:[be instanceof Error?be.message:String(be)]}}}function Jg(P){try{let A=JSON.parse(P),q=ro(A);if(q.errors.length>0)return{ok:!1,errors:q.errors};return{ok:!0,config:{version:1,rules:A.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function Wg(P,A,q,V,ee){let ne=A.find((ce)=>Xg(i(ee,Jr(P,ce,"rulebook.json")))===V);if(ne)return ne;if(n(i(ee,Jr(P,q,"rulebook.json")))===null)return q;for(let ce=2;;ce++){let he=`${q}-${ce}`;if(n(i(ee,Jr(P,he,"rulebook.json")))===null)return he}}function Kg(P,A,q){return{rulebook_version:1,name:P,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:A,allowed_commands:[...new Set(q.map((V)=>V.command))],rules:q,tests:q.map((V)=>({command:[V.command,V.subcommand,V.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:V.name}))}}function Yg(P,A,q,V,ee){if(!m(P).config?.rules.includes(q))return!1;try{let ce=n(A);if(ce===null)return!1;let he=JSON.parse(ce);return he.migrated_from===V&&JSON.stringify(he.rules)===JSON.stringify(ee)}catch{return!1}}function md(P){return{target:P,content:n(P)}}function Zg(P){for(let A of P){if(A.content===null){F(A.target);continue}g(A.target,A.content)}}function Xg(P){let A=n(P);if(A===null)return null;try{let q=JSON.parse(A);return typeof q.migrated_from==="string"?q.migrated_from:null}catch{return null}}import{mkdir as Qg,readFile as eh,writeFile as th}from"node:fs/promises";import{dirname as nh,join as rh}from"node:path";var oh=86400000,ih=604800000;async function yd(P,A=Date.now()){if(P.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let q=je(P);if(!q)return null;let V=rh(q,".cc-safety-net","update-check.json"),ee=await sh(V,A);if(!ee.lastCheck||A-ee.lastCheck>oh){let he=await Wt();if(ee.lastCheck=A,he.latestVersion)ee.latestVersion=he.latestVersion;if(!await hd(V,ee))return null;if(he.error)return null}let ne=ee.latestVersion,ce=wt();if(!ne||!co(ne,ce))return null;if(ee.notifiedVersion===ne&&ee.notifiedAt!==void 0&&A-ee.notifiedAt<ih)return null;if(ee.notifiedVersion=ne,ee.notifiedAt=A,!await hd(V,ee))return null;return`UPDATE_AVAILABLE: cc-safety-net v${ne} is available (running v${ce}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function sh(P,A){let q=await eh(P,"utf8").then((ne)=>JSON.parse(ne)).catch(()=>{return});if(!q||typeof q!=="object"||Array.isArray(q))return{};let V=q,ee=(ne)=>typeof ne==="number"&&Number.isFinite(ne)&&ne<=A?ne:void 0;return{lastCheck:ee(V.lastCheck),latestVersion:typeof V.latestVersion==="string"?V.latestVersion:void 0,notifiedVersion:typeof V.notifiedVersion==="string"?V.notifiedVersion:void 0,notifiedAt:ee(V.notifiedAt)}}async function hd(P,A){return Qg(nh(P),{recursive:!0,mode:448}).then(()=>th(P,JSON.stringify(A),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as ah,resolve as Si}from"node:path";var vd="CC Safety Net Config",lh="═".repeat(vd.length),ch="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",dh=new Set(["rule.json","rule.lock","cache"]);function bd(P,A={}){try{return uh(P,A)}catch(q){if(q instanceof r)return console.error(q.message),1;throw q}}function uh(P,A){let q=A.cwd??process.cwd(),V=J(P,{cwd:q}),ee=nr(P),ne=ns(q),ce=Si(q,de),he=i(V.userScope,ee),ye=i(V.projectScope,ne),be=!1,xe=!1,Ie=[],Xe=[],et=ph(i(V.projectScope,ce));if(mh(),n(V.userConfigTarget)!==null){let Re=Jt(V.userConfigTarget);if(Re.errors.push(...U(V.userConfigPath,V.userScope)),Ie.push({scope:"User",path:V.userConfigPath,result:Re,schema:"rules",target:V.userConfigTarget}),Re.errors.length>0)be=!0}if(n(he)!==null)if(xe=!0,n(V.userConfigTarget)!==null)Xe.push(Wr("user","cleanup"));else{let Re=oo(he);if(Ie.push({scope:"User",path:ee,result:Re,schema:"legacy",inactive:!0,target:he}),Xe.push(Wr("user",Re.errors.length>0?"fix-or-delete":"migrate")),Re.errors.length>0)be=!0}if(n(V.projectConfigTarget)!==null){let Re=Jt(V.projectConfigTarget);if(Re.errors.push(...U(V.projectConfigPath,V.projectScope)),Ie.push({scope:"Project",path:Si(V.projectConfigPath),result:Re,schema:"rules",target:V.projectConfigTarget}),Re.errors.length>0)be=!0;if(n(ye)!==null)xe=!0,Xe.push(Wr("project","cleanup"))}else if(n(ye)!==null){xe=!0,be=!0;let Re=oo(ye);Ie.push({scope:"Project",path:Si(ne),result:Re,schema:"legacy",inactive:!0,target:ye}),Xe.push(Wr("project",Re.errors.length>0?"fix-or-delete":"migrate"))}if(et?.result.errors.length)be=!0;if(Ie.length===0&&!et)return console.log(`
265
- No config files found. Using built-in rules only.`),0;for(let Re of Ie)if(Re.inactive)hh(Re.scope,Re.path,Re.result);else if(Re.result.errors.length>0)yh(Re.scope,Re.path,Re.result.errors);else{if(Re.schema==="rules"&&Lh(Re.target))console.log(`
266
- Added $schema to ${Re.scope.toLowerCase()} config.`);gh(Re.scope,Re.path,Re.result,Re.schema)}for(let Re of Xe)console.error(`
267
- ${dt.red(Re)}`);if(et)if(et.result.errors.length>0)bh(et.path,et.result.errors);else vh(et.path,et.result);if(be)return console.error(`
271
+ Check that every parent path component is a directory.`;return A}import{mkdirSync as Sg}from"node:fs";import{dirname as Rg}from"node:path";import{createInterface as Pg}from"node:readline";import{existsSync as Mc,readFileSync as Lg}from"node:fs";function un(P,A){let q=Ye(P,A);return{policy:q.policy,errors:ie(qe(q.issues,Je,(V)=>V.kind==="custom")," "," ")}}function Yn(P,A){return un(P,A).errors}function jc(P,A){return{"safety.level":P.safety.level,...Ci("safety.overrides",P.safety.overrides),"workflow.worktree_mode":String(P.workflow.worktree_mode),"destructive_command_protection.enabled":String(P.destructive_command_protection.enabled),...Ci("destructive_command_protection.overrides",P.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":Si(P.destructive_command_protection.allow_paths),"secret_protection.enabled":String(P.secret_protection.enabled),...Ci("secret_protection.overrides",P.secret_protection.overrides),"secret_protection.deny_paths":Si(P.secret_protection.deny_paths),"secret_protection.allow_paths":Si(P.secret_protection.allow_paths),...A?{"audit.retention_days":String(P.audit.retention_days)}:{}}}function qr(P,A,q){let V=jc(P,q),ee=jc(A,q);return[...new Set([...Object.keys(V),...Object.keys(ee)])].flatMap((ne)=>V[ne]===ee[ne]?[]:[{field:ne,before:V[ne],after:ee[ne]}])}function Xn(P,A){let q=u(P,A);if(!Mc(q))return{baseline:C(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,P.home),diagnostics:[]};let V=pn(q),ee=un(V.value,P.home);return{baseline:ee.policy,diagnostics:V.errors.length>0?V.errors:ee.errors}}function pn(P){if(!Mc(P))return{errors:[`${P}: file not found`]};try{return{value:JSON.parse(Lg(P,"utf-8")),errors:[]}}catch(A){let q=A instanceof Error?A.message:String(A);return{errors:[`${P}: ${A instanceof SyntaxError?`Invalid JSON: ${q}`:q}`]}}}function Vr(P,A){let q=wg(P)?P:{};return{version:A.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((V)=>q[V]!==void 0).map((V)=>[V,q[V]]))}}function Ci(P,A){return Object.fromEntries(Object.entries(A).flatMap(([q,V])=>V===void 0?[]:[[`${P}.${q}`,String(V)]]))}function Si(P){return P.length===0?"(none)":P.join(", ")}function wg(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{chmodSync as kg,existsSync as Hc,mkdirSync as xg,readFileSync as Uc}from"node:fs";import{dirname as Cg}from"node:path";function Gc(P,A={}){let q=u(P,A);if(!Hc(q))return{path:q,exists:!1,raw:"",policy:W(),errors:[]};let V=Uc(q,"utf-8");if(!V.trim())return{path:q,exists:!0,raw:V,policy:W(),errors:["Config file is empty"]};try{let ee=un(JSON.parse(V),P.home);return{path:q,exists:!0,raw:V,policy:ee.policy,errors:ee.errors}}catch(ee){return{path:q,exists:!0,raw:V,policy:W(),errors:[`Invalid JSON: ${ee instanceof Error?ee.message:String(ee)}`]}}}function Vt(P,A,q={}){let V=u(P,q),ee=un(A,P.home);if(ee.errors.length>0)return{path:V,policy:W(),errors:ee.errors};let ne=ee.policy;return xg(Cg(V),{recursive:!0,mode:448}),g(re(V),`${JSON.stringify(ne,null,2)}
272
+ `,384),kg(V,384),{path:V,policy:ne,errors:[]}}function Bc(P,A){let q=un(A,P.home);if(q.errors.length>0)return{errors:q.errors};return{preview:Ae(q.policy,P.env),errors:[]}}function qc(P,A={}){let q=u(P,A);if(!Hc(q))return Vt(P,X,A);let V=Uc(q,"utf-8");if(!V.trim())return Vt(P,X,A);try{return Vt(P,C(JSON.parse(V),P.home),A)}catch{return Vt(P,X,A)}}var Vc=new Set(["check","apply"]),zc="(unset)";async function Wc(P,A,q={}){let V=xt({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},A),ee=V.positionals[0],ne=[...V.errors,...ee&&!Vc.has(ee)?[`Unknown policy subcommand: ${ee}`]:[],...ee&&Vc.has(ee)&&!V.positionals[1]?[`policy ${ee} requires a file`]:[],...V.positionals.slice(2).map((Re)=>`Unexpected policy argument: ${Re}`)];if(ne.length>0){for(let Re of ne)console.error(Re);return 1}let ce=V.positionals[1];if(!ee||!ce)return Cn(or,console.error),1;let he=V.flags.global?u(P):b(q.cwd??process.cwd()),ye=pn(ce),be=[...ye.errors,...Yn(ye.value,P.home).map((Re)=>`${ce}: ${Re}`),...!V.flags.global&&Ag(ye.value)&&ye.value.audit!==void 0?[`${ce}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(be.length>0){for(let Re of be)console.error(Re);return 1}let xe=C(ye.value,P.home);if(console.log(`Scope: ${V.flags.global?"user":"project"} (${he})`),console.log(`Proposal: ${ce}`),V.flags.global)Jc(C(pn(he).value,P.home),xe,!0);if(!V.flags.global){let Re=Xn(P).baseline;console.log("Effective policy (user + project merged):"),Jc(Z(Re,ae(pn(he).value,P.home).policy).policy,Z(Re,ae(ye.value,P.home).policy).policy,!1)}if(ee==="check")return 0;let Ie=q.input??process.stdin,Xe=q.output??process.stdout;if(!Ie.isTTY||!Xe.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${ce}${V.flags.global?" --global":""}`),1;if(!await Eg(`Apply this policy to ${he}? [y/N] `,Ie,Xe))return console.log("Cancelled; nothing was written."),0;return Dg(P,he,ye.value,xe,V.flags.global),console.log(`Policy applied: ${he}`),0}function Eg(P,A,q){let V=Pg({input:A,output:q,terminal:!1});return new Promise((ee)=>{V.once("close",()=>ee(!1)),V.question(P,(ne)=>{ee(/^y(es)?$/i.test(ne.trim())),V.close()})})}function Dg(P,A,q,V,ee){if(ee){Vt(P,V);return}Sg(Rg(A),{recursive:!0}),Pt(A,Vr(q,V))}function Jc(P,A,q){let V=qr(P,A,q);if(V.length===0){console.log("No changes.");return}console.log(`Changes (${V.length}):`);for(let ee of V)console.log(` ${ee.field}: ${ee.before??zc} -> ${ee.after??zc}`)}function Ag(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{join as Bh}from"node:path";var Kc="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- Transparent wrappers have no built-in defaults. Configure only wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function zr(P,A){if(!P.ok){ed(P);return}Zc(P,A)}function Xc(P,A,q){if(P.ok)console.log(q);if(!P.add){zr(P,`Added rulebook source: ${A}`);return}if(!P.ok){ed(P);return}if(P.add.added.length>0)console.log(`Added ${P.add.added.length} ${P.add.added.length===1?"rulebook":"rulebooks"} from ${P.add.source} at ${P.add.ref}:`),P.add.added.forEach((V)=>{console.log(` - ${V}`)});if(P.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${P.add.source} at ${P.add.ref}: ${P.add.alreadyConfigured.join(", ")}`);if(P.add.commits.length>0)console.log(`Vendored at ${P.add.commits.map((V)=>V.slice(0,7)).join(", ")}.`);Zc(P,"Rule config updated.")}function Zc(P,A){for(let q of P.changes??[])console.log(q);console.log(A),console.log(""),_g(P.entries)}function _g(P){if(P.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${P.length}):`);for(let A of P)console.log(` - ${A.name} ${A.version} (${Tg(A.ruleCount)})`),console.log(` Source: ${A.spec}`)}function Tg(P){return`${P} ${P===1?"rule":"rules"}`}function Qc(P){fn("Active sources",P.rulebooks,(A)=>[`[${A.source}] ${A.name} ${A.version}`,` Source: ${A.spec}`]),fn("Active rules",P.rules,(A)=>[`[${$g(P,A.name)}] ${A.name}`,...Ig(A),` Reason: ${A.reason}`]),fn("Disabled rules",Yc(P,"off"),(A)=>[A.key]),fn("Reason overrides",Yc(P,"reason"),(A)=>[A.key,` Reason: ${A.value.reason}`]),fn("Transparent wrappers",P.transparent_wrappers,(A)=>[A]),fn("Issues",P.errors,(A)=>[A]),fn("Warnings",P.warnings,(A)=>[A])}function fn(P,A,q){if(A.length===0){console.log(`${P}: (none)`);return}console.log(`${P} (${A.length}):`);for(let V of A){let[ee,...ne]=q(V);console.log(` - ${ee}`);for(let ce of ne)console.log(` ${ce}`)}}function Ig(P){if(!P.match)return[` Command: ${P.subcommand?`${P.command} ${P.subcommand}`:P.command}`,` Block args: ${P.block_args.join(", ")}`];return[` Command: ${[P.command,...P.match.command_path].join(" ")}`,...P.match.any_args?[` Any args: ${P.match.any_args.join(", ")}`]:[],...P.match.exclude_args?[` Exclude args: ${P.match.exclude_args.join(", ")}`]:[]]}function $g(P,A){return P.rulebooks.find((q)=>q.rules.includes(A))?.source??"project"}function Yc(P,A){return Object.entries({...P.userConfig?.overrides,...P.projectConfig?.overrides}).filter((q)=>{if(A==="off")return q[1]==="off";return!!q[1]&&typeof q[1]==="object"}).map(([q,V])=>({key:q,value:V}))}function ed(P){for(let A of P.errors)console.error(A)}import{dirname as xd,join as eo}from"node:path";import{join as Ai,resolve as zg}from"node:path";function Ri(P){let A=m(P);if(A.errors.length>0)return{ok:!1,result:{ok:!1,errors:A.errors,entries:[]}};return{ok:!0,config:A.config??it}}function td(P){Pt(P,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function nd(P){Pt(P,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Yr}from"node:path";var Og="custom.";function Jr(P){if(P.rulebook_version!==2)return[];let A=P.rules.map((q)=>({name:q.name,command:q.command,block_args:[],match:q.match,reason:q.reason,intent:q.intent}));return(P.tests??[]).flatMap((q,V)=>{let ee=Pi(h(q.command));if(ee.length===0)return[`tests[${V}]: could not parse fixture command: ${q.command}`];let ne=ee.reduce((ce,he)=>ce??_(he,A)?.id.slice(Og.length),void 0);if(q.expect==="blocked"){if(ne===q.rule)return[];let ce=ne?`"${ne}" matched first`:"no rule matched";return[`tests[${V}]: expected "${q.rule}" to block "${q.command}" but ${ce}`]}return ne?[`tests[${V}]: expected "${q.command}" to be allowed but "${ne}" matched`]:[]})}function Pi(P){return P.nodes.flatMap((A)=>{if(A.kind==="group"||A.kind==="function")return Pi(A.body);if(A.kind!=="command")return[];let q=ge(Q(A.dialect,A.words)).words.map(t);return[...q.length>0?[q]:[],...A.nested.flatMap((V)=>Pi(V))]})}var Wr=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Kr(P={}){return{requests:0,responseBytes:0,maxRequests:P.maxRequests??Wr.maxRequests,maxResponseBytes:P.maxResponseBytes??Wr.maxResponseBytes}}function zt(P){return{controller:new AbortController,budget:Kr(),resolveUrl:P}}function rd(P){return P instanceof Error&&P.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function od(P){if(P.requests>=P.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.requests++}function id(P,A){if(A>P.maxResponseBytes-P.responseBytes)throw P.responseBytes+=A,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.responseBytes+=A}var ld=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function sd(P,A,q=v(Yr(Yr(A)),"rules policy"),V=zt()){if(S(P))return Mg(P,V);return jg(P,A,q)}async function cd(P,A,q,V,ee,ne){if(!S(P))return sd(P,A,q,V);let ce=ee?null:Fg(P,A,q);if(ce)return ce;if(!ee&&!ne)throw Error(`${P} is not vendored; run rule update ${P} to vendor it`);return sd(P,A,q,V)}function Fg(P,A,q=v(Yr(Yr(A)),"rules policy")){let V=I(P),ee=O(A,V.name),ne=n(i(q,ee));if(ne===null)return null;let ce=se(Ei(ne,`Invalid rulebook ${ee}.`));if(ce.name!==V.name)throw Error(`rulebook name "${ce.name}" in ${ee} must match "${V.name}"`);return{spec:P,rulebook:ce,content:ne}}async function dd(P,A={}){if(!K(P))throw Error(`Invalid GitHub repository source: ${P}`);let[q,V]=P.split("/");if(!q||!V)throw Error(`Invalid GitHub repository source: ${P}`);if(A.ref!==void 0&&!oe(A.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${A.ref}`);let ee=A.operation??zt(),ne=A.ref??await Ng(q,V,P,ee),ce=await pd(q,V,ne,P,ee),he=await Xr(`https://api.github.com/repos/${q}/${V}/git/trees/${ce}?recursive=1`,"tree",ee),ye=he.response;if(!ye.ok)throw Error(`Failed to inspect ${P}: GitHub tree returned ${ye.status}`);let be=JSON.parse(he.content);if(!Array.isArray(be?.tree))throw Error(`Failed to inspect ${P}: unexpected GitHub tree response`);let xe=be.tree,Ie=[...new Set(xe.flatMap((Xe)=>{if(!Xe||typeof Xe!=="object")return[];let et=Xe;if(et.type!=="blob"||typeof et.path!=="string")return[];let Re=et.path.match(rt);return Re?.[1]?[Re[1]]:[]}))].sort();if(Ie.length===0)throw Error(`No rulebooks found in ${P} under ${de}/`);return{source:P,owner:q,repo:V,ref:ne,commit:ce,names:Ie}}async function Ng(P,A,q,V){let ee=await Xr(`https://api.github.com/repos/${P}/${A}`,"metadata",V),ne=ee.response;if(!ne.ok)throw Error(`Failed to inspect ${q}: GitHub returned ${ne.status}`);let he=JSON.parse(ee.content)?.default_branch;if(typeof he!=="string"||he==="")throw Error(`Failed to inspect ${q}: missing default branch`);if(!oe(he))throw Error(`GitHub returned an invalid default branch: ${he}`);return he}function jg(P,A,q){ot(P);let V=O(A,P),ee=n(i(q,V));if(ee===null)throw Error(`Rulebook source not found: ${P}`);let ne=ud(Ei(ee,"Invalid local rulebook source."));if(ne.name!==P)throw Error(`rulebook name "${ne.name}" must match local source "${P}"`);return{spec:P,rulebook:ne,content:ee}}async function Mg(P,A){let q=I(P),V=await pd(q.owner,q.repo,q.ref,P,A),ee=await Xr(`https://raw.githubusercontent.com/${q.owner}/${q.repo}/${V}/${q.path}`,"raw",A),ne=ee.response;if(!ne.ok)throw Error(`Failed to fetch ${P}: GitHub raw returned ${ne.status}`);let ce=ee.content,he=ud(Ei(ce,"Invalid GitHub rulebook response."));if(he.name!==q.name)throw Error(`rulebook name "${he.name}" must match GitHub source "${q.name}"`);return{spec:P,rulebook:he,content:ce}}function ud(P){let A=se(P),q=Jr(A);if(q.length>0)throw Error(q.join("; "));return A}function Ei(P,A){try{return JSON.parse(P)}catch{throw Error(A)}}async function pd(P,A,q,V,ee){let ne=await Xr(`https://api.github.com/repos/${P}/${A}/commits/${encodeURIComponent(q)}`,"commit",ee),ce=ne.response;if(!ce.ok)throw Error(`Failed to resolve ${V}: GitHub returned ${ce.status}`);let he=JSON.parse(ne.content);if(typeof he?.sha!=="string"||he.sha==="")throw Error(`Failed to resolve commit for ${V}`);return he.sha}async function Hg(P,A,q={}){if(q.signal?.aborted)throw q.signal.reason;let V=q.budget??Kr(),ee=new AbortController,ne=()=>ee.abort(q.signal?.reason);q.signal?.addEventListener("abort",ne,{once:!0});let ce=!1,he=setTimeout(()=>{if(ee.signal.aborted)return;ce=!0,ee.abort()},q.timeoutMs??ld.timeoutMs);try{if(q.signal?.aborted)throw q.signal.reason;od(V);let ye=await fetch(P,{signal:ee.signal,redirect:"error"});if(!ye.ok)return fd(ye),{response:ye,content:""};return{response:ye,content:await Ug(ye,A,V,()=>ee.abort())}}catch(ye){if(ce)throw Error("GitHub request timed out",{cause:ye});if(q.signal?.aborted)throw q.signal.reason;throw ye}finally{clearTimeout(he),q.signal?.removeEventListener("abort",ne)}}function Xr(P,A,q){return Hg(q.resolveUrl?.(P)??P,A,{budget:q.budget,signal:q.controller.signal})}async function Ug(P,A,q=Kr(),V){let ee=ld[`${A}Bytes`],ne=Number(P.headers.get("content-length"));if(Number.isFinite(ne)&&ne>ee)throw fd(P),Error(`GitHub ${A} response exceeds ${ee} bytes`);if(!P.body)return"";let ce=P.body.getReader(),he=[],ye=0;while(!0){let be=await ce.read();if(be.done)break;try{id(q,be.value.byteLength)}catch(xe){throw V?.(),ad(ce),xe}if(ye+=be.value.byteLength,ye>ee)throw V?.(),ad(ce),Error(`GitHub ${A} response exceeds ${ee} bytes`);he.push(Buffer.from(be.value))}return Buffer.concat(he,ye).toString("utf-8")}function fd(P){if(!P.body)return;md(()=>P.body?.cancel())}function ad(P){md(()=>P.cancel())}function md(P){try{Promise.resolve(P()).catch(()=>{})}catch{}}var Gg=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function gd(P,A){let q=vd(P.rules,A);if(q.length>0)return{ok:!0,specs:q};return yd(P.rules,A)}function hd(P,A){let q=vd(P,A);if(q.length>0)return{ok:!0,specs:q};let V=qg(P,A);if(V.length>0)return{ok:!0,specs:V};let ee=Vg(P,A);if(!ee.ok)return ee;if(ee.specs.length>0)return{ok:!0,specs:ee.specs};return yd(P,A)}function yd(P,A){let q=P.filter((V)=>Di(V)?.name===A);if(q.length===1)return{ok:!0,specs:q};return Bg(A,q)}function Bg(P,A){return{ok:!1,result:{ok:!1,errors:A.length===0?[`No configured rulebook matches ${P}`]:[`Ambiguous rulebook match ${P}: ${A.join(", ")}`],entries:[]}}}function vd(P,A){return P.filter((q)=>q===A)}function qg(P,A){let q=A.match(Gg),V=q?.[1],ee=q?.[2],ne=q?.[3];if(!V||!ee||!ne||!oe(ne))return[];return bd(P,(ce)=>ce.owner===V&&ce.repo===ee&&ce.ref===ne)}function Vg(P,A){if(!K(A))return{ok:!0,specs:[]};let[q,V]=A.split("/"),ee=bd(P,(ce)=>ce.owner===q&&ce.repo===V);if(new Set(ee.map((ce)=>Di(ce)?.ref).filter((ce)=>!!ce)).size<2)return{ok:!0,specs:ee};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${A}. Use an explicit ref:`,` cc-safety-net rule remove ${A}#<ref>`],entries:[]}}}function Di(P){try{return I(P)}catch{return null}}function bd(P,A){return P.filter((q)=>{let V=Di(q);return V?A(V):!1})}async function Qr(P,A={}){let q=_i(A);return Jg(P,q,await Zr(P,q,zt()))}function Jg(P,A,q){if(!q.ok)return q;let V=Et(P,A),ee=[...new Set(U(V.configPath,V.filesystemScope))];if(ee.length===0)return q;return{ok:!1,errors:ee,entries:q.entries}}async function Zr(P,A,q,V={},ee=new Set,ne=new Set){try{let ce=Et(P,A),he=Ri(ce.configTarget);if(!he.ok)return he.result;let ye=he.config,be=A.only?gd(ye,A.only):{ok:!0,specs:ye.rules};if(!be.ok)return be.result;let xe=new Set([...A.refresh?be.specs:[],...ee]),Ie=(ut)=>cd(ut,ce.configDir,ce.filesystemScope,q,xe.has(ut),!A.refresh||xe.has(ut)),Xe=await oh(ye.rules,A.refresh?(ut)=>Ie(ut).then((vt)=>({ok:!0,item:vt})).catch((vt)=>{if(rd(vt))throw vt;return{ok:!1,spec:ut,message:vt instanceof Error?vt.message:String(vt)}}):async(ut)=>({ok:!0,item:await Ie(ut)}),q),et=Xe.filter((ut)=>!ut.ok),Re=Xe.filter((ut)=>ut.ok).map((ut)=>ut.item),at=Re.flatMap((ut)=>Wg(ut,ye.rules)),ct=Re.flatMap((ut)=>Kg(ut,ne,ce)),lt=new Set([...at,...ct].map((ut)=>ut.spec)),ft=[...et,...at,...ct],mt=[],gt=Xg(mt,()=>Re.flatMap((ut)=>lt.has(ut.spec)||ft.length>0&&ne.has(ut.spec)?[]:Yg(ut,ce,V,mt)));return{ok:ft.length===0,errors:ft.map((ut)=>`Failed to update ${ut.spec}: ${ut.message}`),entries:Re.map(Qg),changes:gt}}catch(ce){return Qn(ce)}}function Wg(P,A){if(!S(P.spec))return[];let q=Pe(P.spec),V=A.filter((ee)=>ee!==P.spec&&Pe(ee).toLowerCase()===q.toLowerCase());if(V.length===0)return[];return[{ok:!1,spec:P.spec,message:`rulebook name "${q}" is also claimed by ${V.join(", ")}; rename one of them`}]}function Kg(P,A,q){if(!A.has(P.spec)||!S(P.spec))return[];let V=O(q.configDir,P.rulebook.name),ee=n(i(q.filesystemScope,V));if(ee===null||ee===P.content)return[];return[{ok:!1,spec:P.spec,message:`${V} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Yg(P,A,q,V){if(!S(P.spec))return[];let ee=O(A.configDir,P.rulebook.name),ne=i(A.filesystemScope,ee),ce=n(ne);if(ce===P.content)return[];return V?.push({target:ne,previous:ce}),g(ne,P.content,void 0,q._testAfterPolicyRename),Zg(P,ce)}function Xg(P,A){try{return A()}catch(q){for(let V of[...P].reverse()){if(V.previous===null){F(V.target);continue}g(V.target,V.previous)}throw q}}function Zg(P,A){if(A===null)return[`Vendored ${P.spec} (${P.rulebook.version})`];let q=me(A),V="problem"in q?null:q.rulebook,ee=new Map(V?.rules.map((ce)=>[ce.name,JSON.stringify(ce)])??[]),ne=new Set(P.rulebook.rules.map((ce)=>ce.name));return[`Updated ${P.spec} (${V?.version??"unreadable"} -> ${P.rulebook.version})`,...[...ne].filter((ce)=>!ee.has(ce)).map((ce)=>` + ${ce}`),...[...ee.keys()].filter((ce)=>!ne.has(ce)).map((ce)=>` - ${ce}`),...P.rulebook.rules.filter((ce)=>{let he=ee.get(ce.name);return he!==void 0&&he!==JSON.stringify(ce)}).map((ce)=>` ~ ${ce.name}`)]}function Qg(P){return{spec:P.spec,name:P.rulebook.name,version:P.rulebook.version,ruleCount:P.rulebook.rules.length}}async function Ld(P,A,q={}){return eh(P,A,sh(q),zt())}async function eh(P,A,q,V,ee={}){let ne=null,ce=!1;try{let he=Et(P,q),ye=n(he.configTarget);ne={target:he.configTarget,content:ye};let be=Ri(he.configTarget);if(!be.ok)return be.result;let xe=be.config,Ie=K(A);th(A,q,Ie);let Xe=Ie?await dd(A,{ref:q.ref,operation:V}):null,et=Xe?nh(Xe,q.rulebooks):[],Re=Xe?et.map((mt)=>rh(xe.rules,Xe,mt)??`${A}#${Xe.ref}/${mt}`):[A],at=Re.filter((mt)=>!xe.rules.includes(mt)),ct=[...xe.rules,...at];if(ct.length>pe)return ih();if(ct.length!==xe.rules.length)ce=!0,Pt(he.configTarget,{version:1,rules:ct,overrides:xe.overrides??{},transparent_wrappers:xe.transparent_wrappers??[]},void 0,ee._testAfterPolicyRename);let lt=await Zr(P,q,V,ee,new Set(at),new Set(at));if(!lt.ok)Zn(he.configTarget,ye);if(!lt.ok||!Xe)return lt;let ft=et.filter((mt,gt)=>at.includes(Re[gt]??""));return{...lt,add:{source:A,ref:Xe.ref,selected:et,added:ft,alreadyConfigured:et.filter((mt)=>!ft.includes(mt)),commits:at.length>0?[Xe.commit]:[]}}}catch(he){if(ce&&ne)try{Zn(ne.target,ne.content)}catch(ye){return Qn(ye)}return Qn(he)}}function th(P,A,q){if(!q&&A.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!q&&A.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${P}`);if(A.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let V=A.rulebooks?.filter((ee)=>!l.test(ee))??[];if(V.length>0)throw Error(`Invalid rulebook names: ${V.join(", ")}`)}function nh(P,A){let q=A?[...new Set(A)]:P.names,V=q.filter((ee)=>!P.names.includes(ee));if(V.length>0)throw Error(`Rulebooks not found in ${P.source} at ${P.ref}: ${V.join(", ")}
273
+ Available rulebooks: ${P.names.join(", ")}`);return q}function rh(P,A,q){let V=`${A.source}#${A.ref}/${q}`;if(P.includes(V))return V;let ee=`${A.source}#${A.commit}/${q}`;return P.find((ne)=>ne===ee)}async function oh(P,A,q=zt()){if(P.length>pe)throw Error(fe);let V=[],ee=0,ne,ce=Array.from({length:Math.min(P.length,Wr.concurrency)},async()=>{while(!ne){let he=ee;if(he>=P.length)return;ee++;try{V[he]=await A(P[he],he,q.controller.signal)}catch(ye){if(!ne)ne={value:ye},ee=P.length,q.controller.abort(ye);return}}});if(await Promise.all(ce),ne)throw ne.value;return V}function ih(){return{ok:!1,errors:[fe],entries:[]}}function _i(P){return{cwd:P.cwd,userConfigDir:P.userConfigDir,userConfigPath:P.userConfigPath,projectConfigPath:P.projectConfigPath,global:P.global,only:P.only,refresh:P.refresh}}function sh(P){return{..._i(P),ref:P.ref,rulebooks:P.rulebooks}}function ah(P){return{..._i(P),deleteSource:P.deleteSource}}async function wd(P,A,q={}){try{return await lh(P,A,ah(q),{})}catch(V){return Qn(V)}}async function lh(P,A,q,V){let ee=Et(P,q),ne=m(ee.configTarget);if(ne.errors.length>0)return{ok:!1,errors:ne.errors,entries:[]};if(!ne.config)return{ok:!1,errors:[`No config found at ${ee.configPath}`],entries:[]};let ce=hd(ne.config.rules,A);if(!ce.ok)return ce.result;let he=q.deleteSource?ch(ee.configDir,ce.specs,ee.filesystemScope):{ok:!0,dirs:[]};if(!he.ok)return he.result;let ye=n(ee.configTarget);if(ye===null)return Qn(Error("Rules config is unavailable."));try{Pt(ee.configTarget,{version:1,rules:ne.config.rules.filter((Ie)=>!ce.specs.includes(Ie)),overrides:ne.config.overrides??{},transparent_wrappers:ne.config.transparent_wrappers??[]},void 0,V._testAfterPolicyRename)}catch(Ie){throw Zn(ee.configTarget,ye),Ie}let be=await Zr(P,q,zt(),V);if(!be.ok)return Zn(ee.configTarget,ye),be;let xe=dh(he.dirs,V,ee.filesystemScope);if(!xe.ok){Zn(ee.configTarget,ye);let Ie=await Zr(P,q,zt(),V);if(!Ie.ok)return{ok:!1,errors:[...xe.result.errors,...Ie.errors],entries:Ie.entries};return xe.result}return be}function ch(P,A,q){let V=A.flatMap((he)=>l.test(he)?[]:["--delete-source can only delete local rulebook sources"]),ee=A.map((he)=>Ai(P,he)),ne=V.length>0?[]:ee.flatMap((he)=>kd(he,q)),ce=[...V,...ne];return ce.length>0?{ok:!1,result:{ok:!1,errors:ce,entries:[]}}:{ok:!0,dirs:ee}}function kd(P,A){let q=zg(P),V=i(A,q),ee=le(V);if(!ee)return[`Local rulebook source directory not found: ${P}`];let ne=ee.find((ce)=>ce.name==="rulebook.json");if(!ne)return[`Local rulebook source directory is missing rulebook.json: ${P}`];if(ne.kind!=="file")throw new r(A.label);if(n(i(A,Ai(q,"rulebook.json"))),ee.length>1)return[`Local rulebook source directory contains extra files: ${P}. delete manually if you really want to remove the directory.`];return[]}function dh(P,A,q){let V=P.flatMap((ee)=>{try{if(!le(i(q,ee)))return[];let ne=kd(ee,q);if(ne.length>0)return ne;return uh(ee,A,q),[]}catch(ne){return[`Failed to delete local rulebook source ${ee}: ${ne instanceof Error?ne.message:String(ne)}`]}});return V.length>0?{ok:!1,result:{ok:!1,errors:V,entries:[]}}:{ok:!0}}function uh(P,A,q){if(A._testDeleteLocalSourceDir){A._testDeleteLocalSourceDir(P);return}F(i(q,Ai(P,ue))),nt(i(q,P))}function Zn(P,A){if(A===null){F(P);return}g(P,A)}function Qn(P){return{ok:!1,errors:[P instanceof Error?P.message:String(P)],entries:[]}}var ph=".safety-net.json",fh="~/.cc-safety-net/config.json";async function Rd(P,A){return[await Cd(P,{legacyPath:Hs({cwd:A.cwd}),configPath:M(A.cwd),defaultRulebookName:"project-rules",migratedFrom:ph,cleanup:A.cleanup,syncOptions:{cwd:A.cwd}}),await Cd(P,{legacyPath:lr(P),configPath:j(P),defaultRulebookName:"user-rules",migratedFrom:fh,cleanup:A.cleanup,syncOptions:{cwd:A.cwd,global:!0}})].every((V)=>V)?0:1}async function Cd(P,A){let q=Et(P,A.syncOptions),V=i(q.filesystemScope,A.legacyPath),ee=n(V);if(ee===null)return console.log(`No legacy config found at ${A.legacyPath}`),!0;let ne=gh(ee);if(!ne.ok){for(let et of ne.errors)console.error(et);return!1}let ce=m(q.configTarget);if(ce.errors.length>0){for(let et of ce.errors)console.error(et);return!1}let he=ce.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},ye=hh(xd(A.configPath),he.rules,A.defaultRulebookName,A.migratedFrom,q.filesystemScope),be=eo(xd(A.configPath),ye,"rulebook.json"),xe=i(q.filesystemScope,be),Ie=[Sd(q.configTarget),Sd(xe)],Xe=await mh(P,A,q.configTarget,xe,ye,ne.config.rules,he.rules.includes(ye)?he.rules:[...he.rules,ye],he.overrides??{},he.transparent_wrappers??[]);if(!Xe.ok){bh(Ie);for(let et of Xe.errors)console.error(et);return!1}if(!A.cleanup)return console.log(`Migrated legacy config at ${A.legacyPath}. Legacy file is no longer used.`),!0;if(!vh(q.configTarget,xe,ye,A.migratedFrom,ne.config.rules))return console.error(`Migration cleanup verification failed for ${A.legacyPath}`),!1;return F(V),console.log(`Deleted legacy config at ${A.legacyPath}`),!0}async function mh(P,A,q,V,ee,ne,ce,he,ye){try{return Pt(q,{version:1,rules:ce,overrides:he,transparent_wrappers:ye}),Pt(V,yh(ee,A.migratedFrom,ne)),await Qr(P,A.syncOptions)}catch(be){return{ok:!1,errors:[be instanceof Error?be.message:String(be)]}}}function gh(P){try{let A=JSON.parse(P),q=uo(A);if(q.errors.length>0)return{ok:!1,errors:q.errors};return{ok:!0,config:{version:1,rules:A.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function hh(P,A,q,V,ee){let ne=A.find((ce)=>Lh(i(ee,eo(P,ce,"rulebook.json")))===V);if(ne)return ne;if(n(i(ee,eo(P,q,"rulebook.json")))===null)return q;for(let ce=2;;ce++){let he=`${q}-${ce}`;if(n(i(ee,eo(P,he,"rulebook.json")))===null)return he}}function yh(P,A,q){return{rulebook_version:1,name:P,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:A,allowed_commands:[...new Set(q.map((V)=>V.command))],rules:q,tests:q.map((V)=>({command:[V.command,V.subcommand,V.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:V.name}))}}function vh(P,A,q,V,ee){if(!m(P).config?.rules.includes(q))return!1;try{let ce=n(A);if(ce===null)return!1;let he=JSON.parse(ce);return he.migrated_from===V&&JSON.stringify(he.rules)===JSON.stringify(ee)}catch{return!1}}function Sd(P){return{target:P,content:n(P)}}function bh(P){for(let A of P){if(A.content===null){F(A.target);continue}g(A.target,A.content)}}function Lh(P){let A=n(P);if(A===null)return null;try{let q=JSON.parse(A);return typeof q.migrated_from==="string"?q.migrated_from:null}catch{return null}}import{mkdir as wh,readFile as kh,writeFile as xh}from"node:fs/promises";import{dirname as Ch,join as Sh}from"node:path";var Rh=86400000,Ph=604800000;async function Ed(P,A=Date.now()){if(P.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let q=je(P);if(!q)return null;let V=Sh(q,".cc-safety-net","update-check.json"),ee=await Eh(V,A);if(!ee.lastCheck||A-ee.lastCheck>Rh){let he=await Wt();if(ee.lastCheck=A,he.latestVersion)ee.latestVersion=he.latestVersion;if(!await Pd(V,ee))return null;if(he.error)return null}let ne=ee.latestVersion,ce=wt();if(!ne||!yo(ne,ce))return null;if(ee.notifiedVersion===ne&&ee.notifiedAt!==void 0&&A-ee.notifiedAt<Ph)return null;if(ee.notifiedVersion=ne,ee.notifiedAt=A,!await Pd(V,ee))return null;return`UPDATE_AVAILABLE: cc-safety-net v${ne} is available (running v${ce}). Ask the user once whether to run \`npx -y cc-safety-net@latest update\`; continue the current task either way and do not raise this again.`}async function Eh(P,A){let q=await kh(P,"utf8").then((ne)=>JSON.parse(ne)).catch(()=>{return});if(!q||typeof q!=="object"||Array.isArray(q))return{};let V=q,ee=(ne)=>typeof ne==="number"&&Number.isFinite(ne)&&ne<=A?ne:void 0;return{lastCheck:ee(V.lastCheck),latestVersion:typeof V.latestVersion==="string"?V.latestVersion:void 0,notifiedVersion:typeof V.notifiedVersion==="string"?V.notifiedVersion:void 0,notifiedAt:ee(V.notifiedAt)}}async function Pd(P,A){return wh(Ch(P),{recursive:!0,mode:448}).then(()=>xh(P,JSON.stringify(A),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as Dh,resolve as Ti}from"node:path";var Dd="CC Safety Net Config",Ah="═".repeat(Dd.length),_h="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Th=new Set(["rule.json","rule.lock","cache"]);function Ad(P,A={}){try{return Ih(P,A)}catch(q){if(q instanceof r)return console.error(q.message),1;throw q}}function Ih(P,A){let q=A.cwd??process.cwd(),V=J(P,{cwd:q}),ee=lr(P),ne=cs(q),ce=Ti(q,de),he=i(V.userScope,ee),ye=i(V.projectScope,ne),be=!1,xe=!1,Ie=[],Xe=[],et=$h(i(V.projectScope,ce));if(Fh(),n(V.userConfigTarget)!==null){let Re=Jt(V.userConfigTarget);if(Re.errors.push(...U(V.userConfigPath,V.userScope)),Ie.push({scope:"User",path:V.userConfigPath,result:Re,schema:"rules",target:V.userConfigTarget}),Re.errors.length>0)be=!0}if(n(he)!==null)if(xe=!0,n(V.userConfigTarget)!==null)Xe.push(to("user","cleanup"));else{let Re=po(he);if(Ie.push({scope:"User",path:ee,result:Re,schema:"legacy",inactive:!0,target:he}),Xe.push(to("user",Re.errors.length>0?"fix-or-delete":"migrate")),Re.errors.length>0)be=!0}if(n(V.projectConfigTarget)!==null){let Re=Jt(V.projectConfigTarget);if(Re.errors.push(...U(V.projectConfigPath,V.projectScope)),Ie.push({scope:"Project",path:Ti(V.projectConfigPath),result:Re,schema:"rules",target:V.projectConfigTarget}),Re.errors.length>0)be=!0;if(n(ye)!==null)xe=!0,Xe.push(to("project","cleanup"))}else if(n(ye)!==null){xe=!0,be=!0;let Re=po(ye);Ie.push({scope:"Project",path:Ti(ne),result:Re,schema:"legacy",inactive:!0,target:ye}),Xe.push(to("project",Re.errors.length>0?"fix-or-delete":"migrate"))}if(et?.result.errors.length)be=!0;if(Ie.length===0&&!et)return console.log(`
274
+ No config files found. Using built-in rules only.`),0;for(let Re of Ie)if(Re.inactive)jh(Re.scope,Re.path,Re.result);else if(Re.result.errors.length>0)Mh(Re.scope,Re.path,Re.result.errors);else{if(Re.schema==="rules"&&Gh(Re.target))console.log(`
275
+ Added $schema to ${Re.scope.toLowerCase()} config.`);Nh(Re.scope,Re.path,Re.result,Re.schema)}for(let Re of Xe)console.error(`
276
+ ${dt.red(Re)}`);if(et)if(et.result.errors.length>0)Uh(et.path,et.result.errors);else Hh(et.path,et.result);if(be)return console.error(`
268
277
  Config validation failed.`),1;return console.log(xe?`
269
278
  Configs valid with warnings.`:`
270
- All configs valid.`),0}function Wr(P,A){let q=`legacy ${P} config`;if(A==="cleanup")return`Warning: Legacy ${P} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(A==="migrate")return`Warning: Legacy ${P} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${P} config is no longer supported. Fix or delete the ${q}, then run \`npx -y cc-safety-net rule migrate\`.`}function ph(P){if(le(P)===null)return null;let A=fh(P);if(A.ruleNames.size===0&&A.errors.length===0)return null;return{path:P.path,result:A}}function fh(P){let A=[],q=new Set,V=(le(P)??[]).filter((ee)=>!dh.has(ee.name)).sort((ee,ne)=>ee.name.localeCompare(ne.name));if(V.length===0)return{errors:A,ruleNames:q};for(let ee of V){if(!l.test(ee.name)){A.push(`rulebook directory names must match ${l}: ${ee.name}`);continue}if(ee.kind!=="directory"){A.push(`${ee.name} must be a rulebook directory`);continue}let ne=i(P.scope,ah(P.path,ee.name,"rulebook.json")),ce=n(ne);if(ce===null){A.push(`${ee.name}/rulebook.json is required`);continue}try{let he;try{he=JSON.parse(ce)}catch{A.push(`${ee.name}/rulebook.json: invalid JSON`);continue}let ye=se(he);if(ye.name!==ee.name){A.push(`rulebook name "${ye.name}" must match folder "${ee.name}"`);continue}let be=Hr(ye);if(be.length>0){A.push(...be.map((xe)=>`${ee.name}/rulebook.json: ${xe}`));continue}q.add(ee.name)}catch(he){A.push(he instanceof Error?`${ee.name}/rulebook.json: ${he.message}`:`${ee.name}/rulebook.json: ${String(he)}`)}}return{errors:A,ruleNames:q}}function mh(){console.log(vd),console.log(lh)}function gh(P,A,q,V){if(console.log(`
271
- ✓ ${P} config: ${A}`),console.log(` Schema: ${V==="rules"?"rulebook sources":"legacy inline rules"}`),q.ruleNames.size>0){console.log(` ${V==="rules"?"Sources":"Rules"}:`);let ee=1;for(let ne of q.ruleNames)console.log(` ${ee}. ${ne}`),ee++}else console.log(` ${V==="rules"?"Sources":"Rules"}: (none)`)}function hh(P,A,q){if(console.error(`
272
- ✗ Legacy ${P.toLowerCase()} config: ${A}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),q.errors.length>0){console.error(" Errors:");let V=1;for(let ee of q.errors)for(let ne of ee.split("; "))console.error(` ${V}. ${ne}`),V++;return}if(q.ruleNames.size>0){console.error(" Rules:");let V=1;for(let ee of q.ruleNames)console.error(` ${V}. ${ee}`),V++;return}console.error(" Rules: (none)")}function yh(P,A,q){Ld(`${P} config`,A,q)}function vh(P,A){console.log(`
273
- ✓ GitHub source rules: ${P}`),console.log(" Rulebooks:");let q=1;for(let V of A.ruleNames)console.log(` ${q}. ${V}`),q++}function bh(P,A){Ld("GitHub source rules",P,A)}function Ld(P,A,q){console.error(`
274
- ✗ ${P}: ${A}`),console.error(" Errors:");let V=1;for(let ee of q)for(let ne of ee.split("; "))console.error(` ${V}. ${ne}`),V++}function Lh(P){try{let A=n(P);if(A===null)return!1;let q=JSON.parse(A);if(q.$schema)return!1;return g(P,JSON.stringify({$schema:ch,...q},null,2)),!0}catch(A){if(A instanceof r)throw A;return!1}}var wd=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),kh=new Set(["add","remove","list"]),xh="cc-safety-net/rulebooks";async function kd(P,A){try{return await Ch(P,A)}catch(q){if(q instanceof r)return console.error(q.message),1;throw q}}async function Ch(P,A){let q=Rh(A),V=q.help?Sh(q.positionals):null;if(V)return wn(V),0;if(q.errors.length>0){for(let he of q.errors)console.error(he);return 1}let ee=q.positionals[0];if(!ee)return wn(fn,console.error),1;let ne=q.positionals[1],ce={global:q.global};if(ee==="init"){let he=Pt(P,ce);Ah(he.configTarget);let ye=wh(he.configDir,"example-rules","rulebook.json"),be=i(he.filesystemScope,ye);if(q.example&&n(be)===null)Vc(be);let xe=U(he.configPath,he.filesystemScope);for(let Ie of xe)console.error(Ie);if(xe.length>0)return 1;return console.log("Rule config initialized."),0}if(ee==="add"){let he=xd(q);if(!he)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let ye=Pt(P,ce),be=await cd(P,he,{...ce,ref:q.ref,rulebooks:q.only.length>0?q.only:void 0});return Hc(be,he,`Scope: ${q.global?"user":"project"} (${ye.configDir})`),be.ok?0:1}if(ee==="remove"){if(!ne)return console.error("rule remove requires a source"),1;let he=await dd(P,ne,{...ce,deleteSource:q.deleteSource});return Mr(he,`Removed rulebook source: ${ne}`),he.ok?0:1}if(ee==="update"){let he=await zr(P,{...ce,only:ne,refresh:!0});return Mr(he,"Rule config updated."),he.ok?0:1}if(ee==="sync")return Fs(P,{global:q.global});if(ee==="list"){let he=Y(P,{cwd:process.cwd()});return Gc(he),he.errors.length>0?1:0}if(ee==="wrapper")return _h(P,q);if(ee==="migrate")return gd(P,{cleanup:q.cleanup,cwd:process.cwd()});if(ee==="doc"){console.log(Nc);let he=await yd(P);if(he)console.error(he);return 0}if(ee==="verify")return bd(P);return 1}function Sh(P){if(P.length===0)return fn;let A=fn.subcommands.filter((V)=>V.usage.split(" ")[0]===P[0]);if(A.length===0)return null;if(P.length===1&&A.length>1)return{name:`rule ${P[0]}`,description:`Subcommands of rule ${P[0]}`,usage:`rule ${P[0]} <subcommand>`,subcommands:A,options:[]};let q=P.length===1?A[0]:A.find((V)=>V.usage.split(" ")[1]===P[1]);if(!q)return null;return{name:`rule ${P[0]}`,description:q.description,usage:`rule ${q.usage}`,options:P[0]==="add"?eo:[],examples:P[0]==="add"?to:void 0}}function Rh(P){let A=xt({label:"rule",booleans:{global:["-g","--global"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"]},lists:{only:["--only"]},positionals:"list"},P),q={...A.flags,ref:A.values.ref,only:A.lists.only??[],help:A.help,positionals:A.positionals,errors:A.errors};return Ph(q),q}function Ph(P){let[A]=P.positionals;if(A&&!wd.has(A))P.errors.push(`Unknown rule subcommand: ${A}`);if(P.deleteSource&&A!=="remove")if(A&&wd.has(A))P.errors.push(`Unknown option for rule ${A}: --delete-source`);else P.errors.push("--delete-source is only valid with 'rule remove'");if(P.cleanup&&A!=="migrate")P.errors.push(Wn(A,"--cleanup"));if(P.example&&A!=="init")P.errors.push(Wn(A,"--example"));if(P.ref&&A!=="add")P.errors.push(Wn(A,"--ref"));if(P.only.length>0&&A!=="add")P.errors.push(Wn(A,"--only"));if(A==="add")Eh(P);if(A==="migrate"){if(P.global)P.errors.push(Wn(A,"--global"));if(P.positionals.length>1)P.errors.push(`Unexpected rule migrate argument: ${P.positionals[1]}`)}else if(A==="wrapper")Dh(P);else if(P.positionals.length>2)P.errors.push(`Unexpected rule argument: ${P.positionals[2]}`);if(A==="list"&&P.global)P.errors.push("Unknown option for rule list: --global")}function xd(P){if(P.positionals[1])return P.positionals[1];if(P.ref||P.only.length>0)return xh;return}function Eh(P){let A=xd(P);if(!A)return;if((P.ref||P.only.length>0)&&!K(A)){if(P.ref)P.errors.push(`--ref can only select a ref for an owner/repo source: ${A}`);if(P.only.length>0)P.errors.push("--only can only select rulebooks from an owner/repo source");return}if(P.ref&&!oe(P.ref))P.errors.push(`--ref must use valid path segments: ${P.ref}`);let q=P.only.filter((V)=>!l.test(V));if(q.length>0)P.errors.push(`Invalid rulebook names: ${q.join(", ")}`)}function Wn(P,A){return P?`Unknown option for rule ${P}: ${A}`:`Unknown option for rule: ${A}`}function Dh(P){let A=P.positionals[1],q=P.positionals[2];if(!A){P.errors.push("rule wrapper requires add, remove, or list");return}if(!kh.has(A)){P.errors.push(`Unknown rule wrapper action: ${A}`);return}if(A==="list"){if(q)P.errors.push(`Unexpected rule wrapper argument: ${q}`);return}if(!q){P.errors.push(`rule wrapper ${A} requires a command`);return}if(P.positionals.length>3)P.errors.push(`Unexpected rule wrapper argument: ${P.positionals[3]}`)}function Ah(P){if(n(P)===null){qc(P);return}let A=m(P);if(!A.config)return;Rt(P,{version:1,rules:A.config.rules,overrides:A.config.overrides??{},transparent_wrappers:A.config.transparent_wrappers??[]})}async function _h(P,A){let q=A.positionals[1],V=A.positionals[2],ee=Pt(P,{global:A.global}).configTarget;if(q==="list"){let ye=m(ee);if(ye.errors.length>0){for(let be of ye.errors)console.error(be);return 1}return Th(ye.config?.transparent_wrappers??[]),0}if(!V||!w.test(V))return console.error("transparent wrapper must match command pattern"),1;if(Le(V))return console.error(`reserved command "${V}" cannot be a wrapper`),1;let ne=m(ee);if(ne.errors.length>0){for(let ye of ne.errors)console.error(ye);return 1}let ce=ne.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},he=q==="add"?[...new Set([...ce.transparent_wrappers??[],V])]:(ce.transparent_wrappers??[]).filter((ye)=>ye!==V);return Rt(ee,{version:1,rules:ce.rules,overrides:ce.overrides??{},transparent_wrappers:he}),console.log(q==="add"?`Added transparent wrapper: ${V}`:`Removed transparent wrapper: ${V}`),0}function Th(P){if(P.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${P.length}):`);for(let A of P)console.log(` - ${A}`)}import{sep as Nh}from"node:path";import{existsSync as $h,readFileSync as Ih}from"node:fs";import{join as Oh}from"node:path";async function Fh(P){if(P.isTTY)return null;return(await We(P).catch(()=>null))?.trim()||null}function jh(P){let A=P.env.get("CLAUDE_SETTINGS_PATH");if(A)return A;return Oh(P.home,".claude","settings.json")}function Ri(P){let A=jh(P);if(!$h(A))return!1;try{let q=Ih(A,"utf-8"),V=JSON.parse(q);if(!V.enabledPlugins)return!1;let ee="cc-safety-net@cc-marketplace";if(!(ee in V.enabledPlugins))return!1;return V.enabledPlugins[ee]===!0}catch(q){if(L(o.debug,P.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${A}: ${q instanceof Error?q.message:String(q)}`);return!1}}async function Pi(P,A=process.stdin){let q=Ri(P),V;if(!q)V="\uD83D\uDEE1️ CC Safety Net ❌";else{let ne=E(P,{cwd:process.cwd()}),ce=ne.policy,he=R(ce,P.env),ye=Object.values(H(ce,he.capabilities)).some((Ie)=>Ie.changesInherited),be={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[ye?"custom":he.effectiveLevel],xe=(ne.policyScopes?.weakenings.length??0)>0?"\uD83D\uDD3B":"";V=`\uD83D\uDEE1️ CC Safety Net ${be}${he.worktreeMode?"\uD83C\uDF33":""}${xe}${ne.state==="degraded"?"⚠️":""}`}let ee=await Fh(A);if(ee&&!ee.startsWith("{"))console.log(`${ee} | ${V}`);else console.log(V)}function Cd(P){let A=E(P,{cwd:process.cwd()}),q=A.policy,V=R(q,P.env),ee=!!process.env.NO_COLOR||!process.stdout.isTTY,ne=Math.min(process.stdout.columns||80,100),ce=ee?"ok":"✔",he=ee?"OFF":"✘",ye=(at,ct)=>{let lt=` ${at.padEnd(13)}${ct}`;return(lt.length>ne?`${lt.slice(0,ne-1)}…`:lt).replaceAll(he,dt.red(he))},be=Object.values(H(q,V.capabilities)).some((at)=>at.changesInherited),xe=(at)=>at===P.home||at.startsWith(`${P.home}${Nh}`)?`~${at.slice(P.home.length)}`:at,Ie={ready:dt.green,degraded:dt.yellow}[A.state],Xe=A.policyScopes?.weakenings??[],et=[...Ri(P)?[]:["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."],...A.diagnostics],Re=ee?"-":"·";console.log([`${ee?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Ie(A.state)}`,"",ye("Protection",`destructive ${q.destructiveCommandProtectionEnabled?ce:he} secrets ${q.secretProtection.enabled?ce:he}`),ye("Level",be?`${V.effectiveLevel} (customised)`:V.effectiveLevel),ye("Rules",q.rules.length===0?"none active":`${q.rules.length} active`),ye("Policy",xe(u(P))),...A.policyScopes?[ye("Project",xe(b(process.cwd())))]:[],...V.worktreeMode?[ye("Worktree","relaxations active")]:[],"",...Xe.length===0?[]:[" Project policy",...Xe.flatMap((at)=>jn(at," ",ne-6).map((ct,lt)=>lt===0?` ${ct}`:ct)),""],...et.length===0?[" Everything configured is active."]:[" Not active",...et.flatMap((at)=>jn(at," ",ne-6).map((ct,lt)=>lt===0?` ${Re} ${ct}`:ct)),""," Full report: cc-safety-net doctor"]].join(`
275
- `))}import{spawn as Od}from"node:child_process";import{randomBytes as Wh}from"node:crypto";import{existsSync as Kh}from"node:fs";import{createServer as Yh}from"node:http";import{Writable as Zh}from"node:stream";var Kr=500;function Mh(P){let A=P.filter((ee)=>ee.decision!=="allow"),q=P.filter((ee)=>ee.decision==="allow"),V=Math.min(A.length,Math.max(Kr-q.length,Math.ceil(Kr/2)));return[...A.slice(0,V),...q.slice(0,Kr-V)]}function Sd(P,A,q=D(P)){if(q)z(P,q);let V=(ct)=>new Date(ct.getFullYear(),ct.getMonth(),ct.getDate()).getTime(),ee=V(new Date),ne=new Date(ee);ne.setDate(ne.getDate()-(A-1));let ce=ne.getTime(),he=[],ye={count:0};for(let ct of q?Yt(q,ye):[])for(let lt of pn(ct,ye)){let pt=new Date(lt.ts).getTime();if(!Number.isFinite(pt))continue;if(pt>=ce)he.push(lt)}he.sort((ct,lt)=>new Date(lt.ts).getTime()-new Date(ct.ts).getTime());let be=Array.from({length:A},()=>0),xe=Array.from({length:A},()=>0),Ie={},Xe={},et={},Re=0,at=0;for(let ct of he){let lt=ct.agent||"unknown";Ie[lt]=(Ie[lt]??0)+1;let pt=Math.round((ee-V(new Date(ct.ts)))/86400000),mt=A-1-pt,gt=pt>=0&&pt<A;if(gt)xe[mt]=(xe[mt]??0)+1;if(ct.decision!=="allow"){if(Re++,ct.ruleId)Xe[ct.ruleId]=(Xe[ct.ruleId]??0)+1;let ut=Qr(ct.segment||ct.command);if(ut)et[ut]=(et[ut]??0)+1;if(ct.failureStage)at++;if(gt)be[mt]=(be[mt]??0)+1}}return{days:A,logsDir:q,homeDir:P.home,totalInWindow:he.length,truncated:he.length>Kr,unreadable:ye.count,counts:{blocked:Re,allowed:he.length-Re,agents:Ie,blockedByDay:be,analyzedByDay:xe,rules:Xe,commands:et,errors:at},entries:Mh(he).sort((ct,lt)=>new Date(lt.ts).getTime()-new Date(ct.ts).getTime())}}import{spawn as Hh}from"node:child_process";import{existsSync as Uh,statSync as Rd}from"node:fs";import{delimiter as Gh,join as Bh}from"node:path";var qh=120000,Yr="Choose the project folder",Vh=`try
276
- return POSIX path of (choose folder with prompt "${Yr}")
279
+ All configs valid.`),0}function to(P,A){let q=`legacy ${P} config`;if(A==="cleanup")return`Warning: Legacy ${P} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(A==="migrate")return`Warning: Legacy ${P} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${P} config is no longer supported. Fix or delete the ${q}, then run \`npx -y cc-safety-net rule migrate\`.`}function $h(P){if(le(P)===null)return null;let A=Oh(P);if(A.ruleNames.size===0&&A.errors.length===0)return null;return{path:P.path,result:A}}function Oh(P){let A=[],q=new Set,V=(le(P)??[]).filter((ee)=>!Th.has(ee.name)).sort((ee,ne)=>ee.name.localeCompare(ne.name));if(V.length===0)return{errors:A,ruleNames:q};for(let ee of V){if(!l.test(ee.name)){A.push(`rulebook directory names must match ${l}: ${ee.name}`);continue}if(ee.kind!=="directory"){A.push(`${ee.name} must be a rulebook directory`);continue}let ne=i(P.scope,Dh(P.path,ee.name,"rulebook.json")),ce=n(ne);if(ce===null){A.push(`${ee.name}/rulebook.json is required`);continue}try{let he;try{he=JSON.parse(ce)}catch{A.push(`${ee.name}/rulebook.json: invalid JSON`);continue}let ye=se(he);if(ye.name!==ee.name){A.push(`rulebook name "${ye.name}" must match folder "${ee.name}"`);continue}let be=Jr(ye);if(be.length>0){A.push(...be.map((xe)=>`${ee.name}/rulebook.json: ${xe}`));continue}q.add(ee.name)}catch(he){A.push(he instanceof Error?`${ee.name}/rulebook.json: ${he.message}`:`${ee.name}/rulebook.json: ${String(he)}`)}}return{errors:A,ruleNames:q}}function Fh(){console.log(Dd),console.log(Ah)}function Nh(P,A,q,V){if(console.log(`
280
+ ✓ ${P} config: ${A}`),console.log(` Schema: ${V==="rules"?"rulebook sources":"legacy inline rules"}`),q.ruleNames.size>0){console.log(` ${V==="rules"?"Sources":"Rules"}:`);let ee=1;for(let ne of q.ruleNames)console.log(` ${ee}. ${ne}`),ee++}else console.log(` ${V==="rules"?"Sources":"Rules"}: (none)`)}function jh(P,A,q){if(console.error(`
281
+ ✗ Legacy ${P.toLowerCase()} config: ${A}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),q.errors.length>0){console.error(" Errors:");let V=1;for(let ee of q.errors)for(let ne of ee.split("; "))console.error(` ${V}. ${ne}`),V++;return}if(q.ruleNames.size>0){console.error(" Rules:");let V=1;for(let ee of q.ruleNames)console.error(` ${V}. ${ee}`),V++;return}console.error(" Rules: (none)")}function Mh(P,A,q){_d(`${P} config`,A,q)}function Hh(P,A){console.log(`
282
+ ✓ GitHub source rules: ${P}`),console.log(" Rulebooks:");let q=1;for(let V of A.ruleNames)console.log(` ${q}. ${V}`),q++}function Uh(P,A){_d("GitHub source rules",P,A)}function _d(P,A,q){console.error(`
283
+ ✗ ${P}: ${A}`),console.error(" Errors:");let V=1;for(let ee of q)for(let ne of ee.split("; "))console.error(` ${V}. ${ne}`),V++}function Gh(P){try{let A=n(P);if(A===null)return!1;let q=JSON.parse(A);if(q.$schema)return!1;return g(P,JSON.stringify({$schema:_h,...q},null,2)),!0}catch(A){if(A instanceof r)throw A;return!1}}var Td=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),qh=new Set(["add","remove","list"]),Vh="cc-safety-net/rulebooks";async function Id(P,A){try{return await zh(P,A)}catch(q){if(q instanceof r)return console.error(q.message),1;throw q}}async function zh(P,A){let q=Wh(A),V=q.help?Jh(q.positionals):null;if(V)return Cn(V),0;if(q.errors.length>0){for(let he of q.errors)console.error(he);return 1}let ee=q.positionals[0];if(!ee)return Cn(gn,console.error),1;let ne=q.positionals[1],ce={global:q.global};if(ee==="init"){let he=Et(P,ce);Zh(he.configTarget);let ye=Bh(he.configDir,"example-rules","rulebook.json"),be=i(he.filesystemScope,ye);if(q.example&&n(be)===null)nd(be);let xe=U(he.configPath,he.filesystemScope);for(let Ie of xe)console.error(Ie);if(xe.length>0)return 1;return console.log("Rule config initialized."),0}if(ee==="add"){let he=$d(q);if(!he)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let ye=Et(P,ce),be=await Ld(P,he,{...ce,ref:q.ref,rulebooks:q.only.length>0?q.only:void 0});return Xc(be,he,`Scope: ${q.global?"user":"project"} (${ye.configDir})`),be.ok?0:1}if(ee==="remove"){if(!ne)return console.error("rule remove requires a source"),1;let he=await wd(P,ne,{...ce,deleteSource:q.deleteSource});return zr(he,`Removed rulebook source: ${ne}`),he.ok?0:1}if(ee==="update"){let he=await Qr(P,{...ce,only:ne,refresh:!0});return zr(he,"Rule config updated."),he.ok?0:1}if(ee==="sync")return Bs(P,{global:q.global});if(ee==="list"){let he=Y(P,{cwd:process.cwd()});return Qc(he),he.errors.length>0?1:0}if(ee==="wrapper")return Qh(P,q);if(ee==="migrate")return Rd(P,{cleanup:q.cleanup,cwd:process.cwd()});if(ee==="doc"){console.log(Kc);let he=await Ed(P);if(he)console.error(he);return 0}if(ee==="verify")return Ad(P);return 1}function Jh(P){if(P.length===0)return gn;let A=gn.subcommands.filter((V)=>V.usage.split(" ")[0]===P[0]);if(A.length===0)return null;if(P.length===1&&A.length>1)return{name:`rule ${P[0]}`,description:`Subcommands of rule ${P[0]}`,usage:`rule ${P[0]} <subcommand>`,subcommands:A,options:[]};let q=P.length===1?A[0]:A.find((V)=>V.usage.split(" ")[1]===P[1]);if(!q)return null;return{name:`rule ${P[0]}`,description:q.description,usage:`rule ${q.usage}`,options:P[0]==="add"?ao:[],examples:P[0]==="add"?lo:void 0}}function Wh(P){let A=xt({label:"rule",booleans:{global:["-g","--global"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"]},lists:{only:["--only"]},positionals:"list"},P),q={...A.flags,ref:A.values.ref,only:A.lists.only??[],help:A.help,positionals:A.positionals,errors:A.errors};return Kh(q),q}function Kh(P){let[A]=P.positionals;if(A&&!Td.has(A))P.errors.push(`Unknown rule subcommand: ${A}`);if(P.deleteSource&&A!=="remove")if(A&&Td.has(A))P.errors.push(`Unknown option for rule ${A}: --delete-source`);else P.errors.push("--delete-source is only valid with 'rule remove'");if(P.cleanup&&A!=="migrate")P.errors.push(er(A,"--cleanup"));if(P.example&&A!=="init")P.errors.push(er(A,"--example"));if(P.ref&&A!=="add")P.errors.push(er(A,"--ref"));if(P.only.length>0&&A!=="add")P.errors.push(er(A,"--only"));if(A==="add")Yh(P);if(A==="migrate"){if(P.global)P.errors.push(er(A,"--global"));if(P.positionals.length>1)P.errors.push(`Unexpected rule migrate argument: ${P.positionals[1]}`)}else if(A==="wrapper")Xh(P);else if(P.positionals.length>2)P.errors.push(`Unexpected rule argument: ${P.positionals[2]}`);if(A==="list"&&P.global)P.errors.push("Unknown option for rule list: --global")}function $d(P){if(P.positionals[1])return P.positionals[1];if(P.ref||P.only.length>0)return Vh;return}function Yh(P){let A=$d(P);if(!A)return;if((P.ref||P.only.length>0)&&!K(A)){if(P.ref)P.errors.push(`--ref can only select a ref for an owner/repo source: ${A}`);if(P.only.length>0)P.errors.push("--only can only select rulebooks from an owner/repo source");return}if(P.ref&&!oe(P.ref))P.errors.push(`--ref must use valid path segments: ${P.ref}`);let q=P.only.filter((V)=>!l.test(V));if(q.length>0)P.errors.push(`Invalid rulebook names: ${q.join(", ")}`)}function er(P,A){return P?`Unknown option for rule ${P}: ${A}`:`Unknown option for rule: ${A}`}function Xh(P){let A=P.positionals[1],q=P.positionals[2];if(!A){P.errors.push("rule wrapper requires add, remove, or list");return}if(!qh.has(A)){P.errors.push(`Unknown rule wrapper action: ${A}`);return}if(A==="list"){if(q)P.errors.push(`Unexpected rule wrapper argument: ${q}`);return}if(!q){P.errors.push(`rule wrapper ${A} requires a command`);return}if(P.positionals.length>3)P.errors.push(`Unexpected rule wrapper argument: ${P.positionals[3]}`)}function Zh(P){if(n(P)===null){td(P);return}let A=m(P);if(!A.config)return;Pt(P,{version:1,rules:A.config.rules,overrides:A.config.overrides??{},transparent_wrappers:A.config.transparent_wrappers??[]})}async function Qh(P,A){let q=A.positionals[1],V=A.positionals[2],ee=Et(P,{global:A.global}).configTarget;if(q==="list"){let ye=m(ee);if(ye.errors.length>0){for(let be of ye.errors)console.error(be);return 1}return ey(ye.config?.transparent_wrappers??[]),0}if(!V||!w.test(V))return console.error("transparent wrapper must match command pattern"),1;if(Le(V))return console.error(`reserved command "${V}" cannot be a wrapper`),1;let ne=m(ee);if(ne.errors.length>0){for(let ye of ne.errors)console.error(ye);return 1}let ce=ne.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},he=q==="add"?[...new Set([...ce.transparent_wrappers??[],V])]:(ce.transparent_wrappers??[]).filter((ye)=>ye!==V);return Pt(ee,{version:1,rules:ce.rules,overrides:ce.overrides??{},transparent_wrappers:he}),console.log(q==="add"?`Added transparent wrapper: ${V}`:`Removed transparent wrapper: ${V}`),0}function ey(P){if(P.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${P.length}):`);for(let A of P)console.log(` - ${A}`)}import{sep as sy}from"node:path";import{existsSync as ty,readFileSync as ny}from"node:fs";import{join as ry}from"node:path";async function oy(P){if(P.isTTY)return null;return(await We(P).catch(()=>null))?.trim()||null}function iy(P){let A=P.env.get("CLAUDE_SETTINGS_PATH");if(A)return A;return ry(vr(P),"settings.json")}function Ii(P){let A=iy(P);if(!ty(A))return!1;try{let q=ny(A,"utf-8"),V=JSON.parse(q);if(!V.enabledPlugins)return!1;let ee="cc-safety-net@cc-marketplace";if(!(ee in V.enabledPlugins))return!1;return V.enabledPlugins[ee]===!0}catch(q){if(L(o.debug,P.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${A}: ${q instanceof Error?q.message:String(q)}`);return!1}}async function $i(P,A=process.stdin){let q=Ii(P),V;if(!q)V="\uD83D\uDEE1️ CC Safety Net ❌";else{let ne=E(P,{cwd:process.cwd()}),ce=ne.policy,he=R(ce,P.env),ye=Object.values(H(ce,he.capabilities)).some((Ie)=>Ie.changesInherited),be={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[ye?"custom":he.effectiveLevel],xe=(ne.policyScopes?.weakenings.length??0)>0?"\uD83D\uDD3B":"";V=`\uD83D\uDEE1️ CC Safety Net ${be}${he.worktreeMode?"\uD83C\uDF33":""}${xe}${ne.state==="degraded"?"⚠️":""}`}let ee=await oy(A);if(ee&&!ee.startsWith("{"))console.log(`${ee} | ${V}`);else console.log(V)}function Od(P){let A=E(P,{cwd:process.cwd()}),q=A.policy,V=R(q,P.env),ee=!!process.env.NO_COLOR||!process.stdout.isTTY,ne=Math.min(process.stdout.columns||80,100),ce=ee?"ok":"✔",he=ee?"OFF":"✘",ye=(at,ct)=>{let lt=` ${at.padEnd(13)}${ct}`;return(lt.length>ne?`${lt.slice(0,ne-1)}…`:lt).replaceAll(he,dt.red(he))},be=Object.values(H(q,V.capabilities)).some((at)=>at.changesInherited),xe=(at)=>at===P.home||at.startsWith(`${P.home}${sy}`)?`~${at.slice(P.home.length)}`:at,Ie={ready:dt.green,degraded:dt.yellow}[A.state],Xe=A.policyScopes?.weakenings??[],et=[...Ii(P)?[]:["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."],...A.diagnostics],Re=ee?"-":"·";console.log([`${ee?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Ie(A.state)}`,"",ye("Protection",`destructive ${q.destructiveCommandProtectionEnabled?ce:he} secrets ${q.secretProtection.enabled?ce:he}`),ye("Level",be?`${V.effectiveLevel} (customised)`:V.effectiveLevel),ye("Rules",q.rules.length===0?"none active":`${q.rules.length} active`),ye("Policy",xe(u(P))),...A.policyScopes?[ye("Project",xe(b(process.cwd())))]:[],...V.worktreeMode?[ye("Worktree","relaxations active")]:[],"",...Xe.length===0?[]:[" Project policy",...Xe.flatMap((at)=>Bn(at," ",ne-6).map((ct,lt)=>lt===0?` ${ct}`:ct)),""],...et.length===0?[" Everything configured is active."]:[" Not active",...et.flatMap((at)=>Bn(at," ",ne-6).map((ct,lt)=>lt===0?` ${Re} ${ct}`:ct)),""," Full report: cc-safety-net doctor"]].join(`
284
+ `))}import{spawn as zd}from"node:child_process";import{randomBytes as hy}from"node:crypto";import{existsSync as yy}from"node:fs";import{createServer as vy}from"node:http";import{Writable as by}from"node:stream";var no=500;function ay(P){let A=P.filter((ee)=>ee.decision!=="allow"),q=P.filter((ee)=>ee.decision==="allow"),V=Math.min(A.length,Math.max(no-q.length,Math.ceil(no/2)));return[...A.slice(0,V),...q.slice(0,no-V)]}function Fd(P,A,q=D(P)){if(q)z(P,q);let V=(ct)=>new Date(ct.getFullYear(),ct.getMonth(),ct.getDate()).getTime(),ee=V(new Date),ne=new Date(ee);ne.setDate(ne.getDate()-(A-1));let ce=ne.getTime(),he=[],ye={count:0};for(let ct of q?Xt(q,ye):[])for(let lt of mn(ct,ye)){let ft=new Date(lt.ts).getTime();if(!Number.isFinite(ft))continue;if(ft>=ce)he.push(lt)}he.sort((ct,lt)=>new Date(lt.ts).getTime()-new Date(ct.ts).getTime());let be=Array.from({length:A},()=>0),xe=Array.from({length:A},()=>0),Ie={},Xe={},et={},Re=0,at=0;for(let ct of he){let lt=ct.agent||"unknown";Ie[lt]=(Ie[lt]??0)+1;let ft=Math.round((ee-V(new Date(ct.ts)))/86400000),mt=A-1-ft,gt=ft>=0&&ft<A;if(gt)xe[mt]=(xe[mt]??0)+1;if(ct.decision!=="allow"){if(Re++,ct.ruleId)Xe[ct.ruleId]=(Xe[ct.ruleId]??0)+1;let ut=so(ct.segment||ct.command);if(ut)et[ut]=(et[ut]??0)+1;if(ct.failureStage)at++;if(gt)be[mt]=(be[mt]??0)+1}}return{days:A,logsDir:q,homeDir:P.home,totalInWindow:he.length,truncated:he.length>no,unreadable:ye.count,counts:{blocked:Re,allowed:he.length-Re,agents:Ie,blockedByDay:be,analyzedByDay:xe,rules:Xe,commands:et,errors:at},entries:ay(he).sort((ct,lt)=>new Date(lt.ts).getTime()-new Date(ct.ts).getTime())}}import{spawn as ly}from"node:child_process";import{existsSync as cy,statSync as Nd}from"node:fs";import{delimiter as dy,join as uy}from"node:path";var py=120000,ro="Choose the project folder",fy=`try
285
+ return POSIX path of (choose folder with prompt "${ro}")
277
286
  on error number -128
278
287
  return ""
279
- end try`,zh=`Add-Type -AssemblyName System.Windows.Forms
288
+ end try`,my=`Add-Type -AssemblyName System.Windows.Forms
280
289
  $dialog = New-Object System.Windows.Forms.FolderBrowserDialog
281
- $dialog.Description = '${Yr}'
282
- if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Pd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${Yr}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",Yr]}],Ed=(P,A)=>(A.PATH??"").split(Gh).some((q)=>{if(q.length===0)return!1;try{let V=Rd(Bh(q,P));return V.isFile()&&(V.mode&73)!==0}catch{return!1}});function Ei(P,A){if(P==="darwin"||P==="win32")return!0;if(P!=="linux")return!1;if(!A.DISPLAY&&!A.WAYLAND_DISPLAY)return!1;return Pd.some((q)=>Ed(q.binary,A))}function Jh(P,A){if(P==="darwin")return{cmd:"osascript",args:["-e",Vh]};if(P==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",zh]};let q=Pd.find((V)=>Ed(V.binary,A));return q?{cmd:q.binary,args:q.args}:null}function Di(P=process.platform,A=process.env){let q=Jh(P,A);if(!q)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((V)=>{let ee=Hh(q.cmd,q.args,{env:A,stdio:["ignore","pipe","pipe"]}),ne="",ce=!1,he=(be)=>{if(ce)return;ce=!0,clearTimeout(ye),V(be)},ye=setTimeout(()=>{ee.kill(),he({error:"The folder dialog timed out"})},qh);ee.stdout.on("data",(be)=>{ne+=be.toString()}),ee.on("error",()=>he({error:`Could not open the folder dialog (${q.cmd})`})),ee.on("close",()=>{let be=ne.trim().replace(/\/+$/,"");if(!be)return he({cancelled:!0});if(!Uh(be)||!Rd(be).isDirectory())return he({error:"That selection is not a folder on disk"});he({path:be})})})}var Dd=`<!doctype html>
290
+ $dialog.Description = '${ro}'
291
+ if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,jd=[{binary:"zenity",args:["--file-selection","--directory",`--title=${ro}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",ro]}],Md=(P,A)=>(A.PATH??"").split(dy).some((q)=>{if(q.length===0)return!1;try{let V=Nd(uy(q,P));return V.isFile()&&(V.mode&73)!==0}catch{return!1}});function Oi(P,A){if(P==="darwin"||P==="win32")return!0;if(P!=="linux")return!1;if(!A.DISPLAY&&!A.WAYLAND_DISPLAY)return!1;return jd.some((q)=>Md(q.binary,A))}function gy(P,A){if(P==="darwin")return{cmd:"osascript",args:["-e",fy]};if(P==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",my]};let q=jd.find((V)=>Md(V.binary,A));return q?{cmd:q.binary,args:q.args}:null}function Fi(P=process.platform,A=process.env){let q=gy(P,A);if(!q)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((V)=>{let ee=ly(q.cmd,q.args,{env:A,stdio:["ignore","pipe","pipe"]}),ne="",ce=!1,he=(be)=>{if(ce)return;ce=!0,clearTimeout(ye),V(be)},ye=setTimeout(()=>{ee.kill(),he({error:"The folder dialog timed out"})},py);ee.stdout.on("data",(be)=>{ne+=be.toString()}),ee.on("error",()=>he({error:`Could not open the folder dialog (${q.cmd})`})),ee.on("close",()=>{let be=ne.trim().replace(/\/+$/,"");if(!be)return he({cancelled:!0});if(!cy(be)||!Nd(be).isDirectory())return he({error:"That selection is not a folder on disk"});he({path:be})})})}var Hd=`<!doctype html>
283
292
  <html lang="en">
284
293
  <head>
285
294
  <meta charset="utf-8">
@@ -5916,6 +5925,6 @@ load().then((loaded) => {
5916
5925
  </script>
5917
5926
  </body>
5918
5927
  </html>
5919
- `;var Ad='<script id="ccsn-data" type="application/json">';function _d(P){return Dd.replace(Ad,()=>Ad+JSON.stringify({token:P}).replaceAll("<","\\u003c"))}var Zr="kenryu42/cc-safety-net",Xh=`https://github.com/${Zr}`,Ti=1e4,Qh=7,ey="The project draft directory changed; reload the draft before applying.",ty="audit settings are user scope only; remove the audit section from a project proposal";async function Fd(P,A={}){let q=xt({label:"gui",booleans:{noOpen:["--no-open"]}},P),V=A.log??console.log,ee=A.error??console.error;if(q.errors.length>0){for(let ce of q.errors)ee(ce);return ee("Usage: cc-safety-net gui [--no-open]"),1}let ne=await ny(c,A);if(V(`CC Safety Net policy GUI: ${ne.url}`),!q.flags.noOpen)try{await(A.openBrowser??fy)(ne.url)}catch(ce){ee(`Failed to open browser: ${ce instanceof Error?ce.message:String(ce)}`),ee(`Open this URL manually: ${ne.url}`)}if(A.keepAlive===!1)return await ne.close(),0;return await py(ne),0}async function ny(P,A={}){let q=Wh(24).toString("base64url"),V={dir:null,revision:0},ee=Yh((he,ye)=>{ry(P,he,ye,q,A,V)});await new Promise((he,ye)=>{ee.once("error",ye),ee.listen(0,"127.0.0.1",()=>{ee.off("error",ye),he()})});let ce=`http://127.0.0.1:${ee.address().port}`;return{origin:ce,token:q,url:`${ce}/?token=${encodeURIComponent(q)}`,close:()=>uy(ee)}}async function ry(P,A,q,V,ee,ne){let ce=P(),he=new URL(A.url??"/","http://127.0.0.1");if(A.method==="GET"&&he.pathname==="/favicon.ico"){q.writeHead(204,{"cache-control":"no-store"}),q.end();return}if(!ly(A,he,V)){ht(q,403,{error:"Forbidden"});return}if(A.method==="GET"&&he.pathname==="/"){dy(q,_d(V));return}if(A.method==="GET"&&he.pathname==="/api/policy"){let ye=_c(ce,ee),be=E(ce,Ai(ee));ht(q,200,{...ye,configState:Ne(be),...be.policyScopes?{projectPolicy:{path:b(ee.cwd??process.cwd()),weakenings:be.policyScopes.weakenings}}:{},destructiveCommandRules:G,secretPatterns:Ke,version:wt(),preview:ye.errors.length>0?null:Ae(ye.policy,ce.env)});return}if(A.method==="POST"&&he.pathname==="/api/policy/preview"){let ye=await Kn(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=Tc(ce,ye.value);ht(q,be.errors.length>0?400:200,be);return}if(A.method==="POST"&&he.pathname==="/api/policy/explain"){let ye=await Kn(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=ye.value;if(be===null||typeof be.command!=="string"){ht(q,400,{errors:["command must be a string"]});return}let xe=qn(be.policy,ce.home);if(xe.length>0){ht(q,400,{errors:xe});return}ht(q,200,sy(ce,be.command,be.policy,ee));return}if(A.method==="POST"&&he.pathname==="/api/policy"){let ye=await Kn(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=Vt(ce,ye.value,ee);ht(q,be.errors.length>0?400:200,be);return}if(A.method==="POST"&&he.pathname==="/api/reset"){ht(q,200,Vt(ce,X,ee));return}if(A.method==="POST"&&he.pathname==="/api/repair"){ht(q,200,$c(ce,ee));return}if(A.method==="POST"&&he.pathname==="/api/policy/project/choose-directory"){let ye=await(ee.chooseDirectory??Di)();if("path"in ye)ne.dir=ye.path,ne.revision+=1;ht(q,200,{cancelled:"cancelled"in ye,..."error"in ye?{error:ye.error}:{}});return}if(A.method==="GET"&&he.pathname==="/api/policy/project"){let ye=jd(ne,ee),be=Td(ye,ce.home),xe=Vn(ce,ee);ht(q,200,{path:b(ye),revision:ne.revision,baseline:xe.baseline,userPolicyDiagnostics:xe.diagnostics,projection:be.projection,projectionDiagnostics:be.diagnostics,canPickDirectory:Ei(process.platform,process.env)});return}if(A.method==="POST"&&he.pathname==="/api/policy/project/diff"){let ye=await $d(ce,A,q,ne,ee);if(!ye)return;let be=Td(ye.dir,ce.home),xe=Vn(ce,ee).baseline,Ie=Z(xe,ae(ye.proposal,ce.home).policy);ht(q,200,{rows:jr(Z(xe,be.projection).policy,Ie.policy,!1),weakenings:Ie.weakenings,existingFileDiagnostics:be.diagnostics});return}if(A.method==="POST"&&he.pathname==="/api/policy/project/apply"){let ye=await $d(ce,A,q,ne,ee);if(!ye)return;let be=iy(ye.dir,ye.proposal,ce.home);ht(q,be.errors.length>0?500:200,be);return}if(A.method==="GET"&&he.pathname==="/api/activity"){let ye=te(ce,ee),be=ay(he.searchParams.get("days"),ye);if(be===null){ht(q,400,{error:`days must be an integer between 1 and ${ye}`});return}ht(q,200,Sd(ce,be,ee.activityLogsDir));return}if(A.method==="POST"&&he.pathname==="/api/rules/choose-directory"){ht(q,200,await Di());return}if(A.method==="GET"&&he.pathname==="/api/rules"){let ye=Y(ce,Ai(ee)),be=new Map(ye.rules.map((xe)=>[xe.name,xe]));ht(q,200,{projectPath:ee.cwd??process.cwd(),canPickDirectory:Ei(process.platform,process.env),rulebooks:ye.rulebooks.map((xe)=>({source:xe.source,spec:xe.spec,name:xe.name,version:xe.version,rules:xe.rules.flatMap((Ie)=>{let Xe=be.get(Ie);if(!Xe)return[];return[{name:Xe.name,command:Xe.command,subcommand:Xe.subcommand,block_args:Xe.block_args,reason:Xe.reason}]})})),errors:ye.errors,warnings:ye.warnings});return}if(A.method==="GET"&&he.pathname==="/api/star/context"){ht(q,200,await(ee.fetchStarContext??(()=>by(ce,{logsDir:ee.activityLogsDir})))());return}if(A.method==="POST"&&he.pathname==="/api/star"){let ye=await(ee.starRepo??my)();ht(q,200,ye.ok?{ok:!0}:{ok:!1,fallbackUrl:Xh});return}if(A.method==="GET"&&he.pathname==="/api/integrations"){ht(q,200,await(ee.fetchIntegrations??(()=>gy(ce)))());return}if(A.method==="GET"&&he.pathname==="/api/health"){ht(q,200,await(ee.fetchHealth??yy)());return}if(A.method==="POST"&&(he.pathname==="/api/install"||he.pathname==="/api/uninstall")){let ye=await Kn(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=ye.value?.target;if(typeof be!=="string"||!Mt.some((Ie)=>Ie.target===be)){ht(q,400,{error:"unknown target"});return}let xe=he.pathname==="/api/install"?"install":"uninstall";ht(q,200,await(ee.runIntegration??vy)(xe,be));return}ht(q,404,{error:"Not found"})}function Ai(P){return{...P,cwd:P.cwd??process.cwd()}}function jd(P,A){return P.dir??A.cwd??process.cwd()}function Td(P,A){let q=b(P),V=Kh(q)?dn(q):{value:void 0,errors:[]},ee=ae(V.value,A);return{projection:ee.policy,diagnostics:[...V.errors,...ee.diagnostics]}}async function $d(P,A,q,V,ee){let ne=jd(V,ee),ce=V.revision,he=await Kn(A);if(!he.ok)return ht(q,he.status,{errors:[he.error]}),null;let ye=he.value;if(typeof ye?.revision!=="number")return ht(q,400,{errors:["revision must be a number"]}),null;if(ye.revision!==ce)return ht(q,409,{errors:[ey]}),null;let be=oy(ye.proposal,P.home);if(be.length>0)return ht(q,400,{errors:be}),null;return{dir:ne,proposal:ye.proposal}}function oy(P,A){let q=qn(P,A);if(q.length>0)return q;return P?.audit===void 0?[]:[ty]}function iy(P,A,q){let V=b(P),ee=Nr(A,C(A,q));try{return g(i(v(P,"project policy"),V),`${JSON.stringify(ee,null,2)}
5920
- `),{path:V,errors:[]}}catch(ne){return{path:V,errors:[ne instanceof Error?ne.message:String(ne)]}}}function sy(P,A,q,V){let ee=C(q,P.home),ne=E(P,Ai(V)),ce=Ee({rules:ne.policy.rules,transparentWrappers:ne.policy.transparentWrappers,safety:De(ee.safety),worktreeMode:ee.workflow.worktree_mode,destructiveCommandProtectionEnabled:ee.destructive_command_protection.enabled,destructiveCommandRuleOverrides:ee.destructive_command_protection.overrides,destructiveCommandAllowPaths:ee.destructive_command_protection.allow_paths,secretProtection:{enabled:ee.secret_protection.enabled,disabledRules:Oe(ee.secret_protection.overrides),denyPaths:ee.secret_protection.deny_paths,allowPaths:ee.secret_protection.allow_paths}});return Nn(A,{policySnapshot:ce,cwd:V.cwd,userConfigDir:V.userConfigDir},P)}function ay(P,A){if(P===null)return Math.min(Qh,A);let q=Number(P);if(!Number.isInteger(q)||q<1||q>A)return null;return q}function ly(P,A,q){if(A.searchParams.get("token")!==q)return!1;if(P.method!=="POST")return!0;return P.headers["x-cc-safety-net-token"]===q}var cy=1048576;async function Kn(P){let A=[],q=0;for await(let V of P){let ee=V;if(q+=ee.byteLength,q>cy)return{ok:!1,status:413,error:"Request body is too large"};A.push(ee)}try{return{ok:!0,value:JSON.parse(Buffer.concat(A).toString("utf-8")||"{}")}}catch(V){return{ok:!1,status:400,error:`Invalid JSON: ${V instanceof Error?V.message:String(V)}`}}}function dy(P,A){P.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),P.end(A)}function ht(P,A,q){P.writeHead(A,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),P.end(JSON.stringify(q))}function uy(P){return new Promise((A,q)=>{P.close((V)=>V?q(V):A())})}function py(P){return new Promise((A)=>{let q=()=>{process.off("SIGINT",V),process.off("SIGTERM",V)},V=()=>{q(),P.close().then(A)};process.once("SIGINT",V),process.once("SIGTERM",V)})}function fy(P){let A=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",q=process.platform==="win32"?["/c","start","",P]:[P];return new Promise((V,ee)=>{let ne=Od(A,q,{detached:!0,stdio:"ignore"}),ce=(ye)=>{ne.off("spawn",he),ee(ye)},he=()=>{ne.off("error",ce),ne.unref(),V()};ne.once("error",ce),ne.once("spawn",he)})}async function my(P="gh",A=Ti){return{ok:await _i(P,["api","-X","PUT",`/user/starred/${Zr}`],A)===0}}async function gy(P,A={}){let q=await sr(A.fetcher),V=hy(P,q);return{targets:$t.map((ee)=>{let ne=V.find((ce)=>ce.platform===ee.id);return{target:ee.id,label:vt(ee.id),version:q.versions[ee.id]??null,status:ne?.configured?"active":ne?.detected?"disabled":ne?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:q.version,nodeVersion:q.nodeVersion,platform:q.platform}}}function hy(P,A){return Ln(P,process.cwd(),{ampPluginListOutput:A.ampPluginListOutput,codexPluginListOutput:A.codexPluginListOutput,copilotCliVersion:A.versions["copilot-cli"]})}async function yy(P={}){let A=await(P.checkUpdates??Wt)();return{update:{latestVersion:A.latestVersion??null,updateAvailable:A.updateAvailable}}}var Id=Promise.resolve();function vy(P,A,q={}){let V=async()=>{let ne=[],{log:ce,error:he}=console;console.log=(...ye)=>ne.push(ye.map(String).join(" ")),console.error=console.log;try{return{ok:await Bn(P,[],{selectTargets:async()=>[A],output:new Zh({write(be,xe,Ie){ne.push(String(be).replace(/\n$/,"")),Ie()}}),...q})===0,output:ne.join(`
5921
- `)}}finally{console.log=ce,console.error=he}},ee=Id.then(V);return Id=ee.then(()=>{return},()=>{return}),ee}async function by(P,A={}){let[q,V,ee]=await Promise.all([Ly(A.command),wy(A.fetchRepo),Promise.resolve(tr(P,te(P),A.logsDir).totalBlocked)]);return{starred:q,starCount:V,blockedTotal:ee}}async function Ly(P="gh",A=Ti){if(await _i(P,["auth","status"],A)!==0)return null;let q=await _i(P,["api",`/user/starred/${Zr}`],A);if(q===0)return!0;if(q===null)return null;return!1}function _i(P,A,q){return new Promise((V)=>{let ee=Od(P,A,{stdio:"ignore",windowsHide:!0}),ne=!1,ce=setTimeout(()=>{ee.kill(),he(null)},q),he=(ye)=>{if(ne)return;ne=!0,clearTimeout(ce),V(ye)};ee.once("error",()=>he(null)),ee.once("close",he)})}async function wy(P=fetch){try{let A=await P(`https://api.github.com/repos/${Zr}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Ti)});if(!A.ok)return null;let q=await A.json();return typeof q.stargazers_count==="number"?q.stargazers_count:null}catch{return null}}function ky(P){if(P[0]!=="help")return!1;let A=P[1];if(!A)ti(),process.exit(0);if(Mn(A))process.exit(0);console.error(`Unknown command: ${A}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var xy={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),Mn("hook",console.error),process.exit(1)},install:async(P)=>{process.exit(await Bn("install",P))},update:async(P)=>{process.exit(await hi(P))},uninstall:async(P)=>{process.exit(await Bn("uninstall",P))},rule:async(P)=>{process.exit(await kd(c(),P))},policy:async(P)=>{process.exit(await jc(c(),P))},status:async(P)=>{if(Ht(xt({label:"status"},P).errors))process.exit(1);Cd(c())},statusline:async(P)=>{let A=xt({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},P);if(A.errors.length===0&&A.flags.claudeCode){await Pi(c());return}if(Ht(A.errors),!A.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");Mn("statusline",console.error),process.exit(1)},doctor:async(P)=>{let A=Jo(P);if(!A)process.exit(1);let q=await cl(c(),{json:A.json,skipUpdateCheck:A.skipUpdateCheck});process.exit(q)},logs:async(P)=>{process.exit(await Hi(c(),P))},gui:async(P)=>{process.exit(await Fd(P))},explain:async(P)=>{process.exit(await Ll(c(),P))}};async function Cy(P){let A=xt({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},P);if(ky(P))return;let q=P[0],V=q?er(q):void 0;if(A.help&&V&&V.name!=="rule")Mn(V.name),process.exit(0);if(!q||A.help&&!V)ti(),process.exit(0);if(A.flags.version)xl(),process.exit(0);if(V){await xy[V.name](P.slice(1));return}if(q==="--statusline"){await Pi(c());return}console.error(q.startsWith("-")?`Unknown option: ${q}`:`Unknown command: ${q}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Cy as runCli};
5928
+ `;var Ud='<script id="ccsn-data" type="application/json">';function Gd(P){return Hd.replace(Ud,()=>Ud+JSON.stringify({token:P}).replaceAll("<","\\u003c"))}var oo="kenryu42/cc-safety-net",Ly=`https://github.com/${oo}`,Mi=1e4,wy=7,ky="The project draft directory changed; reload the draft before applying.",xy="audit settings are user scope only; remove the audit section from a project proposal";async function Jd(P,A={}){let q=xt({label:"gui",booleans:{noOpen:["--no-open"]}},P),V=A.log??console.log,ee=A.error??console.error;if(q.errors.length>0){for(let ce of q.errors)ee(ce);return ee("Usage: cc-safety-net gui [--no-open]"),1}let ne=await Cy(c,A);if(V(`CC Safety Net policy GUI: ${ne.url}`),!q.flags.noOpen)try{await(A.openBrowser??Oy)(ne.url)}catch(ce){ee(`Failed to open browser: ${ce instanceof Error?ce.message:String(ce)}`),ee(`Open this URL manually: ${ne.url}`)}if(A.keepAlive===!1)return await ne.close(),0;return await $y(ne),0}async function Cy(P,A={}){let q=hy(24).toString("base64url"),V={dir:null,revision:0},ee=vy((he,ye)=>{Sy(P,he,ye,q,A,V)});await new Promise((he,ye)=>{ee.once("error",ye),ee.listen(0,"127.0.0.1",()=>{ee.off("error",ye),he()})});let ce=`http://127.0.0.1:${ee.address().port}`;return{origin:ce,token:q,url:`${ce}/?token=${encodeURIComponent(q)}`,close:()=>Iy(ee)}}async function Sy(P,A,q,V,ee,ne){let ce=P(),he=new URL(A.url??"/","http://127.0.0.1");if(A.method==="GET"&&he.pathname==="/favicon.ico"){q.writeHead(204,{"cache-control":"no-store"}),q.end();return}if(!Ay(A,he,V)){ht(q,403,{error:"Forbidden"});return}if(A.method==="GET"&&he.pathname==="/"){Ty(q,Gd(V));return}if(A.method==="GET"&&he.pathname==="/api/policy"){let ye=Gc(ce,ee),be=E(ce,Ni(ee));ht(q,200,{...ye,configState:Ne(be),...be.policyScopes?{projectPolicy:{path:b(ee.cwd??process.cwd()),weakenings:be.policyScopes.weakenings}}:{},destructiveCommandRules:G,secretPatterns:Ke,version:wt(),preview:ye.errors.length>0?null:Ae(ye.policy,ce.env)});return}if(A.method==="POST"&&he.pathname==="/api/policy/preview"){let ye=await tr(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=Bc(ce,ye.value);ht(q,be.errors.length>0?400:200,be);return}if(A.method==="POST"&&he.pathname==="/api/policy/explain"){let ye=await tr(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=ye.value;if(be===null||typeof be.command!=="string"){ht(q,400,{errors:["command must be a string"]});return}let xe=Yn(be.policy,ce.home);if(xe.length>0){ht(q,400,{errors:xe});return}ht(q,200,Ey(ce,be.command,be.policy,ee));return}if(A.method==="POST"&&he.pathname==="/api/policy"){let ye=await tr(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=Vt(ce,ye.value,ee);ht(q,be.errors.length>0?400:200,be);return}if(A.method==="POST"&&he.pathname==="/api/reset"){ht(q,200,Vt(ce,X,ee));return}if(A.method==="POST"&&he.pathname==="/api/repair"){ht(q,200,qc(ce,ee));return}if(A.method==="POST"&&he.pathname==="/api/policy/project/choose-directory"){let ye=await(ee.chooseDirectory??Fi)();if("path"in ye)ne.dir=ye.path,ne.revision+=1;ht(q,200,{cancelled:"cancelled"in ye,..."error"in ye?{error:ye.error}:{}});return}if(A.method==="GET"&&he.pathname==="/api/policy/project"){let ye=Wd(ne,ee),be=Bd(ye,ce.home),xe=Xn(ce,ee);ht(q,200,{path:b(ye),revision:ne.revision,baseline:xe.baseline,userPolicyDiagnostics:xe.diagnostics,projection:be.projection,projectionDiagnostics:be.diagnostics,canPickDirectory:Oi(process.platform,process.env)});return}if(A.method==="POST"&&he.pathname==="/api/policy/project/diff"){let ye=await qd(ce,A,q,ne,ee);if(!ye)return;let be=Bd(ye.dir,ce.home),xe=Xn(ce,ee).baseline,Ie=Z(xe,ae(ye.proposal,ce.home).policy);ht(q,200,{rows:qr(Z(xe,be.projection).policy,Ie.policy,!1),weakenings:Ie.weakenings,existingFileDiagnostics:be.diagnostics});return}if(A.method==="POST"&&he.pathname==="/api/policy/project/apply"){let ye=await qd(ce,A,q,ne,ee);if(!ye)return;let be=Py(ye.dir,ye.proposal,ce.home);ht(q,be.errors.length>0?500:200,be);return}if(A.method==="GET"&&he.pathname==="/api/activity"){let ye=te(ce,ee),be=Dy(he.searchParams.get("days"),ye);if(be===null){ht(q,400,{error:`days must be an integer between 1 and ${ye}`});return}ht(q,200,Fd(ce,be,ee.activityLogsDir));return}if(A.method==="POST"&&he.pathname==="/api/rules/choose-directory"){ht(q,200,await Fi());return}if(A.method==="GET"&&he.pathname==="/api/rules"){let ye=Y(ce,Ni(ee)),be=new Map(ye.rules.map((xe)=>[xe.name,xe]));ht(q,200,{projectPath:ee.cwd??process.cwd(),canPickDirectory:Oi(process.platform,process.env),rulebooks:ye.rulebooks.map((xe)=>({source:xe.source,spec:xe.spec,name:xe.name,version:xe.version,rules:xe.rules.flatMap((Ie)=>{let Xe=be.get(Ie);if(!Xe)return[];return[{name:Xe.name,command:Xe.command,subcommand:Xe.subcommand,block_args:Xe.block_args,reason:Xe.reason}]})})),errors:ye.errors,warnings:ye.warnings});return}if(A.method==="GET"&&he.pathname==="/api/star/context"){ht(q,200,await(ee.fetchStarContext??(()=>Uy(ce,{logsDir:ee.activityLogsDir})))());return}if(A.method==="POST"&&he.pathname==="/api/star"){let ye=await(ee.starRepo??Fy)();ht(q,200,ye.ok?{ok:!0}:{ok:!1,fallbackUrl:Ly});return}if(A.method==="GET"&&he.pathname==="/api/integrations"){ht(q,200,await(ee.fetchIntegrations??(()=>Ny(ce)))());return}if(A.method==="GET"&&he.pathname==="/api/health"){ht(q,200,await(ee.fetchHealth??My)());return}if(A.method==="POST"&&(he.pathname==="/api/install"||he.pathname==="/api/uninstall")){let ye=await tr(A);if(!ye.ok){ht(q,ye.status,{errors:[ye.error]});return}let be=ye.value?.target;if(typeof be!=="string"||!Ht.some((Ie)=>Ie.target===be)){ht(q,400,{error:"unknown target"});return}let xe=he.pathname==="/api/install"?"install":"uninstall";ht(q,200,await(ee.runIntegration??Hy)(xe,be));return}ht(q,404,{error:"Not found"})}function Ni(P){return{...P,cwd:P.cwd??process.cwd()}}function Wd(P,A){return P.dir??A.cwd??process.cwd()}function Bd(P,A){let q=b(P),V=yy(q)?pn(q):{value:void 0,errors:[]},ee=ae(V.value,A);return{projection:ee.policy,diagnostics:[...V.errors,...ee.diagnostics]}}async function qd(P,A,q,V,ee){let ne=Wd(V,ee),ce=V.revision,he=await tr(A);if(!he.ok)return ht(q,he.status,{errors:[he.error]}),null;let ye=he.value;if(typeof ye?.revision!=="number")return ht(q,400,{errors:["revision must be a number"]}),null;if(ye.revision!==ce)return ht(q,409,{errors:[ky]}),null;let be=Ry(ye.proposal,P.home);if(be.length>0)return ht(q,400,{errors:be}),null;return{dir:ne,proposal:ye.proposal}}function Ry(P,A){let q=Yn(P,A);if(q.length>0)return q;return P?.audit===void 0?[]:[xy]}function Py(P,A,q){let V=b(P),ee=Vr(A,C(A,q));try{return g(i(v(P,"project policy"),V),`${JSON.stringify(ee,null,2)}
5929
+ `),{path:V,errors:[]}}catch(ne){return{path:V,errors:[ne instanceof Error?ne.message:String(ne)]}}}function Ey(P,A,q,V){let ee=C(q,P.home),ne=E(P,Ni(V)),ce=Ee({rules:ne.policy.rules,transparentWrappers:ne.policy.transparentWrappers,safety:De(ee.safety),worktreeMode:ee.workflow.worktree_mode,destructiveCommandProtectionEnabled:ee.destructive_command_protection.enabled,destructiveCommandRuleOverrides:ee.destructive_command_protection.overrides,destructiveCommandAllowPaths:ee.destructive_command_protection.allow_paths,secretProtection:{enabled:ee.secret_protection.enabled,disabledRules:Oe(ee.secret_protection.overrides),denyPaths:ee.secret_protection.deny_paths,allowPaths:ee.secret_protection.allow_paths}});return qn(A,{policySnapshot:ce,cwd:V.cwd,userConfigDir:V.userConfigDir},P)}function Dy(P,A){if(P===null)return Math.min(wy,A);let q=Number(P);if(!Number.isInteger(q)||q<1||q>A)return null;return q}function Ay(P,A,q){if(A.searchParams.get("token")!==q)return!1;if(P.method!=="POST")return!0;return P.headers["x-cc-safety-net-token"]===q}var _y=1048576;async function tr(P){let A=[],q=0;for await(let V of P){let ee=V;if(q+=ee.byteLength,q>_y)return{ok:!1,status:413,error:"Request body is too large"};A.push(ee)}try{return{ok:!0,value:JSON.parse(Buffer.concat(A).toString("utf-8")||"{}")}}catch(V){return{ok:!1,status:400,error:`Invalid JSON: ${V instanceof Error?V.message:String(V)}`}}}function Ty(P,A){P.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),P.end(A)}function ht(P,A,q){P.writeHead(A,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),P.end(JSON.stringify(q))}function Iy(P){return new Promise((A,q)=>{P.close((V)=>V?q(V):A())})}function $y(P){return new Promise((A)=>{let q=()=>{process.off("SIGINT",V),process.off("SIGTERM",V)},V=()=>{q(),P.close().then(A)};process.once("SIGINT",V),process.once("SIGTERM",V)})}function Oy(P){let A=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",q=process.platform==="win32"?["/c","start","",P]:[P];return new Promise((V,ee)=>{let ne=zd(A,q,{detached:!0,stdio:"ignore"}),ce=(ye)=>{ne.off("spawn",he),ee(ye)},he=()=>{ne.off("error",ce),ne.unref(),V()};ne.once("error",ce),ne.once("spawn",he)})}async function Fy(P="gh",A=Mi){return{ok:await ji(P,["api","-X","PUT",`/user/starred/${oo}`],A)===0}}async function Ny(P,A={}){let q=await pr((ee)=>kn({environment:P,cwd:process.cwd(),openCodeVersion:ee}).status!=="n/a",A.fetcher),V=jy(P,q);return{targets:$t.map((ee)=>{let ne=V.find((ce)=>ce.platform===ee.id);return{target:ee.id,label:bt(ee.id),version:q.versions[ee.id]??null,status:ne?.configured?"active":ne?.detected?"disabled":ne?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:q.version,nodeVersion:q.nodeVersion,platform:q.platform}}}function jy(P,A){return xn(P,process.cwd(),{ampPluginListOutput:A.ampPluginListOutput,codexPluginListOutput:A.codexPluginListOutput,copilotCliVersion:A.versions["copilot-cli"],openCodeVersion:A.versions.opencode,openCodePluginListOutput:A.openCodePluginListOutput})}async function My(P={}){let A=await(P.checkUpdates??Wt)();return{update:{latestVersion:A.latestVersion??null,updateAvailable:A.updateAvailable}}}var Vd=Promise.resolve();function Hy(P,A,q={}){let V=async()=>{let ne=[],{log:ce,error:he}=console;console.log=(...ye)=>ne.push(ye.map(String).join(" ")),console.error=console.log;try{return{ok:await Kn(P,[],{selectTargets:async()=>[A],output:new by({write(be,xe,Ie){ne.push(String(be).replace(/\n$/,"")),Ie()}}),...q})===0,output:ne.join(`
5930
+ `)}}finally{console.log=ce,console.error=he}},ee=Vd.then(V);return Vd=ee.then(()=>{return},()=>{return}),ee}async function Uy(P,A={}){let[q,V,ee]=await Promise.all([Gy(A.command),By(A.fetchRepo),Promise.resolve(ar(P,te(P),A.logsDir).totalBlocked)]);return{starred:q,starCount:V,blockedTotal:ee}}async function Gy(P="gh",A=Mi){if(await ji(P,["auth","status"],A)!==0)return null;let q=await ji(P,["api",`/user/starred/${oo}`],A);if(q===0)return!0;if(q===null)return null;return!1}function ji(P,A,q){return new Promise((V)=>{let ee=zd(P,A,{stdio:"ignore",windowsHide:!0}),ne=!1,ce=setTimeout(()=>{ee.kill(),he(null)},q),he=(ye)=>{if(ne)return;ne=!0,clearTimeout(ce),V(ye)};ee.once("error",()=>he(null)),ee.once("close",he)})}async function By(P=fetch){try{let A=await P(`https://api.github.com/repos/${oo}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(Mi)});if(!A.ok)return null;let q=await A.json();return typeof q.stargazers_count==="number"?q.stargazers_count:null}catch{return null}}function qy(P){if(P[0]!=="help")return!1;let A=P[1];if(!A)di(),process.exit(0);if(Vn(A))process.exit(0);console.error(`Unknown command: ${A}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var Vy={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),Vn("hook",console.error),process.exit(1)},install:async(P)=>{process.exit(await Kn("install",P))},update:async(P)=>{process.exit(await xi(P))},uninstall:async(P)=>{process.exit(await Kn("uninstall",P))},rule:async(P)=>{process.exit(await Id(c(),P))},policy:async(P)=>{process.exit(await Wc(c(),P))},status:async(P)=>{if(Ut(xt({label:"status"},P).errors))process.exit(1);Od(c())},statusline:async(P)=>{let A=xt({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},P);if(A.errors.length===0&&A.flags.claudeCode){await $i(c());return}if(Ut(A.errors),!A.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");Vn("statusline",console.error),process.exit(1)},doctor:async(P)=>{let A=ni(P);if(!A)process.exit(1);let q=await Ll(c(),{json:A.json,skipUpdateCheck:A.skipUpdateCheck});process.exit(q)},logs:async(P)=>{process.exit(await Ji(c(),P))},gui:async(P)=>{process.exit(await Jd(P))},explain:async(P)=>{process.exit(await _l(c(),P))}};async function zy(P){let A=xt({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},P);if(qy(P))return;let q=P[0],V=q?sr(q):void 0;if(A.help&&V&&V.name!=="rule")Vn(V.name),process.exit(0);if(!q||A.help&&!V)di(),process.exit(0);if(A.flags.version)$l(),process.exit(0);if(V){await Vy[V.name](P.slice(1));return}if(q==="--statusline"){await $i(c());return}console.error(q.startsWith("-")?`Unknown option: ${q}`:`Unknown command: ${q}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{zy as runCli};