cc-safety-net 2.6.9 → 2.6.11

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,54 +1,55 @@
1
- import{a,s,Pe,Be,R,nt,ze,c,n,Ve,T,v,pe,ot,f,Ke,u,o,S,i,se,r,g,me,H,st,at,d,ge,he,ct,N,Z,ae,w,lt,_,h,ke,W,l,L,X,Je,Ye,M,C,I,ye,be,Ae,ut,m,e,Oe,Re,Ze,Xe,ce,Te,le,De,Q,B,Ne,xe,z,Qe,V,ee,te,ue,et,tt,E,F,Le,Fe,$e,k,je,_e,Ue,y,t,ne,ve,b,x,A,dt,Ge,He,p,q}from"./chunks/index-0kd1ygaw.js";import{oe,K,We,U,G}from"./chunks/index-xrc55d5p.js";var cp=["-h","--help"];function yn(P,O){let D=Object.entries(P.booleans??{}),j=Object.entries(P.values??{}),J=Object.entries(P.lists??{}),Y=Object.fromEntries(D.map(([Se])=>[Se,!1])),re={},ie=Object.fromEntries(J.map(([Se])=>[Se,[]])),de=[],fe=[],we=!1,Ce=-1;for(let[Se,Ie]of O.entries()){if(Se<=Ce)continue;if(Ie==="--"){de.push(...O.slice(Se+1));break}if(cp.includes(Ie)){we=!0;continue}let Ee=D.find(([,en])=>en.includes(Ie));if(Ee){Y[Ee[0]]=!0;continue}let qe=j.find(([,en])=>en.includes(Ie));if(qe){let en=O[Se+1];if(en===void 0||en.startsWith("-")){fe.push(`${Ie} requires a value`);continue}re[qe[0]]=en,Ce=Se+1;continue}let Me=J.find(([,en])=>en.includes(Ie));if(Me){let en=O.slice(Se+1),on=en.findIndex((an)=>an.startsWith("-")),sn=en.slice(0,on===-1?en.length:on);if(sn.length===0){fe.push(`${Ie} requires at least one value`);continue}ie[Me[0]]=[...ie[Me[0]]??[],...sn],Ce=Se+sn.length;continue}if(Ie.startsWith("-")){fe.push(`Unknown option for ${P.label}: ${Ie}`);continue}if(P.positionals==="tail"){de.push(...O.slice(Se));break}de.push(Ie)}if(P.positionals!=="list"&&P.positionals!=="tail")fe.push(...de.map((Se)=>`Unexpected argument for ${P.label}: ${Se}`));return{flags:Y,values:re,lists:ie,positionals:de,help:we,errors:fe}}function Dn(P){for(let O of P)console.error(O);return P.length>0}import{readdirSync as yp,statSync as Ps,unlinkSync as hp}from"node:fs";import{basename as Rs,dirname as vp,isAbsolute as bp,join as wp,relative as kp,resolve as xp,sep as Cp}from"node:path";var xs=(P)=>{let O=Date.now()-new Date(P).getTime();if(!Number.isFinite(O))return"";let D=Math.floor(O/60000),j=Math.floor(D/60),J=Math.floor(j/24);if(J>0)return`${J}d ago`;if(j>0)return`${j}h ago`;if(D>0)return`${D}m ago`;return"just now"},Ro=(P)=>{let O=(P??"").trim().split(/\s+/).filter((J)=>J&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(J)),D=O[0]?.split("/").pop();if(!D)return null;let j=O[1];return j&&/^[a-z][a-z0-9-]*$/.test(j)?`${D} ${j}`:D};function Cs(P){let O=(J)=>`${J.sessionId}
2
- ${Ro(J.segment||J.command)}`,D=P.filter((J)=>J.decision!=="allow"),j=D.filter((J)=>J.sessionId).reduce((J,Y)=>J.set(O(Y),(J.get(O(Y))??0)+1),new Map);return new Set(D.filter((J)=>J.failureStage||(j.get(O(J))??0)>=2))}import{existsSync as dp,readdirSync as up,readFileSync as pp}from"node:fs";import{join as fp}from"node:path";function Kn(P,O){try{return up(P,{withFileTypes:!0,encoding:"utf8"}).flatMap((D)=>{let j=fp(P,D.name);if(D.isDirectory())return Kn(j,O);if(D.name.endsWith(".jsonl"))return[j];return[]})}catch{if(O&&dp(P))O.count++;return[]}}var mp=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function gp(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let O=P;if(typeof O.ts!=="string"||typeof O.command!=="string")return!1;return mp.every((D)=>O[D]===void 0||typeof O[D]==="string")}function kt(P,O){try{return pp(P,"utf-8").split(`
3
- `).filter(Boolean).flatMap((D)=>{try{let j=JSON.parse(D);if(!gp(j)){if(O)O.count++;return[]}return[j]}catch{if(O)O.count++;return[]}})}catch{if(O)O.count++;return[]}}function hn(P){return Array.from(P,(O)=>{let D=O.charCodeAt(0);if(D<=31||D>=127&&D<=159)return`\\x${D.toString(16).padStart(2,"0")}`;return O}).join("")}function Sp(P,O){let D=oe(P),j=yn({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"]}},O);if(Dn(j.errors))return null;if(j.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(j.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let J=j.values.limit===void 0?20:Ss(j.values.limit);if(J===null)return console.error("--limit must be a positive number"),null;let Y=j.values.since===void 0?Math.min(30,D):Ss(j.values.since);if(Y===null||Y>D)return console.error(`--since must be a positive number of days no greater than ${D}`),null;let re={limit:J,limitExplicit:j.values.limit!==void 0,since:Y,sinceExplicit:j.values.since!==void 0,all:j.flags.all,json:j.flags.json,suspect:j.flags.suspect,pruneLegacy:j.flags.pruneLegacy,dryRun:j.flags.dryRun,id:j.values.id,agent:j.values.agent,rule:j.values.rule,session:j.values.session,project:j.values.project===void 0?void 0:xp(j.values.project)};if(re.id&&(re.agent!==void 0||re.rule!==void 0||re.session!==void 0||re.project!==void 0||re.suspect||re.sinceExplicit||re.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(re.pruneLegacy&&(re.id!==void 0||re.agent!==void 0||re.rule!==void 0||re.session!==void 0||re.project!==void 0||re.suspect||re.all||re.sinceExplicit||re.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(re.dryRun&&!re.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return re}async function Es(P,O,D={}){let j=Sp(P,O);if(!j)return 1;let J=D.logsDir??U(P);if(j.pruneLegacy)return Pp(J,j.json,j.dryRun);if(!J)return console.log(j.json?"[]":j.id?`No retained audit log entry found for id ${hn(j.id)}.`:"No audit log entries found."),0;K(P,J);let Y={count:0},re=Kn(J,Y).flatMap((Ce)=>kt(Ce,Y).map((Se)=>({entry:Se,file:Ce})));if(Y.count>0)console.error(`warning: ${Y.count} audit log ${Y.count===1?"source":"sources"} could not be read; these results are incomplete`);if(j.id)return Ap(re,j,D.timeZone);let ie=Date.now()-j.since*24*60*60*1000,de=re.filter((Ce)=>Tp(Ce,j,J,ie)),fe=j.suspect?Cs(de.map((Ce)=>Ce.entry)):null,we=(fe?de.filter((Ce)=>fe.has(Ce.entry)):de).sort((Ce,Se)=>Date.parse(Se.entry.ts)-Date.parse(Ce.entry.ts)).slice(0,j.limit);if(j.json)return console.log(JSON.stringify(we.map((Ce)=>Ce.entry),null,2)),0;if(we.length===0)return console.log("No audit log entries found."),0;for(let Ce of we)console.log(Op(Ce.entry,D.timeZone));return 0}function Pp(P,O,D){let j=P?Ep(P).map((ie)=>wp(P,ie)):[];if(D)return Rp(j,O);let J=[],Y=0,re=0;for(let ie of j){let de=Ps(ie,{throwIfNoEntry:!1})?.size??0,fe=_p(ie);if(fe){J.push(`${Rs(ie)}: ${fe}`);continue}Y++,re+=de}if(O)return console.log(JSON.stringify({removedFiles:Y,removedBytes:re,failedFiles:J.length})),J.length===0?0:1;console.log(Y===0&&J.length===0?"No legacy audit log files found.":`Removed ${Y} legacy audit log ${Y===1?"file":"files"} (${_s(re)}).`);for(let ie of J)console.error(`Could not remove ${hn(ie)}`);if(console.log("Nested v2 audit logs were not changed."),Y>0)console.log("This deletion cannot be undone.");return J.length===0?0:1}function Rp(P,O){let D=P.reduce((j,J)=>j+(Ps(J,{throwIfNoEntry:!1})?.size??0),0);if(O)return console.log(JSON.stringify({dryRun:!0,files:P.length,bytes:D})),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"} (${_s(D)}).`),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 Ep(P){try{return yp(P,{withFileTypes:!0}).filter((O)=>O.isFile()&&O.name.endsWith(".jsonl")).map((O)=>O.name)}catch{return[]}}function _p(P){try{return hp(P),null}catch(O){return O instanceof Error?O.message:String(O)}}function _s(P){let O=["B","KiB","MiB","GiB"],D=Math.min(Math.floor(Math.log2(Math.max(P,1))/10),O.length-1);return`${Math.round(P/1024**D*10)/10} ${O[D]}`}function Ap(P,O,D){let j=P.filter((Y)=>Y.entry.id===O.id);if(j.length>1)return console.error(`Multiple audit log entries found for id ${hn(O.id??"")}.`),1;if(O.json)return console.log(JSON.stringify(j.map((Y)=>Y.entry),null,2)),0;let J=j[0];if(!J)return console.log(`No retained audit log entry found for id ${hn(O.id??"")}.`),0;return console.log(Dp(J.entry,D)),0}function Tp(P,O,D,j){if(!O.all&&P.entry.decision==="allow")return!1;if(Date.parse(P.entry.ts)<j)return!1;if(O.agent!==void 0&&P.entry.agent!==O.agent)return!1;if(O.rule!==void 0&&P.entry.ruleId!==O.rule)return!1;if(O.session!==void 0&&!Ip(P,D,O.session))return!1;if(O.project!==void 0&&!$p(P.entry.cwd,O.project))return!1;return!0}function Ip(P,O,D){if(P.entry.sessionId===D)return!0;return vp(P.file)===O&&Rs(P.file,".jsonl")===D}function $p(P,O){if(!P)return!1;let D=kp(O,P);return D!==".."&&!D.startsWith(`..${Cp}`)&&!bp(D)}function Op(P,O){let D=hn(P.id??"-"),j=hn(P.decision??"deny"),J=P.cwd?` [${hn(P.cwd)}]`:"",Y=P.segment||P.command,re=Y===P.command?"":"↳ ",ie=Y.length>50?`${Y.slice(0,50)}…`:Y;return`${D.padEnd(16)} ${hn(As(P.ts,O))} ${j.padEnd(5)} ${hn(P.agent??"-").padEnd(15)} ${hn(P.ruleId??"-").padEnd(20)} ${re}${hn(ie)}${J}`}function Dp(P,O){let D=(J)=>hn(J===void 0||J===null||J===""?"-":J),j=P.shape?`${P.agent??"-"} (shape: ${P.shape})`:P.agent??"-";return[`id: ${D(P.id)}`,`ts: ${D(As(P.ts,O))}`,`decision: ${D(P.decision)}`,`agent: ${D(j)}`,`level: ${D(P.level)}`,`tool: ${D(P.toolName)}`,`rule: ${D(P.ruleId)}`,`intent: ${D(P.intent)}`,`stage: ${D(P.failureStage)}`,`error: ${D(P.errorCode)}`,`session: ${D(P.sessionId)}`,`cwd: ${D(P.cwd)}`,`version: ${D(P.v)}`,`truncated: ${D(P.truncated===!0?"yes":void 0)}`,`reason: ${D(P.reason)}`,`command: ${D(P.command)}`,`segment: ${D(P.segment)}`].join(`
4
- `)}function As(P,O){let D=new Date(P);if(Number.isNaN(D.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:O}).format(D)}function Ss(P){let O=Number(P);return Number.isFinite(O)&&O>0?O:null}var Ts={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 Is={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 $s={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 Eo=["npx","--offline","--no-install","@deepseek-ai/dsh","--version"],Os=["cursor-agent","--version"],mr=[{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:10,runtime:{order:8,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:10,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:9,runtime:{order:7,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:9,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:11,runtime:{order:9,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:11,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:12,runtime:{order:10,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:12,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:13,runtime:{order:11,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:13,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:14,install:{order:14,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:15,install:{order:15,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:16,install:{order:16,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:"deepseek-harness",displayName:"DeepSeek Harness",doctorOrder:6,install:{order:6,flag:"--deepseek-harness",artifactKind:"package",probeCommand:Eo}},{id:"devin",displayName:"Devin CLI",doctorOrder:7,runtime:{order:5,flags:["-dv","--devin"],description:"Run as Devin CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:7,flag:"--devin",artifactKind:"hook config",probeCommand:["devin","--version"]}},{id:"droid",displayName:"Factory Droid",doctorOrder:8,runtime:{order:6,flags:["-fd","--droid"],description:"Run as Factory Droid PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--droid",artifactKind:"hook config",probeCommand:["droid","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],gr=mr.slice().sort((P,O)=>P.doctorOrder-O.doctorOrder).map((P)=>P.id),Ht=mr.filter((P)=>("runtime"in P)).slice().sort((P,O)=>P.runtime.order-O.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})),En=mr.slice().sort((P,O)=>P.install.order-O.install.order).map((P)=>({id:P.id,...P.install})).map(({order:P,...O})=>O),Lp=Object.fromEntries(mr.map((P)=>[P.id,P.displayName]));function mn(P){return Lp[P]}var Np=Ht.map((P)=>({flags:P.flags.join(", "),description:P.description})),jp=Ht.flatMap((P)=>P.flags.map((O)=>`cc-safety-net hook ${O}`)),Ds={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Np,{flags:"-h, --help",description:"Show this help"}],examples:jp};var Ls={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...En.map((P)=>({flags:P.flag,description:`Install ${mn(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...En.map((P)=>`cc-safety-net install ${P.flag}`)]},Ns={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...En.map((P)=>({flags:P.flag,description:`Uninstall ${mn(P.id)} ${P.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...En.map((P)=>`cc-safety-net uninstall ${P.flag}`)]},js={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 Fs={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 yr={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 _o=[{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"}],Ao=["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"],xt={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"},..._o.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",...Ao,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var Hs={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 Ms={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 hr=[Hs,Ts,Fs,Is,xt,yr,Ls,js,Ns,Ds,$s,Ms];function Fp(P){return P.aliases??[]}function vr(P){let O=P.toLowerCase();return hr.find((D)=>D.name.toLowerCase()===O||Fp(D).some((j)=>j.toLowerCase()===O))}import{existsSync as xy}from"node:fs";import{basename as Hp}from"node:path";function br(P,O=7,D=U(P)){let j=Date.now()-O*24*60*60*1000,J=[],Y=new Set,re=0,ie,de,fe,we;if(D)K(P,D);let Ce={count:0},Se=D?Kn(D,Ce):[];for(let Ee of Se)for(let qe of kt(Ee,Ce)){if(qe.decision==="allow")continue;let Me=new Date(qe.ts).getTime();if(Me>=j){if(re++,Y.add(qe.sessionId??Hp(Ee,".jsonl")),de===void 0||Me<=de)ie=qe.ts,de=Me;if(we===void 0||Me>we)fe=qe.ts,we=Me;Mp(J,qe,Me)}}let Ie=J.map((Ee)=>({timestamp:Ee.ts,command:Ee.command,reason:Ee.reason,relativeTime:xs(new Date(Ee.ts))}));return{totalBlocked:re,sessionCount:Y.size,recentEntries:Ie,oldestEntry:ie,newestEntry:fe,unreadable:Ce.count}}function Mp(P,O,D){let j=P.findIndex((J)=>D>new Date(J.ts).getTime());if(j===-1){if(P.length<3)P.push(O);return}if(P.splice(j,0,O),P.length>3)P.pop()}import{dirname as Xp}from"node:path";import{dirname as Up,join as Gp,resolve as qp}from"node:path";var Bp="config.json";function wn(P,O,D,j){g(Vp(P),`${JSON.stringify(O,null,2)}
5
- `,D,j)}function Vp(P){return typeof P==="string"?se(P):P}function Io(P){return{errors:ce(Kp(P),": "," "),ruleNames:new Set(De(P).map((O)=>O.toLowerCase()))}}var Jp="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",Us="must match pattern (letters, numbers, hyphens, underscores)";function Kp(P){if(!Gs(P))return[e([],"Config must be an object")];return[...P.version===1?[]:[e(["version"],"must be 1")],...Wp(P.rules)]}function Wp(P){if(P===void 0)return[];if(!Array.isArray(P))return[e(["rules"],"must be an array")];return[...P.flatMap((O,D)=>Gs(O)?zp(O,["rules",D]):[e(["rules",D],"must be an object")]),...Oe(P)]}function zp(P,O){return[...To(P.name,[...O,"name"],"required string",d,Jp),...To(P.command,[...O,"command"],"required string",C,Us),...P.subcommand===void 0?[]:To(P.subcommand,[...O,"subcommand"],"must be a string if provided",C,Us),...Yp(P.block_args,[...O,"block_args"]),...Zp(P.reason,[...O,"reason"]),...P.intent===void 0||Te(P.intent)?[]:[e([...O,"intent"],Re)]]}function To(P,O,D,j,J){if(typeof P!=="string")return[e(O,D)];return j.test(P)?[]:[e(O,J)]}function Yp(P,O){if(!Array.isArray(P))return[e(O,"required array")];if(P.length===0)return[e(O,"must have at least one element")];return P.flatMap((D,j)=>{if(typeof D!=="string")return[e([...O,j],"must be a string")];return D===""?[e([...O,j],"must not be empty")]:[]})}function Zp(P,O){if(typeof P!=="string")return[e(O,"required string")];if(P==="")return[e(O,"must not be empty")];return P.length>I?[e(O,`must be at most ${I} characters`)]:[]}function Gs(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function $o(P){let O=qs(P);if(!O.ok)return O.result;return Io(O.parsed)}function qs(P){let O=[],D=new Set;try{let j=typeof P==="string"?se(P):P,J=r(j);if(J===null)return O.push(`File not found: ${j.path}`),{ok:!1,result:{errors:O,ruleNames:D}};if(!J.trim())return O.push("Config file is empty"),{ok:!1,result:{errors:O,ruleNames:D}};return{ok:!0,parsed:JSON.parse(J)}}catch(j){if(j instanceof o)return O.push(j.message),{ok:!1,result:{errors:O,ruleNames:D}};let J=j instanceof Error?j.message:String(j);return O.push(j instanceof SyntaxError?"Invalid JSON":J),{ok:!1,result:{errors:O,ruleNames:D}}}}function wr(P){return qp(P,".safety-net.json")}function Un(P){let O=qs(P);if(!O.ok)return O.result;let D=Ze(O.parsed);return{errors:D.errors,ruleNames:D.sources}}function Ct(P,O={}){return Gp(Up(ke(P,O)),Bp)}function Bs(P,O,D){let j;try{if(r(O)===null)return{path:P,exists:!1,valid:!1,ruleCount:0};j=Un(O),j.errors.push(...B(P,D))}catch(J){if(!(J instanceof o))throw J;j={errors:[J.message],ruleNames:new Set}}return{path:P,exists:!0,valid:j.errors.length===0,ruleCount:j.ruleNames.size,...j.errors.length>0?{errors:j.errors}:{}}}function Qp(P,O){return{source:O,name:P.name,command:P.command,subcommand:P.subcommand,blockArgs:[...P.block_args],reason:P.reason}}function Vs(P,O){let D=W(P),j=_(O),J=Xp(D),Y=Q(P,{cwd:O,userConfigPath:D,projectConfigPath:j,userConfigDir:J}),re=X(P,{cwd:O,userConfigPath:D,projectConfigPath:j,userConfigDir:J}),ie=new Map(Y.rulebooks.flatMap((de)=>de.rules.map((fe)=>[fe,de.source])));return{userConfig:Bs(D,re.userConfigTarget,re.userScope),projectConfig:Bs(j,re.projectConfigTarget,re.projectScope),effectiveRules:Y.rules.map((de)=>Qp(de,ie.get(de.name)??"project"))}}var ef=[{flag:n.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:n.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:n.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:n.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:n.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:n.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:n.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:n.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"},{flag:n.projectTightenOnly,description:"Ignore project policy settings that weaken the user policy",defaultBehavior:"off"}];function Js(P){return[...ef.map((O)=>({name:O.flag.name,value:pe(O.flag,P.env),isSet:ot(O.flag,P.env),legacyName:O.flag.legacyName,legacyValue:O.flag.legacyName?P.env.get(O.flag.legacyName):void 0,legacyIsSet:O.flag.legacyName?P.env.get(O.flag.legacyName)!==void 0:void 0,description:O.description,defaultBehavior:O.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 Ks={error:0,warning:1,info:2},nf=["policy","config","audit"];function tf(P){return P.map((O)=>{if(O==="ownership")return"is not owned by the current user";if(O==="permissions")return"has unsafe permissions";if(O==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var rf=[{derive:(P)=>P.hooks.length>0&&P.hooks.every((O)=>!O.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((O)=>O.inspectionStatus==="failed").map((O)=>{let D=mn(O.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${D} inspection failed`,detail:`Doctor could not verify the ${D} integration configuration.`,fixHint:`Correct the reported ${D} configuration error, then run \`cc-safety-net doctor\` again.`,integration:O.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)=>P.legacyConfigs&&P.legacyConfigs.length>0?[{checkId:"config.legacy-ignored",severity:"warning",title:"Legacy inline rule configs are ignored",detail:`CC Safety Net no longer loads these files, so their rules enforce nothing: ${P.legacyConfigs.join(", ")}.`,fixHint:"Run `cc-safety-net rule migrate` to convert them (add `--cleanup` to delete each file once it is converted), then rerun doctor."}]:[]},{derive:(P)=>{let O=P.environment.find((D)=>D.name==="CC_SAFETY_NET_AUDIT_SCOPE");return Ve(O?.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."}]:[]}},...nf.map((P)=>({derive:(O)=>O.posture.directories.filter((D)=>D.kind===P&&D.status==="unsafe").map((D)=>({checkId:`posture.${P}-directory-unsafe`,severity:"error",title:`${P[0]?.toUpperCase()}${P.slice(1)} directory is unsafe`,detail:`The ${P} directory ${tf(D.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...D.path?{path:D.path}:{}}))})),{derive:(P)=>{let O=[...P.effectiveSafety.weakenedRuleOverrides].sort();return O.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: ${O.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${O.join(", ")}.`}]:[]}}];function Ws(P){return rf.flatMap((O,D)=>O.derive(P).map((j,J)=>({finding:j,catalogOrder:D,occurrence:J}))).sort((O,D)=>Ks[O.finding.severity]-Ks[D.finding.severity]||O.catalogOrder-D.catalogOrder||O.occurrence-D.occurrence).map((O)=>O.finding)}function Ln(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var of=(P)=>Ln()?`\x1B[32m${P}\x1B[0m`:P,sf=(P)=>Ln()?`\x1B[33m${P}\x1B[0m`:P,af=(P)=>Ln()?`\x1B[34m${P}\x1B[0m`:P,lf=(P)=>Ln()?`\x1B[36m${P}\x1B[0m`:P,cf=(P)=>Ln()?`\x1B[31m${P}\x1B[0m`:P,df=(P)=>Ln()?`\x1B[2m${P}\x1B[0m`:P,uf=(P)=>Ln()?`\x1B[1m${P}\x1B[0m`:P,nn={green:of,yellow:sf,blue:af,cyan:lf,red:cf,dim:df,bold:uf},pf="\x1B[0m",ff=[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 mf(P){let O=P;return()=>(O=(O*1664525+1013904223)%4294967296,O/4294967296)}function gf(P){let O=[...ff],D=mf(P);for(let j=O.length-1;j>0;j--){let J=Math.floor(D()*(j+1)),Y=O[j];O[j]=O[J],O[J]=Y}return O}function yf(P,O=0){if(!Ln())return"";let D=gf(O);return`\x1B[38;5;${D[P%D.length]}m`}function zs(P,O,D=0){if(!Ln())return`"${P}"`;return`${yf(O,D)}"${P}"${pf}`}function kr(P){return P==="default"?"built-in default":`${P} policy`}var hf=new RegExp("\x1B\\[[0-9;]*m","g"),Oo=(P)=>P.replace(hf,"").length;function Wn(P){let O=(P.headers??P.rows[0]??[]).map((re,ie)=>{let de=Math.max(...P.rows.map((fe)=>Oo(fe[ie]??"")));return Math.max(Oo(re),de)}),D=(re,ie)=>re+" ".repeat(Math.max(0,ie-Oo(re))),j=(re,ie)=>ie[0]+O.map((de)=>re.repeat(de+2)).join(ie[1])+ie[2],J=(re)=>`│ ${re.map((ie,de)=>D(ie,O[de]??0)).join(" │ ")} │`,Y=P.headers?[` ${J(P.headers)}`,` ${j("─",["├","┼","┤"])}`]:[];return[` ${j("─",["┌","┬","┐"])}`,...Y,...P.rows.map((re)=>` ${J(re)}`),` ${j("─",["└","┴","┘"])}`].join(`
6
- `)}function Ys(P){let O=[];O.push("Hook Integration"),O.push(vf(P));let D=[],j=[];for(let J of P){let Y=mn(J.platform);if(J.errors&&J.errors.length>0)for(let re of J.errors)if(J.configured)D.push({platform:Y,message:re});else j.push({platform:Y,message:re})}for(let J of D)O.push(` Warning (${J.platform}): ${J.message}`);for(let J of j)O.push(nn.red(` Error (${J.platform}): ${J.message}`));return O.join(`
7
- `)}function vf(P){let O=["Platform","Discovery","Configuration","Inspection"],D=P.map((j)=>{let J=mn(j.platform);if(j.inspectionStatus==="not-inspected"){let de=nn.dim("Not inspected");return[J,de,de,de]}let Y=j.detected?nn.green("Detected"):j.inspectionStatus==="failed"?nn.red("Unknown"):nn.dim("Not detected"),re=j.configured?nn.green("Configured"):j.detected?nn.yellow("Not configured"):j.inspectionStatus==="failed"?nn.red("Unknown"):nn.dim("Not applicable"),ie=j.inspectionStatus==="verified"?nn.green("Verified"):j.inspectionStatus==="failed"?nn.red("Failed"):nn.dim("Not applicable");return[J,Y,re,ie]});return Wn({headers:O,rows:D})}function Zs(P){let D=["Guard Engine Verification",` Synthetic self-test: ${P.failed>0?nn.red(`${P.passed}/${P.total} FAIL`):nn.green(`${P.passed}/${P.total} passed`)}`],j=P.results.filter((J)=>!J.passed);if(j.length>0){D.push(""),D.push(nn.red(" Failures:"));for(let J of j)D.push(nn.red(` • ${J.description}`)),D.push(nn.red(` expected ${J.expected}, got ${J.actual}`))}return D.join(`
8
- `)}function bf(P){if(P.length===0)return" (no custom rules)";let O=["Source","Name","Command","Block Args"],D=P.map((j)=>[j.source,j.name,j.subcommand?`${j.command} ${j.subcommand}`:j.command,j.blockArgs.join(", ")]);return Wn({headers:O,rows:D})}function Xs(P){let O=[];if(O.push("Configuration"),O.push(wf(P.userConfig,P.projectConfig)),O.push(""),P.effectiveRules.length>0)O.push(` Effective rules (${P.effectiveRules.length} total):`),O.push(bf(P.effectiveRules));else O.push(" Effective rules: (none - using built-in rules only)");return O.join(`
9
- `)}function wf(P,O){let D=["Scope","Status"],j=(Y)=>{if(!Y.exists)return nn.dim("N/A");if(!Y.valid)return nn.red(`Invalid (${Y.errors?.[0]??"unknown error"})`);return nn.green("Configured")},J=[["User",j(P)],["Project",j(O)]];return Wn({headers:D,rows:J})}function Qs(P){let O=[];return O.push("Environment"),O.push(kf(P)),O.join(`
10
- `)}function ea(P){let O=P.effectiveSafety.policyScopes,D=["Effective Safety",` Selected preset: ${P.effectiveSafety.selectedPreset}${O?` (${kr(O.levelScope)})`:""}`,` Effective: ${P.effectiveSafety.level}`],j=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[J,Y]of j){let re=P.effectiveSafety.capabilities[J],ie=re.enabled?nn.green("ON"):nn.dim("OFF"),de=re.sources.length>0?` (${re.sources.join(", ")})`:"";D.push(` ${Y}: ${ie} via ${re.source}${de}`)}if(O&&O.weakenings.length>0){D.push(` Project policy deltas${O.weakeningsIgnored?" (ignored)":""}:`);for(let J of O.weakenings)D.push(` ${J}`)}D.push(` Stored rule customizations: ${P.effectiveSafety.ruleCounts.stored}`),D.push(` Effective rule customizations: ${P.effectiveSafety.ruleCounts.effective}`);for(let[J,Y]of Object.entries(P.effectiveSafety.ruleOverrides))D.push(` ${J}: ${Y}`);return D.join(`
11
- `)}function na(P){let O=["Findings"];if(P.length===0)return O.push(" No findings from inspected doctor facts."),O.join(`
12
- `);for(let D of P){let j=`[${D.severity.toUpperCase()}] ${D.checkId}: ${hn(D.title)}`,J=D.severity==="error"?nn.red:D.severity==="warning"?nn.yellow:nn.blue;if(O.push(` ${J(j)}`),O.push(` ${hn(D.detail)}`),D.path)O.push(` Path: ${hn(D.path)}`);if(D.fixHint)O.push(` Fix: ${hn(D.fixHint)}`)}return O.join(`
13
- `)}function kf(P){let O=["Variable","Status","Legacy"],D=P.map((j)=>{let J=j.isSet?nn.green("✓"):nn.dim("✗"),Y=j.legacyName&&j.legacyIsSet?`${j.legacyName} ${nn.green("✓")}`:j.legacyName??"";return[j.name,J,Y]});return Wn({headers:O,rows:D})}function ta(P){let O=[];if(P.totalBlocked===0)O.push("Recent Activity"),O.push(" No blocked commands in the last 7 days"),O.push(" Tip: This is normal for new installations");else O.push(`Recent Activity · last 7 days (${P.totalBlocked} blocked / ${P.sessionCount} sessions)`),O.push(xf(P.recentEntries));if(P.unreadable>0)O.push(` Warning: ${P.unreadable} audit log ${P.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return O.join(`
14
- `)}function xf(P){let O=["Time","Command"],D=P.map((j)=>{let J=hn(j.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),Y=J.length>40?`${J.slice(0,37)}...`:J;return[j.relativeTime,Y]});return Wn({headers:O,rows:D})}function ra(P){let O=[];if(O.push("Update Check"),P.latestVersion===null&&!P.error)return O.push(xr([["Status",nn.dim("Skipped")],["Installed",P.currentVersion]])),O.join(`
15
- `);if(P.error)return O.push(xr([["Status",`${nn.yellow("⚠")} Error`],["Installed",P.currentVersion],["Error",nn.dim(P.error)]])),O.join(`
16
- `);if(P.updateAvailable)return O.push(xr([["Status",`${nn.yellow("⚠")} Update Available`],["Current",P.currentVersion],["Latest",nn.green(P.latestVersion??"")]])),O.push(""),O.push(" Run: bunx cc-safety-net@latest doctor"),O.push(" Or: npx cc-safety-net@latest doctor"),O.join(`
17
- `);return O.push(xr([["Status",`${nn.green("✓")} Up to date`],["Version",P.currentVersion]])),O.join(`
18
- `)}function xr(P){return Wn({rows:P})}function oa(P){let O=[];return O.push("System Info"),O.push(Cf(P)),O.join(`
19
- `)}function Cf(P){let O=["Component","Version"],D=(Y)=>{if(Y===null)return nn.dim("not found");return Y},J=[{label:"cc-safety-net",value:P.version},...gr.map((Y)=>({label:mn(Y),value:P.versions[Y]??null})),{label:"Node.js",value:P.nodeVersion},{label:"npm",value:P.npmVersion},{label:"Bun",value:P.bunVersion},{label:"Platform",value:P.platform}].map((Y)=>[Y.label,D(Y.value)]);return Wn({headers:O,rows:J})}function ia(P){if(P.findings.length===0)return nn.green(`
20
- No findings from inspected doctor facts.`);let O={error:P.findings.filter((Y)=>Y.severity==="error").length,warning:P.findings.filter((Y)=>Y.severity==="warning").length,info:P.findings.filter((Y)=>Y.severity==="info").length},D=["error","warning","info"].filter((Y)=>O[Y]>0).map((Y)=>`${O[Y]} ${Y}`),j=P.findings.length===1?"finding":"findings",J=`
21
- ${P.findings.length} ${j}: ${D.join(", ")}.`;if(O.error>0)return nn.red(J);if(O.warning>0)return nn.yellow(J);return nn.blue(J)}import{lstatSync as Sf}from"node:fs";import{dirname as Do}from"node:path";function Lo(P,O){try{let D=Sf(O);if(D.isSymbolicLink())return{kind:P,path:O,status:"unsafe",issues:["symlink"]};if(!D.isDirectory())return{kind:P,path:O,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:P,path:O,status:"unknown",issues:[]};let j=[...D.uid!==process.getuid()?["ownership"]:[],...(D.mode&18)!==0?["permissions"]:[]];return{kind:P,path:O,status:j.length>0?"unsafe":"safe",issues:j}}catch(D){if(typeof D==="object"&&D!==null&&"code"in D&&D.code==="ENOENT")return{kind:P,path:O,status:"not-applicable",issues:[]};return{kind:P,path:O,status:"unknown",issues:[]}}}function sa(P,O){let D=U(P);return{directories:[Lo("policy",Do(Do(O))),Lo("config",Do(O)),...D?[Lo("audit",D)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as Pf}from"node:child_process";import{existsSync as aa}from"node:fs";import{delimiter as Rf,extname as Ef,join as _f}from"node:path";import{stripVTControlCharacters as la}from"node:util";var da="2.6.9",Af=5000,Tf="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function pn(){return da}function No(P,O){let D=P[O];if(D)return D;let j=Object.keys(P).find((J)=>J.toLowerCase()===O.toLowerCase()&&!!P[J]);return j?P[j]:D}function If(P){return(No(P,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((O)=>O.length>0)}function $f(P,O){let D=Ef(P)?[P]:[...If(O).map((j)=>`${P}${j}`),P];if(P.includes("/")||P.includes("\\"))return D.find((j)=>aa(j))??P;return(No(O,"PATH")??"").split(Rf).flatMap((j)=>D.map((J)=>_f(j,J))).find((j)=>aa(j))??P}function ca(P){if(!/[\s"&|<>^]/.test(P))return P;return`"${P.replace(/"/g,'""')}"`}function zn(P,O){let[D,...j]=P,J=O[Tf]==="win32"?"win32":process.platform;if(!D||J!=="win32")return{cmd:D??"",args:j};let Y=$f(D,O);if(!/\.(?:bat|cmd)$/i.test(Y))return{cmd:Y,args:j};return{cmd:No(O,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",ca(Y),...j.map(ca)].join(" ")]}}var St=async(P,O=Af)=>{let D=await Of(P,{timeoutMs:O});if(D.code!==0)return null;return la(D.stdout).trim()||la(D.stderr).trim()||null};function Of(P,O){let[D,...j]=P;if(!D)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((J)=>{try{let Y=zn([D,...j],process.env),re=Pf(Y.cmd,Y.args,{stdio:["ignore","pipe","pipe"]}),ie=!1,de="",fe="";re.stdout.on("data",(Se)=>{de+=Se.toString()}),re.stderr.on("data",(Se)=>{fe+=Se.toString()});let we=(Se)=>{if(ie)return;ie=!0,clearTimeout(Ce),J(Se)},Ce=setTimeout(()=>{re.kill(),we({code:null,stdout:de,stderr:fe})},O.timeoutMs);re.on("close",(Se)=>{we({code:Se,stdout:de,stderr:fe})}),re.on("error",()=>{we({code:null,stdout:de,stderr:fe})})}catch{J({code:null,stdout:"",stderr:""})}})}function Cr(P){if(!P)return null;let O=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(P);if(O)return O[1]??null;let D=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(P);if(D)return D[1]??null;return P.split(`
22
- `)[0]?.trim()||null}async function Sr(P,O=St,D=process.cwd()){let j=Promise.all(En.map(async(Ce)=>[Ce.id,Cr(await O([...Ce.probeCommand]))])),[J,Y,re,ie,de,fe,we]=await Promise.all([j,j.then(async(Ce)=>{let Se=Ce.find(([qe])=>qe==="opencode")?.[1];if(!Se?.startsWith("2.")||!P(Se))return null;let Ie=["--param",`location[directory]=${D}`],Ee=["opencode","api","integration.list",...Ie];return await O(Ee,30000),O(["opencode","api","plugin.list",...Ie],30000)}),O(["codex","plugin","list"],30000),O(["amp","plugins","list"],30000),O(["node","--version"]),O(["npm","--version"]),O(["bun","--version"])]);return{version:da,versions:Object.fromEntries(J),codexPluginListOutput:re,ampPluginListOutput:ie,openCodePluginListOutput:Y,nodeVersion:Cr(de),npmVersion:Cr(fe),bunVersion:Cr(we),platform:`${process.platform} ${process.arch}`}}function jo(P,O){if(O==="dev")return!1;let D=P.split(".").map(Number),j=O.split(".").map(Number),[J=0,Y=0,re=0]=D,[ie=0,de=0,fe=0]=j;if(J!==ie)return J>ie;if(Y!==de)return Y>de;return re>fe}async function Gn(){let P=pn(),O=new AbortController,D=setTimeout(()=>O.abort(),3000);try{let j=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:O.signal});if(!j.ok)return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${j.status}`};let J=await j.json(),Y=jo(J.version,P);return{currentVersion:P,latestVersion:J.version,updateAvailable:Y}}catch(j){return{currentVersion:P,latestVersion:null,updateAvailable:!1,error:j instanceof Error?j.message:"Network error"}}finally{clearTimeout(D)}}import*as va from"node:readline";var ma=(P)=>`\x1B[${P}B`,Df=(P)=>`\x1B[${P}A`;var ua=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function Lf(P){return new Promise((O)=>setTimeout(O,P))}function Nf(P,O,D){if(!D)return O(P);if(D.aborted)return Promise.resolve();return new Promise((j,J)=>{let Y=()=>D.removeEventListener("abort",re),re=()=>{Y(),j()};D.addEventListener("abort",re,{once:!0}),O(P).then(()=>{Y(),j()},(ie)=>{Y(),J(ie)})})}function Pr(P){return Math.max(0,Math.min(1,P))}function Pt(P){return Math.max(0,Math.min(255,Math.round(P)))}function Fo(P){return P<=0.0031308?12.92*P:1.055*P**0.4166666666666667-0.055}function jf(P,O,D){let j=D*Math.PI/180,J=O*Math.cos(j),Y=O*Math.sin(j),re=(P+0.3963377774*J+0.2158037573*Y)**3,ie=(P-0.1055613458*J-0.0638541728*Y)**3,de=(P-0.0894841775*J-1.291485548*Y)**3;return{blue:Pt(Fo(Pr(-0.0041960863*re-0.7034186147*ie+1.707614701*de))*255),green:Pt(Fo(Pr(-1.2684380046*re+2.6097574011*ie-0.3413193965*de))*255),red:Pt(Fo(Pr(4.0767416621*re-3.3077115913*ie+0.2309699292*de))*255)}}function Ho(P,O){let D=(O*P*180/Math.PI%360+360)%360;return jf(0.72,0.15,D)}function ga(P,O=0.1){let D=Ho(O,P);return`\x1B[38;2;${D.red};${D.green};${D.blue}m`}function Ff(P,O){return{blue:Pt(P.blue+(255-P.blue)*O),green:Pt(P.green+(255-P.green)*O),red:Pt(P.red+(255-P.red)*O)}}function ya(P,O,D){let j=Math.imul(P+2654435769,2246822507)^Math.imul(O+3266489909,668265263)^Math.imul(D+374761393,2654435761),J=j^j>>>15,Y=Math.imul(J,739982445),re=Y^Y>>>12,ie=Math.imul(re,695872825);return((ie^ie>>>15)>>>0)/4294967296}function Hf(P,O,D){let j=Math.floor(ya(P,O,D)*ua.length);return ua[j]??"░"}function pa(P){let O=Pr(P);return O*O*O*(O*(O*6-15)+10)}function Mf(P){if(P.length===0)return"";let O=[],D=!1,j="";for(let J of P){let Y=`${J.red};${J.green};${J.blue}`;if(J.bold!==D)O.push(J.bold?"\x1B[1m":"\x1B[22m"),D=J.bold;if(Y!==j)O.push(`\x1B[38;2;${Y}m`),j=Y;O.push(J.character)}return`${O.join("")}\x1B[22m\x1B[39m`}function Uf(P,O,D,j,J){return P.map((Y,re)=>({...Ho(D,j+O+re/J),bold:!1,character:Y}))}function Gf(P,O,D,j,J,Y,re,ie){let de=Math.max(1,j*0.75),fe=Math.min(1,D/de),we=J*pa(fe),Ce=Math.max(0,(D-de)/Math.max(1,j-de)),Se=(1-pa(D/j))*ie*2,Ie=0.35*Math.max(0,1-Ce*2),Ee=fe>=1,qe=Math.min(P.length,Math.ceil(we+2+1));return P.slice(0,qe).map((Me,en)=>{let on=Ho(Y,re+O+en/ie+Se),sn=en+ya(O,en,7919)*2-1;if(sn>we+2)return{...on,bold:!1,character:" "};let an=we-sn,rn=0.8*Math.exp(-(an*an)/12.5),fn=Math.min(0.9,rn+Ie),On=!Ee&&sn>we-4;return{...Ff(on,fn),bold:fn>0.3,character:On?Hf(O,en,D):Me}})}function fa(P){return`\x1B[?2026h${P.map((O,D)=>`\x1B8${D>0?ma(D):""}${Mf(O)}`).join("")}\x1B[?2026l`}async function Mo(P,O={}){if(!P)return;let D=O.output??process.stdout,j=O.sleep??Lf,J=O.seed??0,Y=P.split(`
23
- `).map((we)=>Array.from(we)),re=Math.max(...Y.map((we)=>we.length)),ie=12000*Y.filter((we)=>we.length>0).length/40,de=re>0?Math.max(1,Math.ceil(ie/16.666666666666668)):0,fe=de>0?ie/de:0;D.write(`\x1B[?25l${Y.length>1?`${`
24
- `.repeat(Y.length-1)}${Df(Y.length-1)}`:""}\x1B7`);try{for(let we=1;we<=de;we+=1){if(O.signal?.aborted)break;D.write(fa(Y.map((Ce,Se)=>Gf(Ce,Se,we,de,re,0.1,J,3)))),await Nf(fe,j,O.signal)}}finally{if(D.write(fa(Y.map((we,Ce)=>Uf(we,Ce,0.1,J,3)))),D.write("\x1B8"),Y.length>1)D.write(ma(Y.length-1));D.write(`
25
- \x1B[0m\x1B[?25h`)}}var ha=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
- `);function qf(P){return Boolean(P.isTTY)}async function Mt(P={}){let O=P.output??process.stdout;if(!qf(O))return;let D=P.input??process.stdin,j={output:O,seed:P.seed??Math.random()*8192,sleep:P.sleep};if(!D.isTTY||typeof D.setRawMode!=="function"){await Mo(ha,j);return}let J=new AbortController,Y=D.readableFlowing===!0,re=D.isRaw===!0,ie=!1,de=(fe,we)=>{if(we.ctrl&&we.name==="c")ie=!0;if(ie||we.name==="return"||we.name==="enter")J.abort()};va.emitKeypressEvents(D),D.on("keypress",de),D.setRawMode(!0),D.resume();try{await Mo(ha,{...j,signal:J.signal})}finally{if(D.off("keypress",de),D.setRawMode(re),!Y)D.pause()}if(!ie)return;if(P.onInterrupt){P.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Wf}from"node:crypto";import{existsSync as ka}from"node:fs";import{dirname as Rr,join as xa}from"node:path";import{dirname as ba,join as Bf,resolve as Vf}from"node:path";var Jf="rule.lock";function Kf(P){return Bf(ba(P),Jf)}function wa(P={}){return Vf(P.cwd??process.cwd(),".safety-net.json")}function kn(P,O){let D=O.global?O.userConfigPath??W(P,O):O.projectConfigPath??_(O.cwd??process.cwd()),j=O.global?Je(P,O):Ye(D,O.cwd??process.cwd()),J=Kf(D);return{configDir:ba(D),configPath:D,lockPath:J,filesystemScope:j,configTarget:i(j,D),lockTarget:i(j,J)}}var zf="`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.",Yf="cache",Zf="rulebooks";function Ca(P,O={}){let D=kn(P,O),j=i(D.filesystemScope,Pa(D.configDir)),J=r(D.lockTarget);if(console.log(zf),J===null&&!ka(j.path))return console.log(`No v2 lock or cache leftovers found in ${Rr(D.configDir)}; nothing to migrate.`),0;let Y=tm(J),re=m(D.configTarget);if(!re.config&&(r(D.configTarget)!==null||Y.size>0))return console.error(`Cannot migrate: the rules config in ${Rr(D.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let ie=re.config?.rules??[];for(let de of ie.flatMap((fe)=>Xf(fe,Y,D,j,O.global===!0)))console.log(de);return H(D.lockTarget),st(j),console.log(`Removed the v2 lock and cache under ${Rr(D.configDir)}.`),0}function Sa(P,O){return[...new Set([{cwd:O},{cwd:O,global:!0}].flatMap((D)=>{let j=kn(P,D);return[j.lockPath,Pa(j.configDir)]}))].filter((D)=>ka(D))}function Xf(P,O,D,j,J){if(!w(P))return[];let Y=N(P).name,re=i(D.filesystemScope,M(D.configDir,Y)),ie=r(re);if(ie!==null&&Qf(ie,Y))return[];let de=O.get(P),fe=de?em(de,Y,j.path,D.filesystemScope):null;if(fe===null)return[`Could not migrate ${P} from the v2 cache. Run \`cc-safety-net rule update ${P}${J?" --global":""}\` to vendor it.`];if(g(re,fe),ie!==null)return[`Restored ${P} from the v2 cache over an invalid file.`];return[`Vendored ${P} from the v2 cache.`]}function Qf(P,O){let D=xe(P);return!("problem"in D)&&D.rulebook.name===O}function em(P,O,D,j){let J=xa(D,Zf,`${nm(P)}--${P.digest.replace("sha256:","").slice(0,12)}`,ge),Y=r(i(j,J));if(Y===null||im(Y)!==P.digest)return null;let re=xe(Y);if("problem"in re||re.rulebook.name!==O)return null;return Y}function Pa(P){return xa(Rr(P),Yf)}function nm(P){return([P.owner,P.repo,P.display_ref,P.name].every((j)=>typeof j==="string"&&j!=="")?`${P.owner}/${P.repo}#${P.display_ref}/${P.name}`:P.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function tm(P){let O=P===null?null:om(P),D=Ra(O)&&Array.isArray(O.rulebooks)?O.rulebooks:[];return new Map(D.filter(rm).map((j)=>[j.spec,j]))}function rm(P){return Ra(P)&&typeof P.spec==="string"&&typeof P.digest==="string"}function Ra(P){return!!P&&typeof P==="object"}function om(P){try{return JSON.parse(P)}catch{return null}}function im(P){return`sha256:${Wf("sha256").update(P).digest("hex")}`}var Ea="\r\x1B[2K",sm="\x1B[?25l",am="\x1B[39m",lm="\x1B[?25h",cm=100,dm=0.55,um=80,_a=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function pm(P){return new Promise((O)=>setTimeout(O,P))}async function Er(P,O={}){let D=O.output??process.stdout;if(!D.isTTY)return P;let j=O.sleep??pm,J=!1,Y=P.then((ie)=>(J=!0,ie),(ie)=>{throw J=!0,ie});if(await Promise.race([Y.then(()=>!0),j(cm).then(()=>!1)]))return Y;D.write(sm);try{for(let ie=0;!J;ie+=1)D.write(`${Ea}${ga(ie*dm)}${_a[ie%_a.length]}${am} ${O.loadingMessage??"Loading…"}`),await Promise.race([Y,j(um)]);return await Y}finally{D.write(`${Ea}${lm}`)}}async function Ut(P,O,D,j={}){let J=O();if(P)await D();if(P&&J.ready)await Er(J.ready,j);return J.finish()}import{stripVTControlCharacters as fm}from"node:util";var _r="amp plugins list",mm=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Aa(P){if(!P.ampPluginListOutput)return{platform:"amp",status:"n/a"};let O=fm(P.ampPluginListOutput).split(`
27
- `).map((D)=>mm.exec(D)?.[1]).find((D)=>D!==void 0);if(!O)return{platform:"amp",status:"n/a"};if(O!=="active")return{platform:"amp",status:"disabled",method:_r,configPath:_r,errors:[`Amp personal plugin cc-safety-net is ${O}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:_r,configPath:_r}}import{existsSync as bm,readFileSync as wm}from"node:fs";import{isAbsolute as rC,join as vm}from"node:path";function Gt(P){return vm(P,".gemini","config","hooks.json")}var km=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function xm(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];return Object.values(P).flatMap((O)=>{if(!O||typeof O!=="object"||Array.isArray(O))return[];let D=O,j=D.PreToolUse;if(!Array.isArray(j))return[];return j.flatMap((J)=>{if(!J||typeof J!=="object"||Array.isArray(J))return[];let Y=J.hooks;if(!Array.isArray(Y))return[];return Y.flatMap((re)=>{if(!re||typeof re!=="object"||Array.isArray(re))return[];let ie=re.command;if(typeof ie!=="string"||!km.test(ie))return[];return[{command:ie,enabled:D.enabled!==!1}]})})})}function Ta(P){let O=Gt(P.environment.home);if(!bm(O))return{platform:"antigravity-cli",status:"n/a",configPath:O};let D;try{D=xm(JSON.parse(wm(O,"utf-8")))}catch(j){return{platform:"antigravity-cli",status:"n/a",configPath:O,errors:[`Failed to parse Antigravity hooks config ${O}: ${j instanceof Error?j.message:String(j)}`]}}if(D.some((j)=>j.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:O};if(D.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:O};return{platform:"antigravity-cli",status:"n/a",configPath:O}}import{existsSync as Em}from"node:fs";import{join as qt}from"node:path";import{existsSync as Cm,lstatSync as Sm,readFileSync as Pm}from"node:fs";import{join as Rm}from"node:path";function xn(P,O=(D)=>D){if(!Cm(P))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(O(Pm(P,"utf-8")))}}catch{return{kind:"unreadable"}}}function Nn(P,O){if(P==="~")return O;if(P.startsWith("~/")||P.startsWith("~\\"))return Rm(O,P.slice(2));return P}function dn(P){try{return Sm(P)}catch{return}}function Ar(P,O){let D=dn(O);if(!D)return{platform:P,status:"n/a",configPath:O};if(!D.isSymbolicLink()&&D.isDirectory())return;return{platform:P,status:"n/a",configPath:O,errors:[`${O} is a symlink or not a directory; move or remove it before installing`]}}function tn(P,O){return typeof P==="object"&&P!==null?P[O]:void 0}var Tr="cc-safety-net@cc-marketplace";function Ir(P){return P.env.get("CLAUDE_CONFIG_DIR")||qt(P.home,".claude")}function Uo(P){return qt(Ir(P),"plugins","installed_plugins.json")}function Ia(P,O){let D=tn(tn(P,"plugins"),O);return Array.isArray(D)&&D.length>0}function $r(P,O){let D=xn(Uo(P));return D.kind==="ok"&&Ia(D.value,O)}function Or(P){let O=Uo(P),D=xn(O);if(D.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(D.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!Ia(D.value,Tr))return{platform:"claude-code",status:"n/a"};let j=qt(Ir(P),"settings.json"),J=xn(j);if(J.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(J.kind==="ok"&&tn(tn(J.value,"enabledPlugins"),Tr)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:j,errors:[`${Tr} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:O}}function $a(P){if(Or(P).status!=="configured")return;let O=xn(Uo(P)),D=O.kind==="ok"?tn(tn(O.value,"plugins"),Tr):void 0,j=(Array.isArray(D)?D:[]).filter((ie)=>tn(ie,"scope")==="user").map((ie)=>tn(ie,"installPath")).find((ie)=>typeof ie==="string");if(!j)return;let J=qt(j,".cursor-plugin","plugin.json"),Y=xn(J),re=Y.kind==="ok"?tn(Y.value,"hooks"):void 0;return typeof re==="string"&&Em(qt(j,re))?J:void 0}function Oa(P){return Or(P.environment)}var Da="Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it.";function La(P){if(!P.codexPluginListOutput)return{platform:"codex",status:"n/a"};let O=P.codexPluginListOutput.split(`
28
- `).find((D)=>D.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!O)return{platform:"codex",status:"n/a"};if(!O.includes("installed,"))return{platform:"codex",status:"n/a"};if(!O.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 jr,readdirSync as _m,readFileSync as Am}from"node:fs";import{join as bn}from"node:path";function vn(P){let O="",D=0,j=!1,J=!1,Y=-1;while(D<P.length){let re=P[D],ie=P[D+1];if(J){O+=re,J=!1,D++;continue}if(re==='"'&&!j){j=!0,Y=-1,O+=re,D++;continue}if(re==='"'&&j){j=!1,O+=re,D++;continue}if(re==="\\"&&j){J=!0,O+=re,D++;continue}if(j){O+=re,D++;continue}if(re==="/"&&ie==="/"){while(D<P.length&&P[D]!==`
29
- `)D++;continue}if(re==="/"&&ie==="*"){D+=2;while(D<P.length-1){if(P[D]==="*"&&P[D+1]==="/"){D+=2;break}D++}continue}if(re===","){Y=O.length,O+=re,D++;continue}if(re==="}"||re==="]"){if(Y!==-1){let de=O.slice(Y+1);if(/^\s*$/.test(de))O=O.slice(0,Y)+de}Y=-1,O+=re,D++;continue}if(!/\s/.test(re))Y=-1;O+=re,D++}return O}function ja(P,O,D){let j=O+1,J=!1;while(j<P.length){if(J){J=!1,j++;continue}if(P[j]==="\\"){J=!0,j++;continue}if(P[j]==='"')return j+1;j++}throw Error(D)}function qo(P,O,D){let j=P[O],J=j==="["?"]":"}",Y=0,re=O;while(re<P.length){let ie=D.skipComment?.(P,re)??re;if(ie!==re){re=ie;continue}if(P[re]==='"'){re=ja(P,re,D.stringError);continue}if(P[re]===j)Y++;if(P[re]===J){if(Y--,Y===0)return re}re++}throw Error(D.bracketError)}function Fa(P,O){let D=P.lastIndexOf(`
30
- `,O)+1;return/^[ \t]*/.exec(P.slice(D))?.[0]??""}function Ha(P,O){let D=O.end+(/^\s*/.exec(P.slice(O.end))?.[0].length??0);if(P[D]===","){let re=P[D+1]===`
31
- `?D+2:D+1;return`${P.slice(0,O.start)}${P.slice(re)}`}let j=P.slice(0,O.start).search(/\s*$/)-1;if(P[j]!==",")return`${P.slice(0,O.start)}${P.slice(O.end)}`;let J=P.lastIndexOf(`
32
- `,j-1),Y=J!==-1&&/^\s*$/.test(P.slice(J+1,j))?J:j;return`${P.slice(0,Y)}${P.slice(O.end)}`}function Go(P,O){if(P.startsWith("//",O)){let D=P.indexOf(`
33
- `,O+2);return D===-1?P.length:D+1}if(P.startsWith("/*",O)){let D=P.indexOf("*/",O+2);return D===-1?P.length:D+2}return O}function Na(P,O){let D=O;while(D<P.length){if(/\s/.test(P[D]??"")){D++;continue}let j=Go(P,D);if(j===D)return D;D=j}return D}function Ma(P,O,D){let j=0,J=0;while(J<P.length){let Y=Go(P,J);if(Y!==J){J=Y;continue}if(P[J]==='"'){let re=ja(P,J,D.stringError);if(j===1&&JSON.parse(P.slice(J,re))===O){let ie=Na(P,re),de=Na(P,ie+1);if(P[ie]===":"&&P[de]==="[")return{start:de,end:qo(P,de,{skipComment:Go,...D})}}J=re;continue}if(P[J]==="{"||P[J]==="[")j++;if(P[J]==="}"||P[J]==="]")j--;J++}return}var An="cc-safety-net@cc-marketplace",Dr=["cc-marketplace","cc-safety-net"],Ua=["_direct","copilot-safety-net"],Ga=["cc-marketplace","safety-net"],qa="safety-net@cc-marketplace";function Lr(P,O){let D=O.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${D}([^a-z0-9-]|$)`,"m").test(P??"")}function Ba(P){return Lr(P,"cc-safety-net@cc-marketplace")}function Va(P){return Lr(P,"cc-marketplace")}function Ja(P){return Lr(P,"copilot-safety-net")}function Ka(P){return Lr(P,"safety-net@cc-marketplace")}function Nr(P){if(!P?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(P)}function za(P,O){if(!P)return null;let D=P.match(/(\d+)\.(\d+)\.(\d+)/);if(!D)return null;let j=[Number(D[1]),Number(D[2]),Number(D[3])];for(let J=0;J<O.length;J++){let Y=j[J]??0,re=O[J]??0;if(Y!==re)return Y>re}return!0}function Tm(P){return za(P,[0,0,422])}function Im(P){return za(P,[1,0,8])}function Vt(P){return P.env.get("COPILOT_HOME")||bn(P.home,".copilot")}function Bo(P){return(P.hooks?.preToolUse??[]).some((D)=>{if(D.type!==void 0&&D.type!=="command")return!1;return Nr(D.command)||Nr(D.bash)||Nr(D.powershell)||Nr(D.exec&&[D.exec,...D.args??[]].join(" "))})}function Bt(P){return P===void 0||typeof P==="string"}function $m(P){return P===void 0||Array.isArray(P)&&P.every((O)=>typeof O==="string")}function Om(P){if(!P||typeof P!=="object"||Array.isArray(P))return!1;let O=P;if(O.disableAllHooks!==void 0&&typeof O.disableAllHooks!=="boolean")return!1;if(O.hooks===void 0)return!0;if(!O.hooks||typeof O.hooks!=="object"||Array.isArray(O.hooks))return!1;let D=O.hooks.preToolUse;if(D===void 0)return!0;return Array.isArray(D)&&D.every((j)=>j!==null&&typeof j==="object"&&!Array.isArray(j)&&Bt(j.type)&&Bt(j.command)&&Bt(j.bash)&&Bt(j.powershell)&&Bt(j.exec)&&$m(j.args))}function Vo(P,O){try{let D=JSON.parse(vn(Am(P,"utf-8")));if(!Om(D)){O?.push(`Invalid hook config ${P}: hooks.preToolUse must be an array of hook objects`);return}return D}catch(D){O?.push(`Failed to parse ${P}: ${D instanceof Error?D.message:String(D)}`);return}}function Ya(P,O){try{return _m(P).filter((D)=>D.endsWith(".json")).sort((D,j)=>D.localeCompare(j))}catch(D){return O?.push(`Failed to read ${P}: ${D instanceof Error?D.message:String(D)}`),[]}}function Dm(P,O){if(!jr(P))return[];let D=[];for(let j of Ya(P,O)){let J=bn(P,j),Y=Vo(J,O);if(Y&&Bo(Y))D.push(J)}return D}function Rt(P,O){if(!jr(P))return;let D=Vo(P,O);if(!D)return;return{path:P,config:D}}function Wa(P,O,D,j){if(O){P.push(`GitHub Copilot CLI ${O} does not support ${D}; requires ${j}+`);return}P.push(`GitHub Copilot CLI version unavailable; skipping ${D} because it requires ${j}+`)}function Lm(P){for(let O of P){if(O?.config.disableAllHooks===!0)return O.path;if(O?.config.disableAllHooks===!1)return}return}function Nm(P,O,D,j){let J=Vt(P),Y=bn(O,".github","hooks"),re=bn(J,"hooks"),ie=bn(O,".github","copilot"),de=bn(O,".claude"),fe=Im(D),we=fe===!0?j:void 0,Ce=[Rt(bn(ie,"settings.local.json"),we),Rt(bn(ie,"settings.json"),we),Rt(bn(de,"settings.local.json"),we),Rt(bn(de,"settings.json"),we)],Se=[Rt(bn(J,"settings.json"),we),Rt(bn(J,"config.json"),we)];if(fe!==!1){let an=Lm([...Ce,...Se]);if(an){if(fe===null)j.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${an} as active`);return{activeConfigPaths:[],repoInlineSources:Ce,disabledBy:an}}}let Ie=Dm(Y,j),Ee=Tm(D),qe=Ee===!0?j:void 0,Me=jr(re)?Ya(re,qe):[],en=[];for(let an of Me){let rn=bn(re,an),fn=Vo(rn,qe);if(fn&&Bo(fn))en.push(rn)}if(Ee!==!0&&en.length>0)Wa(j,D,`user hook files in ${re}`,"0.0.422"),en.length=0;let on=[];for(let an of[...Ce,...Se]){if(!an)continue;if(!Bo(an.config))continue;if(fe===!0){on.push(an);continue}Wa(j,D,"inline hook definitions in Copilot config files","1.0.8");break}let sn=(an)=>an.filter((rn)=>!!rn&&on.includes(rn)).map((rn)=>rn.path);return{activeConfigPaths:[...sn(Ce),...Ie,...sn(Se),...en],repoInlineSources:Ce}}function Za(P){let O=[],D=Nm(P.environment,P.cwd,P.copilotCliVersion,O);if(D.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:D.disabledBy,configPaths:[D.disabledBy],errors:O.length>0?O:void 0};let j=Vt(P.environment),J=bn(j,"installed-plugins",...Dr),Y=jr(J),re=bn(j,"settings.json"),ie=xn(re,vn),de=(Ie)=>tn(tn(Ie,"enabledPlugins"),An),fe=D.repoInlineSources.find((Ie)=>typeof de(Ie?.config)==="boolean"),we=fe??(ie.kind==="ok"?{path:re,config:ie.value}:void 0);if(Y&&!fe&&ie.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};let Ce=Y&&we!==void 0&&de(we.config)===!1;if(Ce&&D.activeConfigPaths.length===0)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:we.path,errors:[`${An} is installed but not enabled in Copilot CLI`]};let Se=Y&&!Ce;if(Se||D.activeConfigPaths.length>0){let Ie=D.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:Se?"plugin config":"hook config",configPath:Ie??(Se?J:void 0),configPaths:D.activeConfigPaths.length>0?D.activeConfigPaths:void 0,errors:O.length>0?O:void 0}}return{platform:"copilot-cli",status:"n/a",errors:O.length>0?O:void 0}}import{existsSync as Qo,readdirSync as Ym,readFileSync as Zm}from"node:fs";import{join as Xo}from"node:path";import{existsSync as Yo,mkdirSync as qm,readFileSync as Bm,rmSync as Vm}from"node:fs";import{dirname as Jm,join as Fr}from"node:path";import{existsSync as jm,renameSync as Fm,statSync as Hm,writeFileSync as Mm}from"node:fs";function cn(P,O){let D=`${P}.${process.pid}.tmp`;Mm(D,O,jm(P)?{mode:Hm(P).mode&511}:{}),Fm(D,P)}import{spawn as Um}from"node:child_process";function Gm(P){return P.join(" ")}function Jo(P,O,D){return[`Failed to run ${Gm(P)}${O===null?"":` (exit ${O})`}.`,D.trim()].filter(Boolean).join(`
34
- `)}function Ko(P){let O={stdout:"",stderr:""};return P.stdout.setEncoding("utf-8"),P.stderr.setEncoding("utf-8"),P.stdout.on("data",(D)=>{O.stdout+=D}),P.stderr.on("data",(D)=>{O.stderr+=D}),O}function gn(P,O){return new Promise((D,j)=>{let J=zn([...P],process.env),Y=Um(J.cmd,J.args,{stdio:["ignore","pipe","pipe"]}),re=Ko(Y),ie=()=>[re.stdout,re.stderr].filter(Boolean).join(`
35
- `),de=O?.timeoutMs??120000,fe=setTimeout(()=>{Y.kill(),j(Error(Jo(P,null,`Timed out after ${de}ms.
36
- ${ie()}`.trim())))},de);Y.on("error",(we)=>{clearTimeout(fe),j(Error(Jo(P,null,`${we.message}
37
- ${ie()}`.trim())))}),Y.on("close",(we)=>{if(clearTimeout(fe),we!==0){j(Error(Jo(P,we,ie())));return}D(O?.stdoutOnly?re.stdout:ie())})})}async function Wo(P){for(let O of P)await gn(O)}async function Xa(P){for(let O of P)try{await gn(O)}catch(D){console.warn(D instanceof Error?D.message:String(D))}}var Cn=Object.fromEntries(Ht.map((P)=>[P.id,`npx -y cc-safety-net hook ${P.flags[1]}`]));var Kt=Cn.cursor,Qa=30;function Mr(P){return Fr(P.home,".cursor","hooks.json")}var Jt="cc-safety-net";function Zo(P){let O=Fr(P.home,".cursor","plugins");return{cache:Fr(O,"cache",Jt),marketplaceClone:Fr(O,"marketplaces","github.com","kenryu42","cc-safety-net")}}async function el(P){let O=Object.values(Zo(P));if(!O.some((j)=>Yo(j)))return;let D="No marketplace matches";return await gn(["cursor-agent","plugin","marketplace","remove",Jt]).catch((j)=>{if(!(j instanceof Error&&j.message.includes(D)))throw j}),O.forEach((j)=>Vm(j,{recursive:!0,force:!0})),[`Removed the ${Jt} marketplace from your Cursor account.`,"If /plugins in cursor-agent still lists CC Safety Net as installed, uninstall it there."].join(`
38
- `)}function Yn(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function zo(){return{command:Kt,timeout:Qa,failClosed:!0}}function Hr(P){return Yn(P)&&P.command===Kt}function Km(P){return Object.keys(P).length===3&&P.command===Kt&&P.timeout===Qa&&P.failClosed===!0}function Wm(P){try{return JSON.parse(Bm(P,"utf-8"))}catch(O){if(O instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${P}: ${O.message}`);throw O}}function nl(P){let O=Wm(P);if(!Yn(O))throw Error(`Cursor hooks config ${P} must be a JSON object`);if(O.version!==1)throw Error(`Cursor hooks config ${P} must set "version": 1`);if(O.hooks!==void 0&&!Yn(O.hooks))throw Error(`Cursor hooks config ${P} "hooks" must be an object`);let D=Yn(O.hooks)?O.hooks.preToolUse:void 0;if(D!==void 0&&!Array.isArray(D))throw Error(`Cursor hooks config ${P} "hooks.preToolUse" must be an array`);return O}function tl(P){let O=Yn(P.hooks)?P.hooks.preToolUse:void 0;return Array.isArray(O)?O:[]}function zm(P){if(!P.some(Hr))return[...P,zo()];return P.reduce((O,D)=>{if(!Hr(D))return O.result.push(D),O;if(!O.inserted)O.result.push(zo()),O.inserted=!0;return O},{result:[],inserted:!1}).result}function rl(P,O,D){let j=Yn(O.hooks)?O.hooks:{},J={...O,hooks:{...j,preToolUse:D}};cn(P,`${JSON.stringify(J,null,2)}
39
- `)}function ol(P){let O=Mr(P);if(!Yo(O))return qm(Jm(O),{recursive:!0}),cn(O,`${JSON.stringify({version:1,hooks:{preToolUse:[zo()]}},null,2)}
40
- `),{path:O,alreadyInstalled:!1};let D=nl(O),j=tl(D),J=j.filter(Hr);if(Yn(D.hooks)&&Array.isArray(D.hooks.preToolUse)&&J.length===1&&J[0]!==void 0&&Km(J[0]))return{path:O,alreadyInstalled:!0};return rl(O,D,zm(j)),{path:O,alreadyInstalled:!1}}function il(P){let O=Mr(P);if(!Yo(O))return{path:O,alreadyInstalled:!1};let D=nl(O),j=tl(D),J=j.filter((Y)=>!Hr(Y));if(J.length===j.length)return{path:O,alreadyInstalled:!1};return rl(O,D,J),{path:O,alreadyInstalled:!0}}function Xm(P){if(!P||typeof P!=="object"||Array.isArray(P))return[];let O=P.hooks;if(!O||typeof O!=="object"||Array.isArray(O))return[];let D=O.preToolUse;if(!Array.isArray(D))return[];return D.filter((j)=>!!j&&typeof j==="object"&&!Array.isArray(j)&&j.command===Kt)}function Qm(P){let O=[];if(P.length>1)O.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let D=P[0];if(D&&D.failClosed!==!0)O.push('Managed hook is missing "failClosed": true; reinstall to repair');if(D&&D.timeout!==30)O.push('Managed hook "timeout" is not 30; reinstall to repair');return O}var Ur="Claude Code plugin",ei="Cursor plugin";function eg(P){let O=Xo(Zo(P).cache,Jt);if(!Qo(O))return{};try{return{version:Ym(O).map((D)=>Xo(O,D)).find((D)=>Qo(Xo(D,".cache-complete")))}}catch{return{unreadable:O}}}function ng(P,O){if(O){let J=["Cursor records enabled plugins on your Cursor account, which doctor cannot check, and keeps a plugin's files after it is uninstalled.","Cursor pins marketplace plugins to the commit they were added at, so `cc-safety-net update` cannot update this plugin, while the npx hook (`cc-safety-net install --cursor`) stays current."].join(" ");return{method:ei,configPath:O,duplicate:`The Cursor plugin also runs this check, so every tool call is checked twice. ${J} If the plugin is installed, run \`cc-safety-net uninstall --cursor\`, uninstall CC Safety Net from /plugins in cursor-agent, then run \`cc-safety-net install --cursor\`.`,alone:`${J} If /plugins in cursor-agent does not list CC Safety Net as installed, run \`cc-safety-net install --cursor\`.`}}let D=$a(P);if(!D)return;let j="Cursor runs the Claude Code plugin only while it imports Claude Code plugins, which doctor cannot check.";return{method:Ur,configPath:D,duplicate:`The Claude Code plugin also runs this check in Cursor, so every tool call is checked twice. ${j} If Cursor runs it, run \`cc-safety-net uninstall --cursor\` to remove this hook.`,alone:`${j} If it stops, run \`cc-safety-net install --cursor\`.`}}function sl(P){let O=tg(P),D=eg(P.environment);if(D.unreadable)return O.status==="configured"?{...O,errors:[...O.errors??[],`Cannot read ${D.unreadable}, so doctor cannot tell whether the Cursor plugin also runs this check.`]}:{platform:"cursor",status:"not-inspected"};let j=ng(P.environment,D.version);if(!j)return O;if(O.status==="configured")return{...O,errors:[...O.errors??[],j.duplicate]};return{platform:"cursor",status:"configured",method:j.method,configPath:j.configPath,errors:[...O.errors??[],j.alone]}}function tg(P){let O=Mr(P.environment);if(!Qo(O))return{platform:"cursor",status:"n/a",configPath:O};let D;try{D=JSON.parse(Zm(O,"utf-8"))}catch(Y){return{platform:"cursor",status:"n/a",configPath:O,errors:[`Failed to parse Cursor hooks config ${O}: ${Y instanceof Error?Y.message:String(Y)}`]}}let j=Xm(D);if(j.length===0)return{platform:"cursor",status:"n/a",configPath:O};let J=Qm(j);return{platform:"cursor",status:"configured",method:"hook config",configPath:O,errors:J.length>0?J:void 0}}import{readdirSync as rg}from"node:fs";import{join as ni,resolve as og}from"node:path";var ti="cc-safety-net";function ri(P){let O=P.env.get("DSH_HOME");return ni(O?.trim()?og(Nn(O,P.home)):ni(P.home,".dsh"),"profiles")}function al(P){let O=ri(P),D=dn(O)?.isDirectory()?rg(O,{withFileTypes:!0}).filter((J)=>J.isDirectory()&&J.name!=="node_modules").map((J)=>{let Y=ni(O,J.name,"package.json");return{name:J.name,configPath:Y,manifest:xn(Y)}}):[];return{installed:D.flatMap((J)=>{if(J.manifest.kind!=="ok")return[];let Y=J.manifest.value;if(tn(tn(Y,"dependencies"),ti)===void 0)return[];let re=tn(tn(tn(Y,"dsh"),"profile"),"bundles");return[{name:J.name,configPath:J.configPath,enabled:Array.isArray(re)&&re.includes(ti)}]}),unreadable:D.some((J)=>J.manifest.kind==="unreadable")}}function oi(P){return al(P).installed}function ll(P){let O=al(P.environment),D=O.installed.filter((Y)=>Y.enabled),j=O.installed.filter((Y)=>!Y.enabled),J=j.map((Y)=>`${ti} is installed in the ${Y.name} profile but its bundle is disabled`);if(D.length>0)return{platform:"deepseek-harness",status:"configured",method:"dsh bundle",configPaths:D.map((Y)=>Y.configPath),...J.length>0?{errors:J}:{}};if(j.length>0)return{platform:"deepseek-harness",status:"disabled",method:"dsh bundle",configPaths:j.map((Y)=>Y.configPath),errors:J};return O.unreadable?{platform:"deepseek-harness",status:"not-inspected"}:{platform:"deepseek-harness",status:"n/a"}}import{existsSync as dg}from"node:fs";import{existsSync as ul,mkdirSync as ig,readFileSync as sg}from"node:fs";import{dirname as ag,join as ai}from"node:path";function ii(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function si(P,O){return ii(P)&&P.command===O}function cl(P,O){return ii(P)&&Array.isArray(P.hooks)&&P.hooks.some((D)=>si(D,O))}function Zn(P,O){return{hooks:[{type:"command",command:P,timeout:O}]}}function jn(P,O){return P.flatMap((D)=>{if(!ii(D)||!Array.isArray(D.hooks))return[D];let j=D.hooks.filter((J)=>!si(J,O));if(j.length===D.hooks.length)return[D];return j.length===0?[]:[{...D,hooks:j}]})}function Et(P,O,D){let j=P.filter((J)=>cl(J,O));return j.length===1&&JSON.stringify(j[0])===JSON.stringify(Zn(O,D))}function _t(P,O){return P.find((D)=>cl(D,O))}function At(P,O,D){let j=Array.isArray(P.hooks)?P.hooks.find((J)=>si(J,O)):void 0;return[...P.matcher===void 0||P.matcher===""||P.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...j?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...j?.timeout===D?[]:[`Managed hook "timeout" is not ${D}; reinstall to repair`]]}var Xn=Cn.devin,Gr=30,lg={config:{},hooks:{},preToolUse:[]};function qr(P,O=process.platform){let D=O==="win32"?P.env.get("APPDATA")||ai(P.home,"AppData","Roaming"):P.env.get("XDG_CONFIG_HOME")||ai(P.home,".config");return ai(D,"devin","config.json")}function dl(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function cg(P){try{return{ok:!0,value:JSON.parse(vn(sg(P,"utf-8")))}}catch(O){return{ok:!1,message:O instanceof Error?O.message:String(O)}}}function li(P){let O=cg(P);if(!O.ok)return`Failed to parse Devin CLI config ${P}: ${O.message}`;let D=O.value;if(!dl(D))return`Devin CLI config ${P} must be a JSON object`;let j=D.hooks===void 0?{}:D.hooks;if(!dl(j))return`Devin CLI config ${P} "hooks" must be an object`;let J=j.PreToolUse===void 0?[]:j.PreToolUse;if(!Array.isArray(J))return`Devin CLI config ${P} "hooks.PreToolUse" must be an array`;return{config:D,hooks:j,preToolUse:J}}function pl(P){let O=li(P);if(typeof O==="string")throw Error(O);return O}function fl(P,O,D){let j={...O.config,hooks:{...O.hooks,PreToolUse:D}};cn(P,`${JSON.stringify(j,null,2)}
41
- `)}function ml(P){let O=qr(P),D=ul(O)?pl(O):lg;if(Et(D.preToolUse,Xn,Gr))return{path:O,alreadyInstalled:!0};return ig(ag(O),{recursive:!0}),fl(O,D,[...jn(D.preToolUse,Xn),Zn(Xn,Gr)]),{path:O,alreadyInstalled:!1}}function gl(P){let O=qr(P);if(!ul(O))return{path:O,alreadyInstalled:!1};let D=pl(O),j=jn(D.preToolUse,Xn);if(JSON.stringify(j)===JSON.stringify(D.preToolUse))return{path:O,alreadyInstalled:!1};return fl(O,D,j),{path:O,alreadyInstalled:!0}}function yl(P){let O=qr(P.environment);if(!dg(O))return{platform:"devin",status:"n/a",configPath:O};let D=li(O);if(typeof D==="string")return{platform:"devin",status:"n/a",configPath:O,errors:[D]};let j=_t(D.preToolUse,Xn);if(!j)return{platform:"devin",status:"n/a",configPath:O};let J=At(j,Xn,Gr);return{platform:"devin",status:"configured",method:"hook config",configPath:O,errors:J.length>0?J:void 0}}import{existsSync as yg,readFileSync as hg}from"node:fs";import{existsSync as Br,mkdirSync as ug,readFileSync as pg,rmSync as fg}from"node:fs";import{dirname as mg,join as hl}from"node:path";var Qn=Cn.droid,Vr=30;function Jr(P){return hl(P.home,".factory","hooks.json")}function vl(P){return hl(P.home,".factory","settings.json")}function ci(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function bl(P){try{return JSON.parse(pg(P,"utf-8"))}catch(O){if(O instanceof SyntaxError)throw Error(`Failed to parse Factory Droid hooks config ${P}: ${O.message}`);throw O}}function wl(P){let O=bl(P);if(!ci(O))throw Error(`Factory Droid hooks config ${P} must be a JSON object`);if(O.PreToolUse===void 0||Array.isArray(O.PreToolUse))return O;throw Error(`Factory Droid hooks config ${P} "PreToolUse" must be an array`)}function gg(P){if(!Br(P))return{};let O=bl(P);return ci(O)&&ci(O.hooks)?O.hooks:{}}function kl(P){return Array.isArray(P.PreToolUse)?P.PreToolUse:[]}function xl(P,O,D){cn(P,`${JSON.stringify({...O,PreToolUse:D},null,2)}
42
- `)}function Cl(P){let O=Jr(P),D=Br(O),j=D?wl(O):gg(vl(P)),J=kl(j);if(D&&Et(J,Qn,Vr))return{path:O,alreadyInstalled:!0};return ug(mg(O),{recursive:!0}),xl(O,j,[...jn(J,Qn),Zn(Qn,Vr)]),{path:O,alreadyInstalled:!1}}function Sl(P){let O=Jr(P);if(!Br(O))return{path:O,alreadyInstalled:!1};let D=wl(O),j=kl(D),J=jn(j,Qn);if(JSON.stringify(J)===JSON.stringify(j))return{path:O,alreadyInstalled:!1};let Y=Br(vl(P));if(J.length===0&&Object.keys(D).length===1&&!Y)return fg(O),{path:O,alreadyInstalled:!0};return xl(O,D,J),{path:O,alreadyInstalled:!0}}function Pl(P){let O=Jr(P.environment);if(!yg(O))return{platform:"droid",status:"n/a",configPath:O};let D;try{D=JSON.parse(hg(O,"utf-8"))}catch(re){return{platform:"droid",status:"n/a",configPath:O,errors:[`Failed to parse Factory Droid hooks config ${O}: ${re instanceof Error?re.message:String(re)}`]}}let j=typeof D==="object"&&D!==null&&"PreToolUse"in D?D.PreToolUse:void 0,J=_t(Array.isArray(j)?j:[],Qn);if(!J)return{platform:"droid",status:"n/a",configPath:O};let Y=[...J.commandRegex===void 0||J.commandRegex===""?[]:['Managed hook has a "commandRegex" that narrows coverage; reinstall to repair'],...At(J,Qn,Vr)];return{platform:"droid",status:"configured",method:"hook config",configPath:O,errors:Y.length>0?Y:void 0}}import{existsSync as vg}from"node:fs";import{join as di}from"node:path";var ui="gemini-safety-net";function pi(P){let O=di(P.home,".gemini","extensions"),D=di(O,ui);if(!vg(D))return{platform:"gemini-cli",status:"n/a"};let j=di(O,"extension-enablement.json"),J=xn(j);if(J.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let Y=J.kind==="ok"?tn(tn(J.value,ui),"overrides"):void 0;if(Array.isArray(Y)&&Y.some((ie)=>typeof ie==="string"&&ie.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:j,errors:[`${ui} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:D}}function Rl(P){return pi(P.environment)}import{existsSync as xg,readFileSync as Cg}from"node:fs";import{existsSync as _l,mkdirSync as bg,readFileSync as Al,rmSync as wg}from"node:fs";import{dirname as kg,join as El}from"node:path";var rt=Cn["grok-build"],Wr=30,fi=Zn(rt,Wr);function zr(P){return El(P.env.get("GROK_HOME")??El(P.home,".grok"),"hooks","cc-safety-net.json")}function Yr(P){return typeof P==="object"&&P!==null&&!Array.isArray(P)}function Tl(P){try{let O=JSON.parse(P);return Yr(O)?O:null}catch{return null}}function Il(P){let O=Yr(P.hooks)?P.hooks.PreToolUse:void 0;return Array.isArray(O)?O:[]}function Kr(P,O,D){let j=Yr(O.hooks)?O.hooks:{};cn(P,`${JSON.stringify({...O,hooks:{...j,PreToolUse:D}},null,2)}
43
- `)}function $l(P){let O=zr(P);if(!_l(O))return bg(kg(O),{recursive:!0}),Kr(O,{},[fi]),{path:O,alreadyInstalled:!1};let D=Tl(Al(O,"utf-8"));if(!D)return Kr(O,{},[fi]),{path:O,alreadyInstalled:!1};let j=Il(D);if(Et(j,rt,Wr))return{path:O,alreadyInstalled:!0};return Kr(O,D,[...jn(j,rt),fi]),{path:O,alreadyInstalled:!1}}function Ol(P){let O=zr(P);if(!_l(O))return{path:O,alreadyInstalled:!1};let D=Tl(Al(O,"utf-8"));if(!D)return{path:O,alreadyInstalled:!1};let j=Il(D),J=jn(j,rt);if(JSON.stringify(J)===JSON.stringify(j))return{path:O,alreadyInstalled:!1};let Y=Yr(D.hooks)?D.hooks:{};if(J.length===0&&Object.keys(D).length===1&&Object.keys(Y).length===1)return wg(O),{path:O,alreadyInstalled:!0};return Kr(O,D,J),{path:O,alreadyInstalled:!0}}function Dl(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}function Ll(P){let O=zr(P.environment);if(!xg(O))return{platform:"grok-build",status:"n/a",configPath:O};let D;try{D=JSON.parse(Cg(O,"utf-8"))}catch(re){return{platform:"grok-build",status:"n/a",configPath:O,errors:[`Failed to parse Grok Build hooks config ${O}: ${re instanceof Error?re.message:String(re)}`]}}let j=Dl(D)&&Dl(D.hooks)?D.hooks.PreToolUse:void 0,J=_t(Array.isArray(j)?j:[],rt);if(!J)return{platform:"grok-build",status:"n/a",configPath:O};let Y=At(J,rt,Wr);return{platform:"grok-build",status:"configured",method:"hook config",configPath:O,errors:Y.length>0?Y:void 0}}import{readFileSync as Bl}from"node:fs";import{join as Vl}from"node:path";var Rn="cc-safety-net",mi="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",Sg=30;function Nl(P){return`${mi}
44
- # version: ${P}
45
- `}function Pg(P){return`${Nl(P)}name: ${Rn}
46
- version: "${P}"
1
+ import{a,s,Ne,tt,T,ht,nt,c,n,rt,P,S,pe,bt,m,_e,x,it,l,o,w,i,se,r,g,me,H,vt,St,p,ge,he,wt,L,Z,ae,C,Ct,I,h,Pe,W,u,A,X,st,at,M,E,O,ye,be,Me,Et,d,e,Fe,Ie,$e,xe,ct,lt,ce,Ae,le,je,Q,B,Ue,ve,z,ut,V,ee,te,ue,dt,pt,k,F,Ge,We,Be,R,ze,Oe,Ve,y,t,ne,Se,b,v,D,kt,qe,Ke,f,q}from"./chunks/index-babcfevy.js";import{Xe}from"./chunks/index-6hppa0dh.js";import{Je,Ce}from"./chunks/index-21n2w3y1.js";import{Qe}from"./chunks/index-n6djve2j.js";import"./chunks/index-1wd9cpbg.js";import{oe,K,et,U,G}from"./chunks/index-7h15fjs7.js";var lf=["-h","--help"];function mn(_,N){let j=Object.entries(_.booleans??{}),J=Object.entries(_.values??{}),Y=Object.entries(_.lists??{}),re=Object.fromEntries(j.map(([Te])=>[Te,!1])),ie={},de=Object.fromEntries(Y.map(([Te])=>[Te,[]])),fe=[],we=[],ke=!1,Re=-1;for(let[Te,Ee]of N.entries()){if(Te<=Re)continue;if(Ee==="--"){fe.push(...N.slice(Te+1));break}if(lf.includes(Ee)){ke=!0;continue}let De=j.find(([,Ye])=>Ye.includes(Ee));if(De){re[De[0]]=!0;continue}let He=J.find(([,Ye])=>Ye.includes(Ee));if(He){let Ye=N[Te+1];if(Ye===void 0||Ye.startsWith("-")){we.push(`${Ee} requires a value`);continue}ie[He[0]]=Ye,Re=Te+1;continue}let Le=Y.find(([,Ye])=>Ye.includes(Ee));if(Le){let Ye=N.slice(Te+1),tn=Ye.findIndex((sn)=>sn.startsWith("-")),rn=Ye.slice(0,tn===-1?Ye.length:tn);if(rn.length===0){we.push(`${Ee} requires at least one value`);continue}de[Le[0]]=[...de[Le[0]]??[],...rn],Re=Te+rn.length;continue}if(Ee.startsWith("-")){we.push(`Unknown option for ${_.label}: ${Ee}`);continue}if(_.positionals==="tail"){fe.push(...N.slice(Te));break}fe.push(Ee)}if(_.positionals!=="list"&&_.positionals!=="tail")we.push(...fe.map((Te)=>`Unexpected argument for ${_.label}: ${Te}`));return{flags:re,values:ie,lists:de,positionals:fe,help:ke,errors:we}}function $n(_){for(let N of _)console.error(N);return _.length>0}import{readdirSync as gf,statSync as zs,unlinkSync as yf}from"node:fs";import{basename as Ys,dirname as hf,isAbsolute as vf,join as bf,relative as wf,resolve as kf,sep as Cf}from"node:path";var Ks=(_)=>{let N=Date.now()-new Date(_).getTime();if(!Number.isFinite(N))return"";let j=Math.floor(N/60000),J=Math.floor(j/60),Y=Math.floor(J/24);if(Y>0)return`${Y}d ago`;if(J>0)return`${J}h ago`;if(j>0)return`${j}m ago`;return"just now"},Go=(_)=>{let N=(_??"").trim().split(/\s+/).filter((Y)=>Y&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(Y)),j=N[0]?.split("/").pop();if(!j)return null;let J=N[1];return J&&/^[a-z][a-z0-9-]*$/.test(J)?`${j} ${J}`:j};function Js(_){let N=(Y)=>`${Y.sessionId}
2
+ ${Go(Y.segment||Y.command)}`,j=_.filter((Y)=>Y.decision!=="allow"),J=j.filter((Y)=>Y.sessionId).reduce((Y,re)=>Y.set(N(re),(Y.get(N(re))??0)+1),new Map);return new Set(j.filter((Y)=>Y.failureStage||(J.get(N(Y))??0)>=2))}import{existsSync as cf,readdirSync as df,readFileSync as uf}from"node:fs";import{join as pf}from"node:path";function Yn(_,N){try{return df(_,{withFileTypes:!0,encoding:"utf8"}).flatMap((j)=>{let J=pf(_,j.name);if(j.isDirectory())return Yn(J,N);if(j.name.endsWith(".jsonl"))return[J];return[]})}catch{if(N&&cf(_))N.count++;return[]}}var ff=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function mf(_){if(!_||typeof _!=="object"||Array.isArray(_))return!1;let N=_;if(typeof N.ts!=="string"||typeof N.command!=="string")return!1;return ff.every((j)=>N[j]===void 0||typeof N[j]==="string")}function $t(_,N){try{return uf(_,"utf-8").split(`
3
+ `).filter(Boolean).flatMap((j)=>{try{let J=JSON.parse(j);if(!mf(J)){if(N)N.count++;return[]}return[J]}catch{if(N)N.count++;return[]}})}catch{if(N)N.count++;return[]}}function gn(_){return Array.from(_,(N)=>{let j=N.charCodeAt(0);if(j<=31||j>=127&&j<=159)return`\\x${j.toString(16).padStart(2,"0")}`;return N}).join("")}function xf(_,N){let j=oe(_),J=mn({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},N);if($n(J.errors))return null;if(J.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(J.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let Y=J.values.limit===void 0?20:Ws(J.values.limit);if(Y===null)return console.error("--limit must be a positive number"),null;let re=J.values.since===void 0?Math.min(30,j):Ws(J.values.since);if(re===null||re>j)return console.error(`--since must be a positive number of days no greater than ${j}`),null;let ie={limit:Y,limitExplicit:J.values.limit!==void 0,since:re,sinceExplicit:J.values.since!==void 0,all:J.flags.all,json:J.flags.json,suspect:J.flags.suspect,pruneLegacy:J.flags.pruneLegacy,dryRun:J.flags.dryRun,id:J.values.id,agent:J.values.agent,rule:J.values.rule,session:J.values.session,project:J.values.project===void 0?void 0:kf(J.values.project)};if(ie.id&&(ie.agent!==void 0||ie.rule!==void 0||ie.session!==void 0||ie.project!==void 0||ie.suspect||ie.sinceExplicit||ie.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(ie.pruneLegacy&&(ie.id!==void 0||ie.agent!==void 0||ie.rule!==void 0||ie.session!==void 0||ie.project!==void 0||ie.suspect||ie.all||ie.sinceExplicit||ie.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(ie.dryRun&&!ie.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return ie}async function Zs(_,N,j={}){let J=xf(_,N);if(!J)return 1;let Y=j.logsDir??U(_);if(J.pruneLegacy)return Sf(Y,J.json,J.dryRun);if(!Y)return console.log(J.json?"[]":J.id?`No retained audit log entry found for id ${gn(J.id)}.`:"No audit log entries found."),0;K(_,Y);let re={count:0},ie=Yn(Y,re).flatMap((Re)=>$t(Re,re).map((Te)=>({entry:Te,file:Re})));if(re.count>0)console.error(`warning: ${re.count} audit log ${re.count===1?"source":"sources"} could not be read; these results are incomplete`);if(J.id)return _f(ie,J,j.timeZone);let de=Date.now()-J.since*24*60*60*1000,fe=ie.filter((Re)=>Tf(Re,J,Y,de)),we=J.suspect?Js(fe.map((Re)=>Re.entry)):null,ke=(we?fe.filter((Re)=>we.has(Re.entry)):fe).sort((Re,Te)=>Date.parse(Te.entry.ts)-Date.parse(Re.entry.ts)).slice(0,J.limit);if(J.json)return console.log(JSON.stringify(ke.map((Re)=>Re.entry),null,2)),0;if(ke.length===0)return console.log("No audit log entries found."),0;for(let Re of ke)console.log(Of(Re.entry,j.timeZone));return 0}function Sf(_,N,j){let J=_?Rf(_).map((de)=>bf(_,de)):[];if(j)return Pf(J,N);let Y=[],re=0,ie=0;for(let de of J){let fe=zs(de,{throwIfNoEntry:!1})?.size??0,we=Ef(de);if(we){Y.push(`${Ys(de)}: ${we}`);continue}re++,ie+=fe}if(N)return console.log(JSON.stringify({removedFiles:re,removedBytes:ie,failedFiles:Y.length})),Y.length===0?0:1;console.log(re===0&&Y.length===0?"No legacy audit log files found.":`Removed ${re} legacy audit log ${re===1?"file":"files"} (${Xs(ie)}).`);for(let de of Y)console.error(`Could not remove ${gn(de)}`);if(console.log("Nested v2 audit logs were not changed."),re>0)console.log("This deletion cannot be undone.");return Y.length===0?0:1}function Pf(_,N){let j=_.reduce((J,Y)=>J+(zs(Y,{throwIfNoEntry:!1})?.size??0),0);if(N)return console.log(JSON.stringify({dryRun:!0,files:_.length,bytes:j})),0;if(console.log(_.length===0?"No legacy audit log files found.":`Would remove ${_.length} legacy audit log ${_.length===1?"file":"files"} (${Xs(j)}).`),console.log("Nested v2 audit logs are not included."),_.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Rf(_){try{return gf(_,{withFileTypes:!0}).filter((N)=>N.isFile()&&N.name.endsWith(".jsonl")).map((N)=>N.name)}catch{return[]}}function Ef(_){try{return yf(_),null}catch(N){return N instanceof Error?N.message:String(N)}}function Xs(_){let N=["B","KiB","MiB","GiB"],j=Math.min(Math.floor(Math.log2(Math.max(_,1))/10),N.length-1);return`${Math.round(_/1024**j*10)/10} ${N[j]}`}function _f(_,N,j){let J=_.filter((re)=>re.entry.id===N.id);if(J.length>1)return console.error(`Multiple audit log entries found for id ${gn(N.id??"")}.`),1;if(N.json)return console.log(JSON.stringify(J.map((re)=>re.entry),null,2)),0;let Y=J[0];if(!Y)return console.log(`No retained audit log entry found for id ${gn(N.id??"")}.`),0;return console.log($f(Y.entry,j)),0}function Tf(_,N,j,J){if(!N.all&&_.entry.decision==="allow")return!1;if(Date.parse(_.entry.ts)<J)return!1;if(N.agent!==void 0&&_.entry.agent!==N.agent)return!1;if(N.rule!==void 0&&_.entry.ruleId!==N.rule)return!1;if(N.session!==void 0&&!Af(_,j,N.session))return!1;if(N.project!==void 0&&!If(_.entry.cwd,N.project))return!1;return!0}function Af(_,N,j){if(_.entry.sessionId===j)return!0;return hf(_.file)===N&&Ys(_.file,".jsonl")===j}function If(_,N){if(!_)return!1;let j=wf(N,_);return j!==".."&&!j.startsWith(`..${Cf}`)&&!vf(j)}function Of(_,N){let j=gn(_.id??"-"),J=gn(_.decision??"deny"),Y=_.cwd?` [${gn(_.cwd)}]`:"",re=_.segment||_.command,ie=re===_.command?"":"↳ ",de=re.length>50?`${re.slice(0,50)}…`:re;return`${j.padEnd(16)} ${gn(Qs(_.ts,N))} ${J.padEnd(5)} ${gn(_.agent??"-").padEnd(15)} ${gn(_.ruleId??"-").padEnd(20)} ${ie}${gn(de)}${Y}`}function $f(_,N){let j=(Y)=>gn(Y===void 0||Y===null||Y===""?"-":Y),J=_.shape?`${_.agent??"-"} (shape: ${_.shape})`:_.agent??"-";return[`id: ${j(_.id)}`,`ts: ${j(Qs(_.ts,N))}`,`decision: ${j(_.decision)}`,`agent: ${j(J)}`,`level: ${j(_.level)}`,`tool: ${j(_.toolName)}`,`rule: ${j(_.ruleId)}`,`intent: ${j(_.intent)}`,`stage: ${j(_.failureStage)}`,`error: ${j(_.errorCode)}`,`session: ${j(_.sessionId)}`,`cwd: ${j(_.cwd)}`,`version: ${j(_.v)}`,`truncated: ${j(_.truncated===!0?"yes":void 0)}`,`reason: ${j(_.reason)}`,`command: ${j(_.command)}`,`segment: ${j(_.segment)}`].join(`
4
+ `)}function Qs(_,N){let j=new Date(_);if(Number.isNaN(j.getTime()))return _;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:N}).format(j)}function Ws(_){let N=Number(_);return Number.isFinite(N)&&N>0?N:null}var ea={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 na={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 ta={name:"gui",description:"Open the local policy editor GUI",usage:"gui [options]",options:[{flags:"--no-open",description:"Print the URL without opening a browser"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net gui","cc-safety-net gui --no-open"]};var Bo=["npx","--offline","--no-install","@deepseek-ai/dsh","--version"],ra=["cursor-agent","--version"],Pr=[{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:10,runtime:{order:8,flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{order:10,flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",doctorOrder:9,runtime:{order:7,flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{order:9,flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",doctorOrder:11,runtime:{order:9,flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{order:11,flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",doctorOrder:12,runtime:{order:10,flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{order:12,flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",doctorOrder:13,runtime:{order:11,flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{order:13,flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",doctorOrder:14,install:{order:14,flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",doctorOrder:15,install:{order:15,flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",doctorOrder:16,install:{order:16,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:"deepseek-harness",displayName:"DeepSeek Harness",doctorOrder:6,install:{order:6,flag:"--deepseek-harness",artifactKind:"package",probeCommand:Bo}},{id:"devin",displayName:"Devin CLI",doctorOrder:7,runtime:{order:5,flags:["-dv","--devin"],description:"Run as Devin CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{order:7,flag:"--devin",artifactKind:"hook config",probeCommand:["devin","--version"]}},{id:"droid",displayName:"Factory Droid",doctorOrder:8,runtime:{order:6,flags:["-fd","--droid"],description:"Run as Factory Droid PreToolUse hook",legacyTopLevelFlags:[]},install:{order:8,flag:"--droid",artifactKind:"hook config",probeCommand:["droid","--version"]}},{id:"amp",displayName:"Amp Code",doctorOrder:2,install:{order:1,flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Rr=Pr.slice().sort((_,N)=>_.doctorOrder-N.doctorOrder).map((_)=>_.id),Yt=Pr.filter((_)=>("runtime"in _)).slice().sort((_,N)=>_.runtime.order-N.runtime.order).map((_)=>({id:_.id,displayName:"displayName"in _.runtime?_.runtime.displayName:_.displayName,flags:_.runtime.flags,legacyFlags:"legacyFlags"in _.runtime?_.runtime.legacyFlags:[],description:_.runtime.description,legacyTopLevelFlags:_.runtime.legacyTopLevelFlags})),Rn=Pr.slice().sort((_,N)=>_.install.order-N.install.order).map((_)=>({id:_.id,..._.install})).map(({order:_,...N})=>N),Df=Object.fromEntries(Pr.map((_)=>[_.id,_.displayName]));function cn(_){return Df[_]}var Lf=Yt.map((_)=>({flags:_.flags.join(", "),description:_.description})),Nf=Yt.flatMap((_)=>_.flags.map((N)=>`cc-safety-net hook ${N}`)),oa={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Lf,{flags:"-h, --help",description:"Show this help"}],examples:Nf};var ia={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...Rn.map((_)=>({flags:_.flag,description:`Install ${cn(_.id)} ${_.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...Rn.map((_)=>`cc-safety-net install ${_.flag}`)]},sa={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...Rn.map((_)=>({flags:_.flag,description:`Uninstall ${cn(_.id)} ${_.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...Rn.map((_)=>`cc-safety-net uninstall ${_.flag}`)]},aa={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 la={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 Er={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 qo=[{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"}],Vo=["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"],Dt={name:"rule",description:"Manage CC Safety Net rule config and rulebook sources",usage:"rule <subcommand>",subcommands:[{usage:"init [--example]",description:"Create inert rule config"},{usage:"add [source] [--ref <ref>] [--only <rulebook...>]",description:"Add rulebook sources and sync"},{usage:"remove <source>",description:"Remove a rulebook source and sync"},{usage:"update [source]",description:"Re-fetch and vendor remote rulebooks"},{usage:"sync",description:"Deprecated: migrate lock and cache leftovers"},{usage:"list",description:"List active rulebooks"},{usage:"wrapper add <command>",description:"Trust a transparent command wrapper"},{usage:"wrapper remove <command>",description:"Remove a transparent command wrapper"},{usage:"wrapper list",description:"List transparent command wrappers"},{usage:"tool add <name...> [--cwd-arg <name>] [--project]",description:"Analyze community shell tools (user scope by default)"},{usage:"tool remove <name...> [--project]",description:"Stop analyzing declared tools"},{usage:"tool list",description:"List declared command tools in both scopes"},{usage:"migrate [--cleanup]",description:"Migrate legacy inline rules"},{usage:"doc",description:"Print the rulebook authoring guide"},{usage:"verify",description:"Validate rule config files"}],options:[{flags:"-g, --global",description:"Use user-scope rule config"},{flags:"--cleanup",description:"Delete legacy files after rule migrate verifies them"},{flags:"--delete-source",description:"Delete clean local source directory on remove"},{flags:"--example",description:"Create an inactive example rulebook with rule init"},{flags:"--project",description:"Use project-scope rule config with rule tool"},{flags:"--cwd-arg",argument:"<name>",description:"Name the working-directory argument with rule tool add"},...qo.slice(0,2),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net rule init","cc-safety-net rule init --example","cc-safety-net rule wrapper add rtk","cc-safety-net rule tool add ops_bash","cc-safety-net rule tool add ops_run_background --cwd-arg cwd --project",...Vo,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var ca={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 da={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 _r=[ca,ea,la,na,Dt,Er,ia,aa,sa,oa,ta,da];function jf(_){return _.aliases??[]}function Tr(_){let N=_.toLowerCase();return _r.find((j)=>j.name.toLowerCase()===N||jf(j).some((J)=>J.toLowerCase()===N))}import{existsSync as $h}from"node:fs";import{basename as Hf}from"node:path";function Ar(_,N=7,j=U(_)){let J=Date.now()-N*24*60*60*1000,Y=[],re=new Set,ie=0,de,fe,we,ke;if(j)K(_,j);let Re={count:0},Te=j?Yn(j,Re):[];for(let De of Te)for(let He of $t(De,Re)){if(He.decision==="allow")continue;let Le=new Date(He.ts).getTime();if(Le>=J){if(ie++,re.add(He.sessionId??Hf(De,".jsonl")),fe===void 0||Le<=fe)de=He.ts,fe=Le;if(ke===void 0||Le>ke)we=He.ts,ke=Le;Ff(Y,He,Le)}}let Ee=Y.map((De)=>({timestamp:De.ts,command:De.command,reason:De.reason,relativeTime:Ks(new Date(De.ts))}));return{totalBlocked:ie,sessionCount:re.size,recentEntries:Ee,oldestEntry:de,newestEntry:we,unreadable:Re.count}}function Ff(_,N,j){let J=_.findIndex((Y)=>j>new Date(Y.ts).getTime());if(J===-1){if(_.length<3)_.push(N);return}if(_.splice(J,0,N),_.length>3)_.pop()}import{dirname as Zf}from"node:path";import{dirname as Mf,join as Uf,resolve as Gf}from"node:path";var Bf="config.json";function bn(_,N,j,J){g(qf(_),`${JSON.stringify(N,null,2)}
5
+ `,j,J)}function qf(_){return typeof _==="string"?se(_):_}function Jo(_){return{errors:ce(Kf(_),": "," "),ruleNames:new Set(je(_).map((N)=>N.toLowerCase()))}}var Vf="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",ua="must match pattern (letters, numbers, hyphens, underscores)";function Kf(_){if(!pa(_))return[e([],"Config must be an object")];return[..._.version===1?[]:[e(["version"],"must be 1")],...Jf(_.rules)]}function Jf(_){if(_===void 0)return[];if(!Array.isArray(_))return[e(["rules"],"must be an array")];return[..._.flatMap((N,j)=>pa(N)?Wf(N,["rules",j]):[e(["rules",j],"must be an object")]),...Fe(_)]}function Wf(_,N){return[...Ko(_.name,[...N,"name"],"required string",p,Vf),...Ko(_.command,[...N,"command"],"required string",E,ua),..._.subcommand===void 0?[]:Ko(_.subcommand,[...N,"subcommand"],"must be a string if provided",E,ua),...zf(_.block_args,[...N,"block_args"]),...Yf(_.reason,[...N,"reason"]),..._.intent===void 0||Ae(_.intent)?[]:[e([...N,"intent"],Ie)]]}function Ko(_,N,j,J,Y){if(typeof _!=="string")return[e(N,j)];return J.test(_)?[]:[e(N,Y)]}function zf(_,N){if(!Array.isArray(_))return[e(N,"required array")];if(_.length===0)return[e(N,"must have at least one element")];return _.flatMap((j,J)=>{if(typeof j!=="string")return[e([...N,J],"must be a string")];return j===""?[e([...N,J],"must not be empty")]:[]})}function Yf(_,N){if(typeof _!=="string")return[e(N,"required string")];if(_==="")return[e(N,"must not be empty")];return _.length>O?[e(N,`must be at most ${O} characters`)]:[]}function pa(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}function Wo(_){let N=fa(_);if(!N.ok)return N.result;return Jo(N.parsed)}function fa(_){let N=[],j=new Set;try{let J=typeof _==="string"?se(_):_,Y=r(J);if(Y===null)return N.push(`File not found: ${J.path}`),{ok:!1,result:{errors:N,ruleNames:j}};if(!Y.trim())return N.push("Config file is empty"),{ok:!1,result:{errors:N,ruleNames:j}};return{ok:!0,parsed:JSON.parse(Y)}}catch(J){if(J instanceof o)return N.push(J.message),{ok:!1,result:{errors:N,ruleNames:j}};let Y=J instanceof Error?J.message:String(J);return N.push(J instanceof SyntaxError?"Invalid JSON":Y),{ok:!1,result:{errors:N,ruleNames:j}}}}function Ir(_){return Gf(_,".safety-net.json")}function Un(_){let N=fa(_);if(!N.ok)return N.result;let j=ct(N.parsed);return{errors:j.errors,ruleNames:j.sources}}function Lt(_,N={}){return Uf(Mf(Pe(_,N)),Bf)}function ma(_,N,j){let J;try{if(r(N)===null)return{path:_,exists:!1,valid:!1,ruleCount:0};J=Un(N),J.errors.push(...B(_,j))}catch(Y){if(!(Y instanceof o))throw Y;J={errors:[Y.message],ruleNames:new Set}}return{path:_,exists:!0,valid:J.errors.length===0,ruleCount:J.ruleNames.size,...J.errors.length>0?{errors:J.errors}:{}}}function Xf(_,N){return{source:N,name:_.name,command:_.command,subcommand:_.subcommand,blockArgs:[..._.block_args],reason:_.reason}}function ga(_,N){let j=W(_),J=I(N),Y=Zf(j),re=Q(_,{cwd:N,userConfigPath:j,projectConfigPath:J,userConfigDir:Y}),ie=X(_,{cwd:N,userConfigPath:j,projectConfigPath:J,userConfigDir:Y}),de=new Map(re.rulebooks.flatMap((fe)=>fe.rules.map((we)=>[we,fe.source])));return{userConfig:ma(j,ie.userConfigTarget,ie.userScope),projectConfig:ma(J,ie.projectConfigTarget,ie.projectScope),effectiveRules:re.rules.map((fe)=>Xf(fe,de.get(fe.name)??"project"))}}var Qf=[{flag:n.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:n.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:n.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:n.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:n.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:n.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:n.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:n.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"},{flag:n.projectTightenOnly,description:"Ignore project policy settings that weaken the user policy",defaultBehavior:"off"}];function ya(_){return[...Qf.map((N)=>({name:N.flag.name,value:pe(N.flag,_.env),isSet:bt(N.flag,_.env),legacyName:N.flag.legacyName,legacyValue:N.flag.legacyName?_.env.get(N.flag.legacyName):void 0,legacyIsSet:N.flag.legacyName?_.env.get(N.flag.legacyName)!==void 0:void 0,description:N.description,defaultBehavior:N.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:_.env.get("CC_SAFETY_NET_HOME"),isSet:_.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var ha={error:0,warning:1,info:2},em=["policy","config","audit"];function nm(_){return _.map((N)=>{if(N==="ownership")return"is not owned by the current user";if(N==="permissions")return"has unsafe permissions";if(N==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var tm=[{derive:(_)=>_.hooks.length>0&&_.hooks.every((N)=>!N.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(_)=>_.hooks.filter((N)=>N.inspectionStatus==="failed").map((N)=>{let j=cn(N.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${j} inspection failed`,detail:`Doctor could not verify the ${j} integration configuration.`,fixHint:`Correct the reported ${j} configuration error, then run \`cc-safety-net doctor\` again.`,integration:N.platform}})},{derive:(_)=>_.userConfig.exists&&!_.userConfig.valid?[{checkId:"config.user-invalid",severity:"error",title:"User configuration is invalid",detail:"Doctor could not load a valid user rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:_.userConfig.path}]:[]},{derive:(_)=>_.projectConfig.exists&&!_.projectConfig.valid?[{checkId:"config.project-invalid",severity:"error",title:"Project configuration is invalid",detail:"Doctor could not load a valid project rules configuration.",fixHint:"Run `cc-safety-net rule verify`, correct the reported error, then rerun doctor.",path:_.projectConfig.path}]:[]},{derive:(_)=>_.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${_.configState.reason}`,fixHint:"Fix the file named in the reason, or run `cc-safety-net rule update` to vendor a remote source, then rerun doctor."}]:[]},{derive:(_)=>_.v2Leftovers&&_.v2Leftovers.length>0?[{checkId:"config.v2-leftovers",severity:"info",title:"Rulebook lock and cache leftovers detected",detail:`Files an earlier version left behind are no longer read: ${_.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(_)=>_.legacyConfigs&&_.legacyConfigs.length>0?[{checkId:"config.legacy-ignored",severity:"warning",title:"Legacy inline rule configs are ignored",detail:`CC Safety Net no longer loads these files, so their rules enforce nothing: ${_.legacyConfigs.join(", ")}.`,fixHint:"Run `cc-safety-net rule migrate` to convert them (add `--cleanup` to delete each file once it is converted), then rerun doctor."}]:[]},{derive:(_)=>{let N=_.environment.find((j)=>j.name==="CC_SAFETY_NET_AUDIT_SCOPE");return rt(N?.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."}]:[]}},...em.map((_)=>({derive:(N)=>N.posture.directories.filter((j)=>j.kind===_&&j.status==="unsafe").map((j)=>({checkId:`posture.${_}-directory-unsafe`,severity:"error",title:`${_[0]?.toUpperCase()}${_.slice(1)} directory is unsafe`,detail:`The ${_} directory ${nm(j.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...j.path?{path:j.path}:{}}))})),{derive:(_)=>{let N=[..._.effectiveSafety.weakenedRuleOverrides].sort();return N.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: ${N.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${N.join(", ")}.`}]:[]}}];function va(_){return tm.flatMap((N,j)=>N.derive(_).map((J,Y)=>({finding:J,catalogOrder:j,occurrence:Y}))).sort((N,j)=>ha[N.finding.severity]-ha[j.finding.severity]||N.catalogOrder-j.catalogOrder||N.occurrence-j.occurrence).map((N)=>N.finding)}function Dn(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var rm=(_)=>Dn()?`\x1B[32m${_}\x1B[0m`:_,om=(_)=>Dn()?`\x1B[33m${_}\x1B[0m`:_,im=(_)=>Dn()?`\x1B[34m${_}\x1B[0m`:_,sm=(_)=>Dn()?`\x1B[36m${_}\x1B[0m`:_,am=(_)=>Dn()?`\x1B[31m${_}\x1B[0m`:_,lm=(_)=>Dn()?`\x1B[2m${_}\x1B[0m`:_,cm=(_)=>Dn()?`\x1B[1m${_}\x1B[0m`:_,en={green:rm,yellow:om,blue:im,cyan:sm,red:am,dim:lm,bold:cm},dm="\x1B[0m",um=[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 pm(_){let N=_;return()=>(N=(N*1664525+1013904223)%4294967296,N/4294967296)}function fm(_){let N=[...um],j=pm(_);for(let J=N.length-1;J>0;J--){let Y=Math.floor(j()*(J+1)),re=N[J];N[J]=N[Y],N[Y]=re}return N}function mm(_,N=0){if(!Dn())return"";let j=fm(N);return`\x1B[38;5;${j[_%j.length]}m`}function ba(_,N,j=0){if(!Dn())return`"${_}"`;return`${mm(N,j)}"${_}"${dm}`}function Or(_){return _==="default"?"built-in default":`${_} policy`}var gm=new RegExp("\x1B\\[[0-9;]*m","g"),zo=(_)=>_.replace(gm,"").length;function Zn(_){let N=(_.headers??_.rows[0]??[]).map((ie,de)=>{let fe=Math.max(..._.rows.map((we)=>zo(we[de]??"")));return Math.max(zo(ie),fe)}),j=(ie,de)=>ie+" ".repeat(Math.max(0,de-zo(ie))),J=(ie,de)=>de[0]+N.map((fe)=>ie.repeat(fe+2)).join(de[1])+de[2],Y=(ie)=>`│ ${ie.map((de,fe)=>j(de,N[fe]??0)).join(" │ ")} │`,re=_.headers?[` ${Y(_.headers)}`,` ${J("─",["├","┼","┤"])}`]:[];return[` ${J("─",["┌","┬","┐"])}`,...re,..._.rows.map((ie)=>` ${Y(ie)}`),` ${J("─",["└","┴","┘"])}`].join(`
6
+ `)}function wa(_){let N=[];N.push("Hook Integration"),N.push(ym(_));let j=[],J=[];for(let Y of _){let re=cn(Y.platform);if(Y.errors&&Y.errors.length>0)for(let ie of Y.errors)if(Y.configured)j.push({platform:re,message:ie});else J.push({platform:re,message:ie})}for(let Y of j)N.push(` Warning (${Y.platform}): ${Y.message}`);for(let Y of J)N.push(en.red(` Error (${Y.platform}): ${Y.message}`));return N.join(`
7
+ `)}function ym(_){let N=["Platform","Discovery","Configuration","Inspection"],j=_.map((J)=>{let Y=cn(J.platform);if(J.inspectionStatus==="not-inspected"){let fe=en.dim("Not inspected");return[Y,fe,fe,fe]}let re=J.detected?en.green("Detected"):J.inspectionStatus==="failed"?en.red("Unknown"):en.dim("Not detected"),ie=J.configured?en.green("Configured"):J.detected?en.yellow("Not configured"):J.inspectionStatus==="failed"?en.red("Unknown"):en.dim("Not applicable"),de=J.inspectionStatus==="verified"?en.green("Verified"):J.inspectionStatus==="failed"?en.red("Failed"):en.dim("Not applicable");return[Y,re,ie,de]});return Zn({headers:N,rows:j})}function ka(_){let j=["Guard Engine Verification",` Synthetic self-test: ${_.failed>0?en.red(`${_.passed}/${_.total} FAIL`):en.green(`${_.passed}/${_.total} passed`)}`],J=_.results.filter((Y)=>!Y.passed);if(J.length>0){j.push(""),j.push(en.red(" Failures:"));for(let Y of J)j.push(en.red(` • ${Y.description}`)),j.push(en.red(` expected ${Y.expected}, got ${Y.actual}`))}return j.join(`
8
+ `)}function hm(_){if(_.length===0)return" (no custom rules)";let N=["Source","Name","Command","Block Args"],j=_.map((J)=>[J.source,J.name,J.subcommand?`${J.command} ${J.subcommand}`:J.command,J.blockArgs.join(", ")]);return Zn({headers:N,rows:j})}function Ca(_){let N=[];if(N.push("Configuration"),N.push(vm(_.userConfig,_.projectConfig)),N.push(""),_.effectiveRules.length>0)N.push(` Effective rules (${_.effectiveRules.length} total):`),N.push(hm(_.effectiveRules));else N.push(" Effective rules: (none - using built-in rules only)");return N.join(`
9
+ `)}function vm(_,N){let j=["Scope","Status"],J=(re)=>{if(!re.exists)return en.dim("N/A");if(!re.valid)return en.red(`Invalid (${re.errors?.[0]??"unknown error"})`);return en.green("Configured")},Y=[["User",J(_)],["Project",J(N)]];return Zn({headers:j,rows:Y})}function xa(_){let N=[];return N.push("Environment"),N.push(bm(_)),N.join(`
10
+ `)}function Sa(_){let N=_.effectiveSafety.policyScopes,j=["Effective Safety",` Selected preset: ${_.effectiveSafety.selectedPreset}${N?` (${Or(N.levelScope)})`:""}`,` Effective: ${_.effectiveSafety.level}`],J=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[Y,re]of J){let ie=_.effectiveSafety.capabilities[Y],de=ie.enabled?en.green("ON"):en.dim("OFF"),fe=ie.sources.length>0?` (${ie.sources.join(", ")})`:"";j.push(` ${re}: ${de} via ${ie.source}${fe}`)}if(N&&N.weakenings.length>0){j.push(` Project policy deltas${N.weakeningsIgnored?" (ignored)":""}:`);for(let Y of N.weakenings)j.push(` ${Y}`)}j.push(` Stored rule customizations: ${_.effectiveSafety.ruleCounts.stored}`),j.push(` Effective rule customizations: ${_.effectiveSafety.ruleCounts.effective}`);for(let[Y,re]of Object.entries(_.effectiveSafety.ruleOverrides))j.push(` ${Y}: ${re}`);return j.join(`
11
+ `)}function Pa(_){let N=["Findings"];if(_.length===0)return N.push(" No findings from inspected doctor facts."),N.join(`
12
+ `);for(let j of _){let J=`[${j.severity.toUpperCase()}] ${j.checkId}: ${gn(j.title)}`,Y=j.severity==="error"?en.red:j.severity==="warning"?en.yellow:en.blue;if(N.push(` ${Y(J)}`),N.push(` ${gn(j.detail)}`),j.path)N.push(` Path: ${gn(j.path)}`);if(j.fixHint)N.push(` Fix: ${gn(j.fixHint)}`)}return N.join(`
13
+ `)}function bm(_){let N=["Variable","Status","Legacy"],j=_.map((J)=>{let Y=J.isSet?en.green("✓"):en.dim("✗"),re=J.legacyName&&J.legacyIsSet?`${J.legacyName} ${en.green("✓")}`:J.legacyName??"";return[J.name,Y,re]});return Zn({headers:N,rows:j})}function Ra(_){let N=[];if(_.totalBlocked===0)N.push("Recent Activity"),N.push(" No blocked commands in the last 7 days"),N.push(" Tip: This is normal for new installations");else N.push(`Recent Activity · last 7 days (${_.totalBlocked} blocked / ${_.sessionCount} sessions)`),N.push(wm(_.recentEntries));if(_.unreadable>0)N.push(` Warning: ${_.unreadable} audit log ${_.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return N.join(`
14
+ `)}function wm(_){let N=["Time","Command"],j=_.map((J)=>{let Y=gn(J.command.replace(/\r\n|\r|\n/g," ↵ ").replace(/\t/g," ")),re=Y.length>40?`${Y.slice(0,37)}...`:Y;return[J.relativeTime,re]});return Zn({headers:N,rows:j})}function Ea(_){let N=[];if(N.push("Update Check"),_.latestVersion===null&&!_.error)return N.push($r([["Status",en.dim("Skipped")],["Installed",_.currentVersion]])),N.join(`
15
+ `);if(_.error)return N.push($r([["Status",`${en.yellow("⚠")} Error`],["Installed",_.currentVersion],["Error",en.dim(_.error)]])),N.join(`
16
+ `);if(_.updateAvailable)return N.push($r([["Status",`${en.yellow("⚠")} Update Available`],["Current",_.currentVersion],["Latest",en.green(_.latestVersion??"")]])),N.push(""),N.push(" Run: bunx cc-safety-net@latest doctor"),N.push(" Or: npx cc-safety-net@latest doctor"),N.join(`
17
+ `);return N.push($r([["Status",`${en.green("✓")} Up to date`],["Version",_.currentVersion]])),N.join(`
18
+ `)}function $r(_){return Zn({rows:_})}function _a(_){let N=[];return N.push("System Info"),N.push(km(_)),N.join(`
19
+ `)}function km(_){let N=["Component","Version"],j=(re)=>{if(re===null)return en.dim("not found");return re},Y=[{label:"cc-safety-net",value:_.version},...Rr.map((re)=>({label:cn(re),value:_.versions[re]??null})),{label:"Node.js",value:_.nodeVersion},{label:"npm",value:_.npmVersion},{label:"Bun",value:_.bunVersion},{label:"Platform",value:_.platform}].map((re)=>[re.label,j(re.value)]);return Zn({headers:N,rows:Y})}function Ta(_){if(_.findings.length===0)return en.green(`
20
+ No findings from inspected doctor facts.`);let N={error:_.findings.filter((re)=>re.severity==="error").length,warning:_.findings.filter((re)=>re.severity==="warning").length,info:_.findings.filter((re)=>re.severity==="info").length},j=["error","warning","info"].filter((re)=>N[re]>0).map((re)=>`${N[re]} ${re}`),J=_.findings.length===1?"finding":"findings",Y=`
21
+ ${_.findings.length} ${J}: ${j.join(", ")}.`;if(N.error>0)return en.red(Y);if(N.warning>0)return en.yellow(Y);return en.blue(Y)}import{lstatSync as Cm}from"node:fs";import{dirname as Yo}from"node:path";function Zo(_,N){try{let j=Cm(N);if(j.isSymbolicLink())return{kind:_,path:N,status:"unsafe",issues:["symlink"]};if(!j.isDirectory())return{kind:_,path:N,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:_,path:N,status:"unknown",issues:[]};let J=[...j.uid!==process.getuid()?["ownership"]:[],...(j.mode&18)!==0?["permissions"]:[]];return{kind:_,path:N,status:J.length>0?"unsafe":"safe",issues:J}}catch(j){if(typeof j==="object"&&j!==null&&"code"in j&&j.code==="ENOENT")return{kind:_,path:N,status:"not-applicable",issues:[]};return{kind:_,path:N,status:"unknown",issues:[]}}}function Aa(_,N){let j=U(_);return{directories:[Zo("policy",Yo(Yo(N))),Zo("config",Yo(N)),...j?[Zo("audit",j)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as xm}from"node:child_process";import{existsSync as Ia}from"node:fs";import{delimiter as Sm,extname as Pm,join as Rm}from"node:path";import{stripVTControlCharacters as Oa}from"node:util";var Da="2.6.11",Em=5000,_m="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function pn(){return Da}function Xo(_,N){let j=_[N];if(j)return j;let J=Object.keys(_).find((Y)=>Y.toLowerCase()===N.toLowerCase()&&!!_[Y]);return J?_[J]:j}function Tm(_){return(Xo(_,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((N)=>N.length>0)}function Am(_,N){let j=Pm(_)?[_]:[...Tm(N).map((J)=>`${_}${J}`),_];if(_.includes("/")||_.includes("\\"))return j.find((J)=>Ia(J))??_;return(Xo(N,"PATH")??"").split(Sm).flatMap((J)=>j.map((Y)=>Rm(J,Y))).find((J)=>Ia(J))??_}function $a(_){if(!/[\s"&|<>^]/.test(_))return _;return`"${_.replace(/"/g,'""')}"`}function Xn(_,N){let[j,...J]=_,Y=N[_m]==="win32"?"win32":process.platform;if(!j||Y!=="win32")return{cmd:j??"",args:J};let re=Am(j,N);if(!/\.(?:bat|cmd)$/i.test(re))return{cmd:re,args:J};return{cmd:Xo(N,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",$a(re),...J.map($a)].join(" ")]}}var Nt=async(_,N=Em)=>{let j=await Im(_,{timeoutMs:N});if(j.code!==0)return null;return Oa(j.stdout).trim()||Oa(j.stderr).trim()||null};function Im(_,N){let[j,...J]=_;if(!j)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((Y)=>{try{let re=Xn([j,...J],process.env),ie=xm(re.cmd,re.args,{stdio:["ignore","pipe","pipe"]}),de=!1,fe="",we="";ie.stdout.on("data",(Te)=>{fe+=Te.toString()}),ie.stderr.on("data",(Te)=>{we+=Te.toString()});let ke=(Te)=>{if(de)return;de=!0,clearTimeout(Re),Y(Te)},Re=setTimeout(()=>{ie.kill(),ke({code:null,stdout:fe,stderr:we})},N.timeoutMs);ie.on("close",(Te)=>{ke({code:Te,stdout:fe,stderr:we})}),ie.on("error",()=>{ke({code:null,stdout:fe,stderr:we})})}catch{Y({code:null,stdout:"",stderr:""})}})}function Dr(_){if(!_)return null;let N=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(_);if(N)return N[1]??null;let j=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(_);if(j)return j[1]??null;return _.split(`
22
+ `)[0]?.trim()||null}async function Lr(_,N=Nt,j=process.cwd()){let J=Promise.all(Rn.map(async(Re)=>[Re.id,Dr(await N([...Re.probeCommand]))])),[Y,re,ie,de,fe,we,ke]=await Promise.all([J,J.then(async(Re)=>{let Te=Re.find(([He])=>He==="opencode")?.[1];if(!Te?.startsWith("2.")||!_(Te))return null;let Ee=["--param",`location[directory]=${j}`],De=["opencode","api","integration.list",...Ee];return await N(De,30000),N(["opencode","api","plugin.list",...Ee],30000)}),N(["codex","plugin","list"],30000),N(["amp","plugins","list"],30000),N(["node","--version"]),N(["npm","--version"]),N(["bun","--version"])]);return{version:Da,versions:Object.fromEntries(Y),codexPluginListOutput:ie,ampPluginListOutput:de,openCodePluginListOutput:re,nodeVersion:Dr(fe),npmVersion:Dr(we),bunVersion:Dr(ke),platform:`${process.platform} ${process.arch}`}}function Qo(_,N){if(N==="dev")return!1;let j=_.split(".").map(Number),J=N.split(".").map(Number),[Y=0,re=0,ie=0]=j,[de=0,fe=0,we=0]=J;if(Y!==de)return Y>de;if(re!==fe)return re>fe;return ie>we}async function Gn(){let _=pn(),N=new AbortController,j=setTimeout(()=>N.abort(),3000);try{let J=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:N.signal});if(!J.ok)return{currentVersion:_,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${J.status}`};let Y=await J.json(),re=Qo(Y.version,_);return{currentVersion:_,latestVersion:Y.version,updateAvailable:re}}catch(J){return{currentVersion:_,latestVersion:null,updateAvailable:!1,error:J instanceof Error?J.message:"Network error"}}finally{clearTimeout(j)}}import*as Ga from"node:readline";var Ha=(_)=>`\x1B[${_}B`,Om=(_)=>`\x1B[${_}A`;var La=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function $m(_){return new Promise((N)=>setTimeout(N,_))}function Dm(_,N,j){if(!j)return N(_);if(j.aborted)return Promise.resolve();return new Promise((J,Y)=>{let re=()=>j.removeEventListener("abort",ie),ie=()=>{re(),J()};j.addEventListener("abort",ie,{once:!0}),N(_).then(()=>{re(),J()},(de)=>{re(),Y(de)})})}function Nr(_){return Math.max(0,Math.min(1,_))}function jt(_){return Math.max(0,Math.min(255,Math.round(_)))}function ei(_){return _<=0.0031308?12.92*_:1.055*_**0.4166666666666667-0.055}function Lm(_,N,j){let J=j*Math.PI/180,Y=N*Math.cos(J),re=N*Math.sin(J),ie=(_+0.3963377774*Y+0.2158037573*re)**3,de=(_-0.1055613458*Y-0.0638541728*re)**3,fe=(_-0.0894841775*Y-1.291485548*re)**3;return{blue:jt(ei(Nr(-0.0041960863*ie-0.7034186147*de+1.707614701*fe))*255),green:jt(ei(Nr(-1.2684380046*ie+2.6097574011*de-0.3413193965*fe))*255),red:jt(ei(Nr(4.0767416621*ie-3.3077115913*de+0.2309699292*fe))*255)}}function ni(_,N){let j=(N*_*180/Math.PI%360+360)%360;return Lm(0.72,0.15,j)}function Fa(_,N=0.1){let j=ni(N,_);return`\x1B[38;2;${j.red};${j.green};${j.blue}m`}function Nm(_,N){return{blue:jt(_.blue+(255-_.blue)*N),green:jt(_.green+(255-_.green)*N),red:jt(_.red+(255-_.red)*N)}}function Ma(_,N,j){let J=Math.imul(_+2654435769,2246822507)^Math.imul(N+3266489909,668265263)^Math.imul(j+374761393,2654435761),Y=J^J>>>15,re=Math.imul(Y,739982445),ie=re^re>>>12,de=Math.imul(ie,695872825);return((de^de>>>15)>>>0)/4294967296}function jm(_,N,j){let J=Math.floor(Ma(_,N,j)*La.length);return La[J]??"░"}function Na(_){let N=Nr(_);return N*N*N*(N*(N*6-15)+10)}function Hm(_){if(_.length===0)return"";let N=[],j=!1,J="";for(let Y of _){let re=`${Y.red};${Y.green};${Y.blue}`;if(Y.bold!==j)N.push(Y.bold?"\x1B[1m":"\x1B[22m"),j=Y.bold;if(re!==J)N.push(`\x1B[38;2;${re}m`),J=re;N.push(Y.character)}return`${N.join("")}\x1B[22m\x1B[39m`}function Fm(_,N,j,J,Y){return _.map((re,ie)=>({...ni(j,J+N+ie/Y),bold:!1,character:re}))}function Mm(_,N,j,J,Y,re,ie,de){let fe=Math.max(1,J*0.75),we=Math.min(1,j/fe),ke=Y*Na(we),Re=Math.max(0,(j-fe)/Math.max(1,J-fe)),Te=(1-Na(j/J))*de*2,Ee=0.35*Math.max(0,1-Re*2),De=we>=1,He=Math.min(_.length,Math.ceil(ke+2+1));return _.slice(0,He).map((Le,Ye)=>{let tn=ni(re,ie+N+Ye/de+Te),rn=Ye+Ma(N,Ye,7919)*2-1;if(rn>ke+2)return{...tn,bold:!1,character:" "};let sn=ke-rn,nn=0.8*Math.exp(-(sn*sn)/12.5),an=Math.min(0.9,nn+Ee),Sn=!De&&rn>ke-4;return{...Nm(tn,an),bold:an>0.3,character:Sn?jm(N,Ye,j):Le}})}function ja(_){return`\x1B[?2026h${_.map((N,j)=>`\x1B8${j>0?Ha(j):""}${Hm(N)}`).join("")}\x1B[?2026l`}async function ti(_,N={}){if(!_)return;let j=N.output??process.stdout,J=N.sleep??$m,Y=N.seed??0,re=_.split(`
23
+ `).map((ke)=>Array.from(ke)),ie=Math.max(...re.map((ke)=>ke.length)),de=12000*re.filter((ke)=>ke.length>0).length/40,fe=ie>0?Math.max(1,Math.ceil(de/16.666666666666668)):0,we=fe>0?de/fe:0;j.write(`\x1B[?25l${re.length>1?`${`
24
+ `.repeat(re.length-1)}${Om(re.length-1)}`:""}\x1B7`);try{for(let ke=1;ke<=fe;ke+=1){if(N.signal?.aborted)break;j.write(ja(re.map((Re,Te)=>Mm(Re,Te,ke,fe,ie,0.1,Y,3)))),await Dm(we,J,N.signal)}}finally{if(j.write(ja(re.map((ke,Re)=>Fm(ke,Re,0.1,Y,3)))),j.write("\x1B8"),re.length>1)j.write(Ha(re.length-1));j.write(`
25
+ \x1B[0m\x1B[?25h`)}}var Ua=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
26
+ `);function Um(_){return Boolean(_.isTTY)}async function Zt(_={}){let N=_.output??process.stdout;if(!Um(N))return;let j=_.input??process.stdin,J={output:N,seed:_.seed??Math.random()*8192,sleep:_.sleep};if(!j.isTTY||typeof j.setRawMode!=="function"){await ti(Ua,J);return}let Y=new AbortController,re=j.readableFlowing===!0,ie=j.isRaw===!0,de=!1,fe=(we,ke)=>{if(ke.ctrl&&ke.name==="c")de=!0;if(de||ke.name==="return"||ke.name==="enter")Y.abort()};Ga.emitKeypressEvents(j),j.on("keypress",fe),j.setRawMode(!0),j.resume();try{await ti(Ua,{...J,signal:Y.signal})}finally{if(j.off("keypress",fe),j.setRawMode(ie),!re)j.pause()}if(!de)return;if(_.onInterrupt){_.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as Km}from"node:crypto";import{existsSync as Va}from"node:fs";import{dirname as jr,join as Ka}from"node:path";import{dirname as Ba,join as Gm,resolve as Bm}from"node:path";var qm="rule.lock";function Vm(_){return Gm(Ba(_),qm)}function qa(_={}){return Bm(_.cwd??process.cwd(),".safety-net.json")}function hn(_,N){let j=N.global?N.userConfigPath??W(_,N):N.projectConfigPath??I(N.cwd??process.cwd()),J=N.global?st(_,N):at(j,N.cwd??process.cwd()),Y=Vm(j);return{configDir:Ba(j),configPath:j,lockPath:Y,filesystemScope:J,configTarget:i(J,j),lockTarget:i(J,Y)}}var Jm="`cc-safety-net rule sync` is deprecated: rulebooks are live files that need no synchronization. This run only migrates the lock and cache an earlier version left behind.",Wm="cache",zm="rulebooks";function Ja(_,N={}){let j=hn(_,N),J=i(j.filesystemScope,za(j.configDir)),Y=r(j.lockTarget);if(console.log(Jm),Y===null&&!Va(J.path))return console.log(`No v2 lock or cache leftovers found in ${jr(j.configDir)}; nothing to migrate.`),0;let re=eg(Y),ie=d(j.configTarget);if(!ie.config&&(r(j.configTarget)!==null||re.size>0))return console.error(`Cannot migrate: the rules config in ${jr(j.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let de=ie.config?.rules??[];for(let fe of de.flatMap((we)=>Ym(we,re,j,J,N.global===!0)))console.log(fe);return H(j.lockTarget),vt(J),console.log(`Removed the v2 lock and cache under ${jr(j.configDir)}.`),0}function Wa(_,N){return[...new Set([{cwd:N},{cwd:N,global:!0}].flatMap((j)=>{let J=hn(_,j);return[J.lockPath,za(J.configDir)]}))].filter((j)=>Va(j))}function Ym(_,N,j,J,Y){if(!C(_))return[];let re=L(_).name,ie=i(j.filesystemScope,M(j.configDir,re)),de=r(ie);if(de!==null&&Zm(de,re))return[];let fe=N.get(_),we=fe?Xm(fe,re,J.path,j.filesystemScope):null;if(we===null)return[`Could not migrate ${_} from the v2 cache. Run \`cc-safety-net rule update ${_}${Y?" --global":""}\` to vendor it.`];if(g(ie,we),de!==null)return[`Restored ${_} from the v2 cache over an invalid file.`];return[`Vendored ${_} from the v2 cache.`]}function Zm(_,N){let j=ve(_);return!("problem"in j)&&j.rulebook.name===N}function Xm(_,N,j,J){let Y=Ka(j,zm,`${Qm(_)}--${_.digest.replace("sha256:","").slice(0,12)}`,ge),re=r(i(J,Y));if(re===null||rg(re)!==_.digest)return null;let ie=ve(re);if("problem"in ie||ie.rulebook.name!==N)return null;return re}function za(_){return Ka(jr(_),Wm)}function Qm(_){return([_.owner,_.repo,_.display_ref,_.name].every((J)=>typeof J==="string"&&J!=="")?`${_.owner}/${_.repo}#${_.display_ref}/${_.name}`:_.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function eg(_){let N=_===null?null:tg(_),j=Ya(N)&&Array.isArray(N.rulebooks)?N.rulebooks:[];return new Map(j.filter(ng).map((J)=>[J.spec,J]))}function ng(_){return Ya(_)&&typeof _.spec==="string"&&typeof _.digest==="string"}function Ya(_){return!!_&&typeof _==="object"}function tg(_){try{return JSON.parse(_)}catch{return null}}function rg(_){return`sha256:${Km("sha256").update(_).digest("hex")}`}var Za="\r\x1B[2K",og="\x1B[?25l",ig="\x1B[39m",sg="\x1B[?25h",ag=100,lg=0.55,cg=80,Xa=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function dg(_){return new Promise((N)=>setTimeout(N,_))}async function Hr(_,N={}){let j=N.output??process.stdout;if(!j.isTTY)return _;let J=N.sleep??dg,Y=!1,re=_.then((de)=>(Y=!0,de),(de)=>{throw Y=!0,de});if(await Promise.race([re.then(()=>!0),J(ag).then(()=>!1)]))return re;j.write(og);try{for(let de=0;!Y;de+=1)j.write(`${Za}${Fa(de*lg)}${Xa[de%Xa.length]}${ig} ${N.loadingMessage??"Loading…"}`),await Promise.race([re,J(cg)]);return await re}finally{j.write(`${Za}${sg}`)}}async function Xt(_,N,j,J={}){let Y=N();if(_)await j();if(_&&Y.ready)await Hr(Y.ready,J);return Y.finish()}import{stripVTControlCharacters as ug}from"node:util";var Fr="amp plugins list",pg=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function Qa(_){if(!_.ampPluginListOutput)return{platform:"amp",status:"n/a"};let N=ug(_.ampPluginListOutput).split(`
27
+ `).map((j)=>pg.exec(j)?.[1]).find((j)=>j!==void 0);if(!N)return{platform:"amp",status:"n/a"};if(N!=="active")return{platform:"amp",status:"disabled",method:Fr,configPath:Fr,errors:[`Amp personal plugin cc-safety-net is ${N}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:Fr,configPath:Fr}}import{existsSync as wg,readFileSync as kg}from"node:fs";import{isAbsolute as aS,join as bg}from"node:path";function Qt(_){return bg(_,".gemini","config","hooks.json")}var el=new Map([["run_command","auto"]]),nl="manage_task";var Cg=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function xg(_){if(!_||typeof _!=="object"||Array.isArray(_))return[];return Object.values(_).flatMap((N)=>{if(!N||typeof N!=="object"||Array.isArray(N))return[];let j=N,J=j.PreToolUse;if(!Array.isArray(J))return[];return J.flatMap((Y)=>{if(!Y||typeof Y!=="object"||Array.isArray(Y))return[];let re=Y.hooks;if(!Array.isArray(re))return[];return re.flatMap((ie)=>{if(!ie||typeof ie!=="object"||Array.isArray(ie))return[];let de=ie.command;if(typeof de!=="string"||!Cg.test(de))return[];return[{command:de,enabled:j.enabled!==!1}]})})})}function tl(_){let N=Qt(_.environment.home);if(!wg(N))return{platform:"antigravity-cli",status:"n/a",configPath:N};let j;try{j=xg(JSON.parse(kg(N,"utf-8")))}catch(J){return{platform:"antigravity-cli",status:"n/a",configPath:N,errors:[`Failed to parse Antigravity hooks config ${N}: ${J instanceof Error?J.message:String(J)}`]}}if(j.some((J)=>J.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:N};if(j.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:N};return{platform:"antigravity-cli",status:"n/a",configPath:N}}import{existsSync as _g}from"node:fs";import{join as Nn}from"node:path";import{existsSync as Sg,lstatSync as Pg,readFileSync as Rg}from"node:fs";import{join as Eg}from"node:path";function vn(_,N=(j)=>j){if(!Sg(_))return{kind:"missing"};try{return{kind:"ok",value:JSON.parse(N(Rg(_,"utf-8")))}}catch{return{kind:"unreadable"}}}function Ln(_,N){if(_==="~")return N;if(_.startsWith("~/")||_.startsWith("~\\"))return Eg(N,_.slice(2));return _}function dn(_){try{return Pg(_)}catch{return}}function Br(_,N){let j=dn(N);if(!j)return{platform:_,status:"n/a",configPath:N};if(!j.isSymbolicLink()&&j.isDirectory())return;return{platform:_,status:"n/a",configPath:N,errors:[`${N} is a symlink or not a directory; move or remove it before installing`]}}function Ze(_,N){return typeof _==="object"&&_!==null?_[N]:void 0}var qr="cc-safety-net@cc-marketplace";function Vr(_){return _.env.get("CLAUDE_CONFIG_DIR")||Nn(_.home,".claude")}function rl(_){return Nn(_.env.get("CLAUDE_CODE_PLUGIN_CACHE_DIR")||Nn(Vr(_),"plugins"),"installed_plugins.json")}function ol(_,N){let j=Ze(Ze(_,"plugins"),N);return Array.isArray(j)&&j.length>0}function Kr(_,N){let j=vn(rl(_));return j.kind==="ok"&&ol(j.value,N)}function ii(_){return il(rl(_),Nn(Vr(_),"settings.json"))}function il(_,N){let j=vn(_);if(j.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(j.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!ol(j.value,qr))return{platform:"claude-code",status:"n/a"};let J=vn(N);if(J.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(J.kind==="ok"&&Ze(Ze(J.value,"enabledPlugins"),qr)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:N,errors:[`${qr} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:_}}function sl(_){let N=Nn(_.home,".claude"),j=Nn(N,"plugins","installed_plugins.json");if(il(j,Nn(N,"settings.json")).status!=="configured")return;let J=vn(j),Y=J.kind==="ok"?Ze(Ze(J.value,"plugins"),qr):void 0,re=(Array.isArray(Y)?Y:[]).filter((we)=>Ze(we,"scope")==="user").map((we)=>Ze(we,"installPath")).find((we)=>typeof we==="string");if(!re)return;let ie=Nn(re,".cursor-plugin","plugin.json"),de=vn(ie),fe=de.kind==="ok"?Ze(de.value,"hooks"):void 0;return typeof fe==="string"&&_g(Nn(re,fe))?ie:void 0}function al(_){return ii(_.environment)}var ll="Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it.";function cl(_){if(!_.codexPluginListOutput)return{platform:"codex",status:"n/a"};let N=_.codexPluginListOutput.split(`
28
+ `).find((j)=>j.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!N)return{platform:"codex",status:"n/a"};if(!N.includes("installed,"))return{platform:"codex",status:"n/a"};if(!N.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex runs only trusted hooks, and doctor cannot check trust. Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it."]}}import{existsSync as Yr,readdirSync as Tg,readFileSync as Ag}from"node:fs";import{join as wn}from"node:path";function yn(_){let N="",j=0,J=!1,Y=!1,re=-1;while(j<_.length){let ie=_[j],de=_[j+1];if(Y){N+=ie,Y=!1,j++;continue}if(ie==='"'&&!J){J=!0,re=-1,N+=ie,j++;continue}if(ie==='"'&&J){J=!1,N+=ie,j++;continue}if(ie==="\\"&&J){Y=!0,N+=ie,j++;continue}if(J){N+=ie,j++;continue}if(ie==="/"&&de==="/"){while(j<_.length&&_[j]!==`
29
+ `)j++;continue}if(ie==="/"&&de==="*"){j+=2;while(j<_.length-1){if(_[j]==="*"&&_[j+1]==="/"){j+=2;break}j++}continue}if(ie===","){re=N.length,N+=ie,j++;continue}if(ie==="}"||ie==="]"){if(re!==-1){let fe=N.slice(re+1);if(/^\s*$/.test(fe))N=N.slice(0,re)+fe}re=-1,N+=ie,j++;continue}if(!/\s/.test(ie))re=-1;N+=ie,j++}return N}function ul(_,N,j){let J=N+1,Y=!1;while(J<_.length){if(Y){Y=!1,J++;continue}if(_[J]==="\\"){Y=!0,J++;continue}if(_[J]==='"')return J+1;J++}throw Error(j)}function ai(_,N,j){let J=_[N],Y=J==="["?"]":"}",re=0,ie=N;while(ie<_.length){let de=j.skipComment?.(_,ie)??ie;if(de!==ie){ie=de;continue}if(_[ie]==='"'){ie=ul(_,ie,j.stringError);continue}if(_[ie]===J)re++;if(_[ie]===Y){if(re--,re===0)return ie}ie++}throw Error(j.bracketError)}function pl(_,N){let j=_.lastIndexOf(`
30
+ `,N)+1;return/^[ \t]*/.exec(_.slice(j))?.[0]??""}function fl(_,N){let j=N.end+(/^\s*/.exec(_.slice(N.end))?.[0].length??0);if(_[j]===","){let ie=_[j+1]===`
31
+ `?j+2:j+1;return`${_.slice(0,N.start)}${_.slice(ie)}`}let J=_.slice(0,N.start).search(/\s*$/)-1;if(_[J]!==",")return`${_.slice(0,N.start)}${_.slice(N.end)}`;let Y=_.lastIndexOf(`
32
+ `,J-1),re=Y!==-1&&/^\s*$/.test(_.slice(Y+1,J))?Y:J;return`${_.slice(0,re)}${_.slice(N.end)}`}function si(_,N){if(_.startsWith("//",N)){let j=_.indexOf(`
33
+ `,N+2);return j===-1?_.length:j+1}if(_.startsWith("/*",N)){let j=_.indexOf("*/",N+2);return j===-1?_.length:j+2}return N}function dl(_,N){let j=N;while(j<_.length){if(/\s/.test(_[j]??"")){j++;continue}let J=si(_,j);if(J===j)return j;j=J}return j}function ml(_,N,j){let J=0,Y=0;while(Y<_.length){let re=si(_,Y);if(re!==Y){Y=re;continue}if(_[Y]==='"'){let ie=ul(_,Y,j.stringError);if(J===1&&JSON.parse(_.slice(Y,ie))===N){let de=dl(_,ie),fe=dl(_,de+1);if(_[de]===":"&&_[fe]==="[")return{start:fe,end:ai(_,fe,{skipComment:si,...j})}}Y=ie;continue}if(_[Y]==="{"||_[Y]==="[")J++;if(_[Y]==="}"||_[Y]==="]")J--;Y++}return}var Tn="cc-safety-net@cc-marketplace",Jr=["cc-marketplace","cc-safety-net"],gl=["_direct","copilot-safety-net"],yl=["cc-marketplace","safety-net"],hl="safety-net@cc-marketplace";function Wr(_,N){let j=N.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${j}([^a-z0-9-]|$)`,"m").test(_??"")}function vl(_){return Wr(_,"cc-safety-net@cc-marketplace")}function bl(_){return Wr(_,"cc-marketplace")}function wl(_){return Wr(_,"copilot-safety-net")}function kl(_){return Wr(_,"safety-net@cc-marketplace")}function zr(_){if(!_?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(_)}function xl(_,N){if(!_)return null;let j=_.match(/(\d+)\.(\d+)\.(\d+)/);if(!j)return null;let J=[Number(j[1]),Number(j[2]),Number(j[3])];for(let Y=0;Y<N.length;Y++){let re=J[Y]??0,ie=N[Y]??0;if(re!==ie)return re>ie}return!0}function Ig(_){return xl(_,[0,0,422])}function Og(_){return xl(_,[1,0,8])}function tr(_){return _.env.get("COPILOT_HOME")||wn(_.home,".copilot")}function Sl(_){return _.disableAllHooks!==!0&&Pl(_)}function Pl(_){return(_.hooks?.preToolUse??[]).some((j)=>{if(j.type!==void 0&&j.type!=="command")return!1;return zr(j.command)||zr(j.bash)||zr(j.powershell)||zr(j.exec&&[j.exec,...j.args??[]].join(" "))})}function er(_){return _===void 0||typeof _==="string"}function $g(_){return _===void 0||Array.isArray(_)&&_.every((N)=>typeof N==="string")}function Dg(_){if(!_||typeof _!=="object"||Array.isArray(_))return!1;let N=_;if(N.disableAllHooks!==void 0&&typeof N.disableAllHooks!=="boolean")return!1;if(N.hooks===void 0)return!0;if(!N.hooks||typeof N.hooks!=="object"||Array.isArray(N.hooks))return!1;let j=N.hooks.preToolUse;if(j===void 0)return!0;return Array.isArray(j)&&j.every((J)=>J!==null&&typeof J==="object"&&!Array.isArray(J)&&er(J.type)&&er(J.command)&&er(J.bash)&&er(J.powershell)&&er(J.exec)&&$g(J.args))}function li(_,N){try{let j=JSON.parse(yn(Ag(_,"utf-8")));if(!Dg(j)){N?.push(`Invalid hook config ${_}: hooks.preToolUse must be an array of hook objects`);return}return j}catch(j){N?.push(`Failed to parse ${_}: ${j instanceof Error?j.message:String(j)}`);return}}function Rl(_,N){try{return Tg(_).filter((j)=>j.endsWith(".json")).sort((j,J)=>j.localeCompare(J))}catch(j){return N?.push(`Failed to read ${_}: ${j instanceof Error?j.message:String(j)}`),[]}}function Lg(_,N){if(!Yr(_))return[];let j=[];for(let J of Rl(_,N)){let Y=wn(_,J),re=li(Y,N);if(re&&Sl(re))j.push(Y)}return j}function nr(_,N){if(!Yr(_))return;let j=li(_,N);if(!j)return;return{path:_,config:j}}function Cl(_,N,j,J){if(N){_.push(`GitHub Copilot CLI ${N} does not support ${j}; requires ${J}+`);return}_.push(`GitHub Copilot CLI version unavailable; skipping ${j} because it requires ${J}+`)}function Ng(_){for(let N of _){if(N?.config.disableAllHooks===!0)return N.path;if(N?.config.disableAllHooks===!1)return}return}function jg(_,N,j,J){let Y=tr(_),re=wn(N,".github","hooks"),ie=wn(Y,"hooks"),de=wn(N,".github","copilot"),fe=wn(N,".claude"),we=Og(j),ke=we===!0?J:void 0,Re=[nr(wn(de,"settings.local.json"),ke),nr(wn(de,"settings.json"),ke),nr(wn(fe,"settings.local.json"),ke),nr(wn(fe,"settings.json"),ke)],Te=nr(wn(Y,"settings.json"),ke),Ee=[Te?.config.disableAllHooks===!0?void 0:Te];if(we!==!1){let nn=Ng(Re);if(nn){if(we===null)J.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${nn} as active`);return{activeConfigPaths:[],repoInlineSources:Re,disabledBy:nn}}}let De=Lg(re,J),He=Ig(j),Le=He===!0?J:void 0,Ye=Yr(ie)?Rl(ie,Le):[],tn=[];for(let nn of Ye){let an=wn(ie,nn),Sn=li(an,Le);if(Sn&&Sl(Sn))tn.push(an)}if(He!==!0&&tn.length>0)Cl(J,j,`user hook files in ${ie}`,"0.0.422"),tn.length=0;let rn=[];for(let nn of[...Re,...Ee]){if(!nn)continue;if(!Pl(nn.config))continue;if(we===!0){rn.push(nn);continue}Cl(J,j,"inline hook definitions in Copilot config files","1.0.8");break}let sn=(nn)=>nn.filter((an)=>!!an&&rn.includes(an)).map((an)=>an.path);return{activeConfigPaths:[...sn(Re),...De,...sn(Ee),...tn],repoInlineSources:Re}}function El(_){let N=[],j=jg(_.environment,_.cwd,_.copilotCliVersion,N);if(j.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:j.disabledBy,configPaths:[j.disabledBy],errors:N.length>0?N:void 0};let J=tr(_.environment),Y=wn(J,"installed-plugins",...Jr),re=Yr(Y),ie=wn(J,"settings.json"),de=vn(ie,yn),fe=(Ee)=>Ze(Ze(Ee,"enabledPlugins"),Tn),we=j.repoInlineSources.find((Ee)=>typeof fe(Ee?.config)==="boolean"),ke=we??(de.kind==="ok"?{path:ie,config:de.value}:void 0);if(re&&!we&&de.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};let Re=re&&ke!==void 0&&fe(ke.config)===!1;if(Re&&j.activeConfigPaths.length===0)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:ke.path,errors:[`${Tn} is installed but not enabled in Copilot CLI`]};let Te=re&&!Re;if(Te||j.activeConfigPaths.length>0){let Ee=j.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:Te?"plugin config":"hook config",configPath:Ee??(Te?Y:void 0),configPaths:j.activeConfigPaths.length>0?j.activeConfigPaths:void 0,errors:N.length>0?N:void 0}}return{platform:"copilot-cli",status:"n/a",errors:N.length>0?N:void 0}}import{existsSync as yi,readdirSync as Zg,readFileSync as Xg}from"node:fs";import{join as gi}from"node:path";import{existsSync as fi,mkdirSync as qg,readFileSync as Vg,rmSync as Kg}from"node:fs";import{dirname as Jg,join as Zr}from"node:path";import{existsSync as Hg,renameSync as Fg,statSync as Mg,writeFileSync as Ug}from"node:fs";function ln(_,N){let j=`${_}.${process.pid}.tmp`;Ug(j,N,Hg(_)?{mode:Mg(_).mode&511}:{}),Fg(j,_)}import{spawn as Gg}from"node:child_process";function Bg(_){return _.join(" ")}function ci(_,N,j){return[`Failed to run ${Bg(_)}${N===null?"":` (exit ${N})`}.`,j.trim()].filter(Boolean).join(`
34
+ `)}function di(_){let N={stdout:"",stderr:""};return _.stdout.setEncoding("utf-8"),_.stderr.setEncoding("utf-8"),_.stdout.on("data",(j)=>{N.stdout+=j}),_.stderr.on("data",(j)=>{N.stderr+=j}),N}function fn(_,N){return new Promise((j,J)=>{let Y=Xn([..._],process.env),re=Gg(Y.cmd,Y.args,{stdio:["ignore","pipe","pipe"]}),ie=di(re),de=()=>[ie.stdout,ie.stderr].filter(Boolean).join(`
35
+ `),fe=N?.timeoutMs??120000,we=setTimeout(()=>{re.kill(),J(Error(ci(_,null,`Timed out after ${fe}ms.
36
+ ${de()}`.trim())))},fe);re.on("error",(ke)=>{clearTimeout(we),J(Error(ci(_,null,`${ke.message}
37
+ ${de()}`.trim())))}),re.on("close",(ke)=>{if(clearTimeout(we),ke!==0){J(Error(ci(_,ke,de())));return}j(N?.stdoutOnly?ie.stdout:de())})})}async function ui(_){for(let N of _)await fn(N)}async function _l(_){for(let N of _)try{await fn(N)}catch(j){console.warn(j instanceof Error?j.message:String(j))}}var kn=Object.fromEntries(Yt.map((_)=>[_.id,`npx -y cc-safety-net hook ${_.flags[1]}`]));var or=kn.cursor,Tl=30;function Qr(_){return Zr(_.home,".cursor","hooks.json")}var rr="cc-safety-net";function mi(_){let N=Zr(_.home,".cursor","plugins");return{cache:Zr(N,"cache",rr),marketplaceClone:Zr(N,"marketplaces","github.com","kenryu42","cc-safety-net")}}async function Al(_){let N=Object.values(mi(_));if(!N.some((J)=>fi(J)))return;let j="No marketplace matches";return await fn(["cursor-agent","plugin","marketplace","remove",rr]).catch((J)=>{if(!(J instanceof Error&&J.message.includes(j)))throw J}),N.forEach((J)=>Kg(J,{recursive:!0,force:!0})),[`Removed the ${rr} marketplace from your Cursor account.`,"If /plugins in cursor-agent still lists CC Safety Net as installed, uninstall it there."].join(`
38
+ `)}function ot(_){return typeof _==="object"&&_!==null&&!Array.isArray(_)}function pi(){return{command:or,timeout:Tl,failClosed:!0}}function Xr(_){return ot(_)&&_.command===or}function Wg(_){return Object.keys(_).length===3&&_.command===or&&_.timeout===Tl&&_.failClosed===!0}function zg(_){try{return JSON.parse(Vg(_,"utf-8"))}catch(N){if(N instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${_}: ${N.message}`);throw N}}function Il(_){let N=zg(_);if(!ot(N))throw Error(`Cursor hooks config ${_} must be a JSON object`);if(N.version!==1)throw Error(`Cursor hooks config ${_} must set "version": 1`);if(N.hooks!==void 0&&!ot(N.hooks))throw Error(`Cursor hooks config ${_} "hooks" must be an object`);let j=ot(N.hooks)?N.hooks.preToolUse:void 0;if(j!==void 0&&!Array.isArray(j))throw Error(`Cursor hooks config ${_} "hooks.preToolUse" must be an array`);return N}function Ol(_){let N=ot(_.hooks)?_.hooks.preToolUse:void 0;return Array.isArray(N)?N:[]}function Yg(_){if(!_.some(Xr))return[..._,pi()];return _.reduce((N,j)=>{if(!Xr(j))return N.result.push(j),N;if(!N.inserted)N.result.push(pi()),N.inserted=!0;return N},{result:[],inserted:!1}).result}function $l(_,N,j){let J=ot(N.hooks)?N.hooks:{},Y={...N,hooks:{...J,preToolUse:j}};ln(_,`${JSON.stringify(Y,null,2)}
39
+ `)}function Dl(_){let N=Qr(_);if(!fi(N))return qg(Jg(N),{recursive:!0}),ln(N,`${JSON.stringify({version:1,hooks:{preToolUse:[pi()]}},null,2)}
40
+ `),{path:N,alreadyInstalled:!1};let j=Il(N),J=Ol(j),Y=J.filter(Xr);if(ot(j.hooks)&&Array.isArray(j.hooks.preToolUse)&&Y.length===1&&Y[0]!==void 0&&Wg(Y[0]))return{path:N,alreadyInstalled:!0};return $l(N,j,Yg(J)),{path:N,alreadyInstalled:!1}}function Ll(_){let N=Qr(_);if(!fi(N))return{path:N,alreadyInstalled:!1};let j=Il(N),J=Ol(j),Y=J.filter((re)=>!Xr(re));if(Y.length===J.length)return{path:N,alreadyInstalled:!1};return $l(N,j,Y),{path:N,alreadyInstalled:!0}}function Qg(_){if(!_||typeof _!=="object"||Array.isArray(_))return[];let N=_.hooks;if(!N||typeof N!=="object"||Array.isArray(N))return[];let j=N.preToolUse;if(!Array.isArray(j))return[];return j.filter((J)=>!!J&&typeof J==="object"&&!Array.isArray(J)&&J.command===or)}function ey(_){let N=[];if(_.length>1)N.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let j=_[0];if(j&&j.failClosed!==!0)N.push('Managed hook is missing "failClosed": true; reinstall to repair');if(j&&j.timeout!==30)N.push('Managed hook "timeout" is not 30; reinstall to repair');return N}var eo="Claude Code plugin",hi="Cursor plugin";function ny(_){let N=gi(mi(_).cache,rr);if(!yi(N))return{};try{return{version:Zg(N).map((j)=>gi(N,j)).find((j)=>yi(gi(j,".cache-complete")))}}catch{return{unreadable:N}}}function ty(_,N){if(N){let Y=["Cursor records enabled plugins on your Cursor account, which doctor cannot check, and keeps a plugin's files after it is uninstalled.","Cursor pins marketplace plugins to the commit they were added at, so `cc-safety-net update` cannot update this plugin, while the npx hook (`cc-safety-net install --cursor`) stays current."].join(" ");return{method:hi,configPath:N,duplicate:`The Cursor plugin also runs this check, so every tool call is checked twice. ${Y} If the plugin is installed, run \`cc-safety-net uninstall --cursor\`, uninstall CC Safety Net from /plugins in cursor-agent, then run \`cc-safety-net install --cursor\`.`,alone:`${Y} If /plugins in cursor-agent does not list CC Safety Net as installed, run \`cc-safety-net install --cursor\`.`}}let j=sl(_);if(!j)return;let J="Cursor runs the Claude Code plugin only while it imports Claude Code plugins, which doctor cannot check.";return{method:eo,configPath:j,duplicate:`The Claude Code plugin also runs this check in Cursor, so every tool call is checked twice. ${J} If Cursor runs it, run \`cc-safety-net uninstall --cursor\` to remove this hook.`,alone:`${J} If it stops, run \`cc-safety-net install --cursor\`.`}}function Nl(_){let N=ry(_),j=ny(_.environment);if(j.unreadable)return N.status==="configured"?{...N,errors:[...N.errors??[],`Cannot read ${j.unreadable}, so doctor cannot tell whether the Cursor plugin also runs this check.`]}:{platform:"cursor",status:"not-inspected"};let J=ty(_.environment,j.version);if(!J)return N;if(N.status==="configured")return{...N,errors:[...N.errors??[],J.duplicate]};return{platform:"cursor",status:"configured",method:J.method,configPath:J.configPath,errors:[...N.errors??[],J.alone]}}function ry(_){let N=Qr(_.environment);if(!yi(N))return{platform:"cursor",status:"n/a",configPath:N};let j;try{j=JSON.parse(Xg(N,"utf-8"))}catch(re){return{platform:"cursor",status:"n/a",configPath:N,errors:[`Failed to parse Cursor hooks config ${N}: ${re instanceof Error?re.message:String(re)}`]}}let J=Qg(j);if(J.length===0)return{platform:"cursor",status:"n/a",configPath:N};let Y=ey(J);return{platform:"cursor",status:"configured",method:"hook config",configPath:N,errors:Y.length>0?Y:void 0}}import{readdirSync as oy}from"node:fs";import{join as vi,resolve as iy}from"node:path";var bi="cc-safety-net";function wi(_){let N=_.env.get("DSH_HOME");return vi(N?.trim()?iy(Ln(N,_.home)):vi(_.home,".dsh"),"profiles")}function jl(_){let N=wi(_),j=dn(N)?.isDirectory()?oy(N,{withFileTypes:!0}).filter((Y)=>Y.isDirectory()&&Y.name!=="node_modules").map((Y)=>{let re=vi(N,Y.name,"package.json");return{name:Y.name,configPath:re,manifest:vn(re)}}):[];return{installed:j.flatMap((Y)=>{if(Y.manifest.kind!=="ok")return[];let re=Y.manifest.value;if(Ze(Ze(re,"dependencies"),bi)===void 0)return[];let ie=Ze(Ze(Ze(re,"dsh"),"profile"),"bundles");return[{name:Y.name,configPath:Y.configPath,enabled:Array.isArray(ie)&&ie.includes(bi)}]}),unreadable:j.some((Y)=>Y.manifest.kind==="unreadable")}}function ki(_){return jl(_).installed}function Hl(_){let N=jl(_.environment),j=N.installed.filter((re)=>re.enabled),J=N.installed.filter((re)=>!re.enabled),Y=J.map((re)=>`${bi} is installed in the ${re.name} profile but its bundle is disabled`);if(j.length>0)return{platform:"deepseek-harness",status:"configured",method:"dsh bundle",configPaths:j.map((re)=>re.configPath),...Y.length>0?{errors:Y}:{}};if(J.length>0)return{platform:"deepseek-harness",status:"disabled",method:"dsh bundle",configPaths:J.map((re)=>re.configPath),errors:Y};return N.unreadable?{platform:"deepseek-harness",status:"not-inspected"}:{platform:"deepseek-harness",status:"n/a"}}import{existsSync as uy}from"node:fs";import{existsSync as Ul,mkdirSync as sy,readFileSync as ay}from"node:fs";import{dirname as ly,join as Si}from"node:path";function Ci(_){return typeof _==="object"&&_!==null&&!Array.isArray(_)}function xi(_,N){return Ci(_)&&_.command===N}function Fl(_,N){return Ci(_)&&Array.isArray(_.hooks)&&_.hooks.some((j)=>xi(j,N))}function ft(_,N){return{hooks:[{type:"command",command:_,timeout:N}]}}function jn(_,N){return _.flatMap((j)=>{if(!Ci(j)||!Array.isArray(j.hooks))return[j];let J=j.hooks.filter((Y)=>!xi(Y,N));if(J.length===j.hooks.length)return[j];return J.length===0?[]:[{...j,hooks:J}]})}function Ht(_,N,j){let J=_.filter((Y)=>Fl(Y,N));return J.length===1&&JSON.stringify(J[0])===JSON.stringify(ft(N,j))}function Ft(_,N){return _.find((j)=>Fl(j,N))}function Mt(_,N,j){let J=Array.isArray(_.hooks)?_.hooks.find((Y)=>xi(Y,N)):void 0;return[..._.matcher===void 0||_.matcher===""||_.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...J?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...J?.timeout===j?[]:[`Managed hook "timeout" is not ${j}; reinstall to repair`]]}var mt=kn.devin,no=30,cy={config:{},hooks:{},preToolUse:[]};function to(_,N=process.platform){let j=N==="win32"?_.env.get("APPDATA")||Si(_.home,"AppData","Roaming"):_.env.get("XDG_CONFIG_HOME")||Si(_.home,".config");return Si(j,"devin","config.json")}function Ml(_){return typeof _==="object"&&_!==null&&!Array.isArray(_)}function dy(_){try{return{ok:!0,value:JSON.parse(yn(ay(_,"utf-8")))}}catch(N){return{ok:!1,message:N instanceof Error?N.message:String(N)}}}function Pi(_){let N=dy(_);if(!N.ok)return`Failed to parse Devin CLI config ${_}: ${N.message}`;let j=N.value;if(!Ml(j))return`Devin CLI config ${_} must be a JSON object`;let J=j.hooks===void 0?{}:j.hooks;if(!Ml(J))return`Devin CLI config ${_} "hooks" must be an object`;let Y=J.PreToolUse===void 0?[]:J.PreToolUse;if(!Array.isArray(Y))return`Devin CLI config ${_} "hooks.PreToolUse" must be an array`;return{config:j,hooks:J,preToolUse:Y}}function Gl(_){let N=Pi(_);if(typeof N==="string")throw Error(N);return N}function Bl(_,N,j){let J={...N.config,hooks:{...N.hooks,PreToolUse:j}};ln(_,`${JSON.stringify(J,null,2)}
41
+ `)}function ql(_){let N=to(_),j=Ul(N)?Gl(N):cy;if(Ht(j.preToolUse,mt,no))return{path:N,alreadyInstalled:!0};return sy(ly(N),{recursive:!0}),Bl(N,j,[...jn(j.preToolUse,mt),ft(mt,no)]),{path:N,alreadyInstalled:!1}}function Vl(_){let N=to(_);if(!Ul(N))return{path:N,alreadyInstalled:!1};let j=Gl(N),J=jn(j.preToolUse,mt);if(JSON.stringify(J)===JSON.stringify(j.preToolUse))return{path:N,alreadyInstalled:!1};return Bl(N,j,J),{path:N,alreadyInstalled:!0}}function Kl(_){let N=to(_.environment);if(!uy(N))return{platform:"devin",status:"n/a",configPath:N};let j=Pi(N);if(typeof j==="string")return{platform:"devin",status:"n/a",configPath:N,errors:[j]};let J=Ft(j.preToolUse,mt);if(!J)return{platform:"devin",status:"n/a",configPath:N};let Y=Mt(J,mt,no);return{platform:"devin",status:"configured",method:"hook config",configPath:N,errors:Y.length>0?Y:void 0}}import{existsSync as by,readFileSync as wy}from"node:fs";import{existsSync as ir,mkdirSync as py,readFileSync as fy,rmSync as my}from"node:fs";import{dirname as gy,join as Ei}from"node:path";var gt=kn.droid,ro=30;function oo(_){return Ei(_.home,".factory","hooks.json")}function Jl(_){return Ei(_.home,".factory","settings.json")}function yy(_){return Ei(_.home,".factory","hooks","hooks.json")}function Ri(_){return typeof _==="object"&&_!==null&&!Array.isArray(_)}function Wl(_){try{return JSON.parse(yn(fy(_,"utf-8")))}catch(N){if(N instanceof SyntaxError)throw Error(`Failed to parse Factory Droid hooks config ${_}: ${N.message}`);throw N}}function _i(_){let N=Wl(_);if(!Ri(N))throw Error(`Factory Droid hooks config ${_} must be a JSON object`);if(N.PreToolUse===void 0||Array.isArray(N.PreToolUse))return N;throw Error(`Factory Droid hooks config ${_} "PreToolUse" must be an array`)}function hy(_){if(!ir(_))return{};let N=Wl(_);return Ri(N)&&Ri(N.hooks)&&N.hooks.PreToolUse!==void 0?{PreToolUse:N.hooks.PreToolUse}:{}}function vy(_){let N=yy(_);return{...hy(Jl(_)),...ir(N)?_i(N):{}}}function zl(_){return Array.isArray(_.PreToolUse)?_.PreToolUse:[]}function Yl(_,N,j){ln(_,`${JSON.stringify({...N,PreToolUse:j},null,2)}
42
+ `)}function Zl(_){let N=oo(_),j=ir(N),J=j?_i(N):vy(_),Y=zl(J);if(j&&Ht(Y,gt,ro))return{path:N,alreadyInstalled:!0};return py(gy(N),{recursive:!0}),Yl(N,J,[...jn(Y,gt),ft(gt,ro)]),{path:N,alreadyInstalled:!1}}function Xl(_){let N=oo(_);if(!ir(N))return{path:N,alreadyInstalled:!1};let j=_i(N),J=zl(j),Y=jn(J,gt);if(JSON.stringify(Y)===JSON.stringify(J))return{path:N,alreadyInstalled:!1};let re=ir(Jl(_));if(Y.length===0&&Object.keys(j).length===1&&!re)return my(N),{path:N,alreadyInstalled:!0};return Yl(N,j,Y),{path:N,alreadyInstalled:!0}}function Ql(_){let N=oo(_.environment);if(!by(N))return{platform:"droid",status:"n/a",configPath:N};let j;try{j=JSON.parse(yn(wy(N,"utf-8")))}catch(ie){return{platform:"droid",status:"n/a",configPath:N,errors:[`Failed to parse Factory Droid hooks config ${N}: ${ie instanceof Error?ie.message:String(ie)}`]}}let J=typeof j==="object"&&j!==null&&"PreToolUse"in j?j.PreToolUse:void 0,Y=Ft(Array.isArray(J)?J:[],gt);if(!Y)return{platform:"droid",status:"n/a",configPath:N};let re=[...Y.commandRegex===void 0||Y.commandRegex===""?[]:['Managed hook has a "commandRegex" that narrows coverage; reinstall to repair'],...Mt(Y,gt,ro)];return{platform:"droid",status:"configured",method:"hook config",configPath:N,errors:re.length>0?re:void 0}}import{existsSync as ky}from"node:fs";import{join as Ti}from"node:path";var Ai="gemini-safety-net";function Ii(_){let N=Ti(_.home,".gemini","extensions"),j=Ti(N,Ai);if(!ky(j))return{platform:"gemini-cli",status:"n/a"};let J=Ti(N,"extension-enablement.json"),Y=vn(J);if(Y.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let re=Y.kind==="ok"?Ze(Ze(Y.value,Ai),"overrides"):void 0;if(Array.isArray(re)&&re.some((de)=>typeof de==="string"&&de.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:J,errors:[`${Ai} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:j}}function ec(_){return Ii(_.environment)}import{existsSync as Py,readFileSync as cc,statSync as Ry}from"node:fs";import{dirname as lc,join as Ey}from"node:path";import{existsSync as tc,mkdirSync as Cy,readFileSync as rc,rmSync as xy}from"node:fs";import{dirname as Sy,join as nc}from"node:path";var Bn=kn["grok-build"],so=30,Oi=ft(Bn,so);function ao(_){return nc(_.env.get("GROK_HOME")??nc(_.home,".grok"),"hooks","cc-safety-net.json")}function lo(_){return typeof _==="object"&&_!==null&&!Array.isArray(_)}function oc(_){try{let N=JSON.parse(_);return lo(N)?N:null}catch{return null}}function ic(_){let N=lo(_.hooks)?_.hooks.PreToolUse:void 0;return Array.isArray(N)?N:[]}function io(_,N,j){let J=lo(N.hooks)?N.hooks:{};ln(_,`${JSON.stringify({...N,hooks:{...J,PreToolUse:j}},null,2)}
43
+ `)}function sc(_){let N=ao(_);if(!tc(N))return Cy(Sy(N),{recursive:!0}),io(N,{},[Oi]),{path:N,alreadyInstalled:!1};let j=oc(rc(N,"utf-8"));if(!j)return io(N,{},[Oi]),{path:N,alreadyInstalled:!1};let J=ic(j);if(Ht(J,Bn,so))return{path:N,alreadyInstalled:!0};return io(N,j,[...jn(J,Bn),Oi]),{path:N,alreadyInstalled:!1}}function ac(_){let N=ao(_);if(!tc(N))return{path:N,alreadyInstalled:!1};let j=oc(rc(N,"utf-8"));if(!j)return{path:N,alreadyInstalled:!1};let J=ic(j),Y=jn(J,Bn);if(JSON.stringify(Y)===JSON.stringify(J))return{path:N,alreadyInstalled:!1};let re=lo(j.hooks)?j.hooks:{};if(Y.length===0&&Object.keys(j).length===1&&Object.keys(re).length===1)return xy(N),{path:N,alreadyInstalled:!0};return io(N,j,Y),{path:N,alreadyInstalled:!0}}function $i(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}function _y(_){try{return Ry(_,{throwIfNoEntry:!1})?.isFile()===!0?cc(_,"utf-8"):""}catch{return}}function dc(_){let N=ao(_.environment);if(!Py(N))return{platform:"grok-build",status:"n/a",configPath:N};let j;try{j=JSON.parse(cc(N,"utf-8"))}catch(Re){return{platform:"grok-build",status:"n/a",configPath:N,errors:[`Failed to parse Grok Build hooks config ${N}: ${Re instanceof Error?Re.message:String(Re)}`]}}let J=$i(j)&&$i(j.hooks)&&Array.isArray(j.hooks.PreToolUse)?j.hooks.PreToolUse:[],Y=Ft(J,Bn);if(!Y)return{platform:"grok-build",status:"n/a",configPath:N};let re=Array.isArray(Y.hooks)?Y.hooks.findIndex((Re)=>$i(Re)&&Re.command===Bn):-1,ie=`global/cc-safety-net:pre_tool_use[${J.indexOf(Y)}].hooks[${re}]`,de=Ey(lc(lc(N)),"disabled-hooks"),fe=_y(de),we=fe?.split(`
44
+ `).some((Re)=>Re.trim()===ie)===!0,ke=[...fe===void 0?[`Cannot read ${de}, so doctor cannot tell whether Grok Build skips the hook`]:[],...we?[`Grok Build skips the hook: ${ie} is listed in ${de}; enable it in /hooks`]:[],...Mt(Y,Bn,so)];return{platform:"grok-build",status:we?"disabled":"configured",method:"hook config",configPath:N,errors:ke.length>0?ke:void 0}}import{readFileSync as bc}from"node:fs";import{join as wc}from"node:path";var Pn="cc-safety-net",Di="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",Ty=30;function uc(_){return`${Di}
45
+ # version: ${_}
46
+ `}function Ay(_){return`${uc(_)}name: ${Pn}
47
+ version: "${_}"
47
48
  description: "Block destructive commands and secret-file access before Hermes runs a tool."
48
49
  author: "cc-safety-net"
49
50
  provides_hooks:
50
51
  - pre_tool_call
51
- `}function Rg(P){return`${Nl(P)}"""CC Safety Net guard for Hermes Agent.
52
+ `}function Iy(_){return`${uc(_)}"""CC Safety Net guard for Hermes Agent.
52
53
 
53
54
  Registers pre_tool_call and forwards the tool call to the packaged CC Safety Net
54
55
  adapter (cc-safety-net hook --hermes-agent) over JSON stdin. The adapter prints nothing
@@ -64,8 +65,8 @@ import subprocess
64
65
 
65
66
  HOOK_EVENT = "pre_tool_call"
66
67
  SUPPORTED_TOOLS = ("patch", "read_file", "terminal", "write_file")
67
- ANALYZER = [${Cn["hermes-agent"].split(" ").map((O)=>`"${O}"`).join(", ")}]
68
- TIMEOUT_SECONDS = ${Sg}
68
+ ANALYZER = [${kn["hermes-agent"].split(" ").map((N)=>`"${N}"`).join(", ")}]
69
+ TIMEOUT_SECONDS = ${Ty}
69
70
 
70
71
 
71
72
  def _block(detail):
@@ -218,82 +219,85 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
218
219
 
219
220
  def register(ctx):
220
221
  ctx.register_hook("pre_tool_call", _pre_tool_call)
221
- `}function Wt(P){return[{name:"__init__.py",content:Rg(P)},{name:"plugin.yaml",content:Pg(P)}]}import{mkdirSync as Eg,readdirSync as _g,readFileSync as jl,rmSync as gi}from"node:fs";import{basename as Ag,dirname as Tg,join as Fn}from"node:path";var Ig="__pycache__",$g=/^[a-z0-9][a-z0-9_-]{0,63}$/;function Og(P){try{return jl(P,"utf-8").trim()}catch{return}}function yi(P){let O=P.env.get("HERMES_HOME")?.trim();if(O&&Ag(Tg(O))==="profiles")return O;let D=O||Fn(P.home,".hermes"),j=Fn(D,"active_profile"),J=Og(j),Y=J?.toLowerCase();if(!Y||Y==="default")return D;if(!$g.test(Y))throw Error(`Invalid Hermes profile name "${J}" in ${j}; run \`hermes profile use <name>\` with a valid profile.`);return Fn(D,"profiles",Y)}function hi(P){return Fn(yi(P),"plugins",Rn)}function vi(P){return P.startsWith(mi)}function bi(P,O){let D=hi(P),j=dn(D);if(j&&(j.isSymbolicLink()||!j.isDirectory()))throw Error(`Refusing to ${O} ${D}: not a regular directory. Move or remove it and rerun ${O==="install"?"install":"uninstall"} --hermes-agent.`);return D}function Fl(P,O){let D=dn(P);if(!D)return;if(D.isSymbolicLink()||!D.isFile())throw Error(`Refusing to ${O} ${P}: not a regular file. Move or remove it.`);let j=jl(P,"utf-8");if(!vi(j))throw Error(`Refusing to ${O} unmanaged file at ${P}. Move or remove it.`);return j}function Hl(P){let O=bi(P,"install"),D=Wt(pn());if(D.map((J)=>Fl(Fn(O,J.name),"overwrite")).every((J,Y)=>J===D[Y]?.content))return{path:O,alreadyInstalled:!0};return Eg(O,{recursive:!0}),D.forEach((J)=>{cn(Fn(O,J.name),J.content)}),{path:O,alreadyInstalled:!1}}function wi(P){let O=bi(P,"remove");if(!dn(O))return[];return Wt(pn()).filter((D)=>Fl(Fn(O,D.name),"remove")!==void 0)}function Ml(P){let O=bi(P,"remove");if(!dn(O))return{path:O,alreadyInstalled:!1};let D=wi(P);if(D.forEach((j)=>{gi(Fn(O,j.name))}),gi(Fn(O,Ig),{recursive:!0,force:!0}),_g(O).length===0)gi(O,{recursive:!0});return{path:O,alreadyInstalled:D.length>0}}var zt="hermes-agent",Ul=/^([^\s#][^:]*):/,Dg=/^\s+([A-Za-z_][\w-]*):/,Gl=/^\s+-\s*(.*)$/;function Lg(P){return P.trim().replace(/^(["'])(.*)\1$/,"$2")}function Ng(P){let O=P.split(/\r?\n/),D=O.findIndex((Y)=>Ul.exec(Y)?.[1]?.trim()==="plugins");if(D===-1)return[];let j=O.slice(D+1),J=j.findIndex((Y)=>Ul.test(Y));return J===-1?j:j.slice(0,J)}function ql(P,O){let D=Ng(P),j=D.findIndex((re)=>Dg.exec(re)?.[1]===O);if(j===-1)return[];let J=D.slice(j+1),Y=J.findIndex((re)=>!Gl.test(re));return(Y===-1?J:J.slice(0,Y)).map((re)=>Lg(Gl.exec(re)?.[1]??""))}function jg(P){try{return Bl(Vl(yi(P),"config.yaml"),"utf-8")}catch{return}}function ki(P){let O=jg(P)??"";return ql(O,"enabled").includes(Rn)&&!ql(O,"disabled").includes(Rn)}function Jl(P){return/^# version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function Fg(P,O){let D=dn(P);if(!D)return{error:`${O.name} is missing from ${P}; run install --hermes-agent`};if(D.isSymbolicLink()||!D.isFile())return{error:`${P} is a symlink or not a regular file; move or remove it`};try{let j=Bl(P,"utf-8");if(!vi(j))return{error:`Unmanaged ${O.name} occupies ${P}; move or remove it`};if(Jl(j)===pn()&&j!==O.content)return{error:`Modified ${O.name} occupies ${P}; run install --hermes-agent to restore it`};return{content:j}}catch(j){return{error:`Failed to read ${P}: ${j instanceof Error?j.message:String(j)}`}}}function Hg(P){try{return{path:hi(P)}}catch(O){return{error:O instanceof Error?O.message:String(O)}}}function Kl(P){let O=Hg(P.environment);if("error"in O)return{platform:zt,status:"n/a",errors:[O.error]};let D=O.path,j=Ar(zt,D);if(j)return j;let J=Wt(pn()).map((de)=>Fg(Vl(D,de.name),de)),Y=J.flatMap((de)=>("error"in de)?[de.error]:[]);if(Y.length>0)return{platform:zt,status:"n/a",configPath:D,errors:Y};let re=J.some((de)=>("content"in de)&&Jl(de.content)!==pn()),ie=re?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!ki(P.environment))return{platform:zt,status:"disabled",method:"plugin directory",configPath:D,errors:[`${Rn} is not enabled in Hermes; run \`hermes plugins enable ${Rn}\``,...ie]};return{platform:zt,status:"configured",method:"plugin directory",configPath:D,errors:re?ie:void 0}}import{existsSync as Mg,readFileSync as Ug}from"node:fs";import{join as Wl}from"node:path";var Gg=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/;function qg(P){return Wl(P.env.get("KIMI_CODE_HOME")||Wl(P.home,".kimi-code"),"config.toml")}function Yt(P){let O=qg(P.environment);if(!Mg(O))return{platform:"kimi-code",status:"n/a",configPath:O};try{if(!Gg.test(Ug(O,"utf-8")))return{platform:"kimi-code",status:"n/a",configPath:O}}catch(D){return{platform:"kimi-code",status:"n/a",configPath:O,errors:[`Failed to read ${O}: ${D instanceof Error?D.message:String(D)}`]}}return{platform:"kimi-code",status:"configured",method:"hook config",configPath:O}}import{readFileSync as rc}from"node:fs";import{join as Xt}from"node:path";var un="cc-safety-net",Pn="index.js",Tt="openclaw.plugin.json",It="package.json";var Zr="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as Bg,lstatSync as Vg,readdirSync as Jg,readFileSync as Kg}from"node:fs";import{dirname as zl,join as qn}from"node:path";import{fileURLToPath as Wg}from"node:url";var xi=qn("openclaw",un),it=`run \`openclaw plugins enable ${un}\``,zg="config reload superseded by a newer runtime config source",Yg=[Pn,Tt,It];function Yl(P){let O=P.env.get("OPENCLAW_HOME")?.trim();return O?Nn(O,P.home):P.home}function Zl(P){let O=Yl(P),D=P.env.get("OPENCLAW_STATE_DIR")?.trim();if(D)return Nn(D,O);let j=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return j?zl(Nn(j,O)):qn(O,".openclaw")}function Xl(P){let O=P.env.get("OPENCLAW_CONFIG_PATH")?.trim();return O?Nn(O,Yl(P)):qn(Zl(P),"openclaw.json")}function Zt(P){return qn(Zl(P),"extensions",un)}function Zg(P){let O=Jg(P);if(O.length===0)return!0;if(O.some((J)=>!Yg.includes(J)))return!1;let D=qn(P,Pn),j=dn(D);return j!==void 0&&!j.isSymbolicLink()&&j.isFile()&&Kg(D,"utf-8").startsWith(Zr)}function Ci(P){let O=Zt(P),D=dn(O);if(!D)return;if(!D.isSymbolicLink()&&D.isDirectory()&&Zg(O))return;throw Error(`Refusing to modify ${O}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Ql(){let P=zl(Wg(import.meta.url));return[qn(P,xi),qn(P,"..",xi),qn(P,"..","..","..","dist",xi)]}function Si(P=Ql()){return P.find((O)=>Bg(O)&&Vg(O).isDirectory())}function Xg(P=Ql()){let O=Si(P);if(!O)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return O}function ec(P=Xg()){return[["openclaw","plugins","install",P,"--force","--accept-capabilities"]]}function Qg(P){let O=(()=>{try{return JSON.parse(P)}catch{return}})(),D=tn(tn(O,"plugin"),"status");return typeof D==="string"?D:void 0}async function ey(){await gn(["openclaw","plugins","enable",un]).catch((P)=>{if(!(P instanceof Error&&P.message.includes(zg)))throw P})}async function nc(P){let O=async()=>Qg(await gn(["openclaw","plugins","inspect",un,"--runtime","--json"],{stdoutOnly:!0})),D=await O(),j=D==="disabled"&&P;if(j)await ey();let J=j?await O():D;if(J==="loaded")return;throw Error(`${J===void 0?`The ${un} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:J==="disabled"?`OpenClaw reports the ${un} plugin with status "disabled"; ${it}.`:`OpenClaw reports the ${un} plugin with status "${J}".`} Run \`openclaw plugins inspect ${un} --runtime\` for details.`)}var Xr="openclaw";function $t(P,O){let D=Xt(P,O),j=dn(D);if(!j)return{error:`${O} is missing from ${D}; run install --openclaw`};if(j.isSymbolicLink()||!j.isFile())return{error:`${D} is a symlink or not a regular file; move or remove it`};try{return{content:rc(D,"utf-8")}}catch(J){return{error:`Failed to read ${D}: ${J instanceof Error?J.message:String(J)}`}}}function oc(P){try{return JSON.parse(vn(P))}catch{return}}function ny(P){let O=$t(P,Tt);if("error"in O)return O.error;if(tn(oc(O.content),"id")===un)return;return`${Xt(P,Tt)} is not a valid ${un} manifest; run install --openclaw`}function ty(P){let O=$t(P,It);if("error"in O)return O.error;let D=tn(tn(oc(O.content),"openclaw"),"extensions");if(Array.isArray(D)&&D.includes(`./${Pn}`))return;return`${Xt(P,It)} does not point OpenClaw at ${Pn}; run install --openclaw`}function tc(P){return Array.isArray(P)?P.filter((O)=>typeof O==="string"):[]}function ry(P){let O=Xl(P);if(!dn(O))return`${un} is not enabled; ${it}`;let D=(()=>{try{return JSON.parse(vn(rc(O,"utf-8")))}catch{return}})();if(D===void 0)return`Failed to read ${O}; fix it, then ${it}`;let j=tn(D,"plugins");if(tn(j,"enabled")===!1)return`plugins.enabled is false in ${O}; no OpenClaw plugin loads`;let J=tn(tn(tn(j,"entries"),un),"enabled");if(tc(tn(j,"deny")).includes(un)||J===!1)return`${un} is disabled in ${O}; ${it}`;let Y=tc(tn(j,"allow"));if(Y.length>0&&!Y.includes(un))return`plugins.allow in ${O} does not list ${un}; add it, then ${it}`;if(Y.includes(un)||J===!0)return;return`${un} is not enabled; ${it}`}function ic(P){return/^\/\/ version:\s*(.+)$/m.exec(P)?.[1]?.trim()}function oy(P,O,D){if(D===void 0)return[];let j=$t(D,Pn);if(!(("content"in j)&&ic(j.content)===O))return[];return[Pn,Tt,It].flatMap((Y)=>{let re=$t(P,Y),ie=$t(D,Y);if("error"in re||"error"in ie||re.content===ie.content)return[];return[`Modified ${Y} occupies ${Xt(P,Y)}; run install --openclaw to restore it`]})}function sc(P){let O=Zt(P.environment),D=Ar(Xr,O);if(D)return D;let j=$t(O,Pn),Y=["error"in j?j.error:j.content.startsWith(Zr)?void 0:`Unmanaged ${Pn} occupies ${Xt(O,Pn)}; move or remove it`,ny(O),ty(O)].filter((we)=>we!==void 0),re="content"in j?ic(j.content):void 0,ie=Y.length>0?Y:oy(O,re,Si());if(ie.length>0)return{platform:Xr,status:"n/a",configPath:O,errors:ie};let de=re===pn()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],fe=ry(P.environment);if(fe)return{platform:Xr,status:"disabled",method:"plugin directory",configPath:O,errors:[fe,...de]};return{platform:Xr,status:"configured",method:"plugin directory",configPath:O,errors:de.length>0?de:void 0}}import{existsSync as fy,readFileSync as my}from"node:fs";import{basename as gy}from"node:path";import{existsSync as Qr,readFileSync as Pi,rmSync as iy}from"node:fs";import{join as Tn}from"node:path";import{pathToFileURL as sy}from"node:url";var Qt="cc-safety-net",pt=`${Qt}@latest`,Ri=["opencode.json","opencode.jsonc"],ay=60,ly=250,ac="CCSafetyNetPlugin",cy={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function lc(P){return Tn(P.env.get("XDG_CONFIG_HOME")||Tn(P.home,".config"),"opencode")}function Ei(P){return P.env.get("OPENCODE_CONFIG_DIR")||lc(P)}function _i(P){return Ri.map((O)=>Tn(Ei(P),O))}function Ai(P){return[...new Set([Ei(P),lc(P)])].flatMap((O)=>Ri.map((D)=>Tn(O,D)))}function cc(P){return Tn(P.env.get("XDG_CACHE_HOME")||Tn(P.home,".cache"),"opencode","packages",pt)}function dc(P){iy(cc(P),{recursive:!0,force:!0})}async function uc(P){let O=(await gn(["opencode","--version"],{stdoutOnly:!0})).trim(),D=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(O),j=Number(D?.[1]),J=Number(D?.[2]),Y=Number(D?.[3]);if(!D||j!==1&&j!==2||j===1&&(J<18||J===18&&Y<29)||j===2&&J===0&&Y<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${O||"an unknown version"}.`);if(j===2){for(let re of _i(P)){if(!Qr(re))continue;let ie=Ii(Pi(re,"utf-8"),re);if(["plugin","plugins"].some((fe)=>{let we=tn(ie,fe);return Array.isArray(we)&&we.some((Ce)=>eo(Ce)&&(typeof Ce==="string"?Ce:tn(Ce,"package"))!==pt)}))throw Error(`Change the cc-safety-net package spec in ${re} to ${pt}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[],afterInstall:async()=>{if((await gn(["opencode","plugin","add",pt],{stdoutOnly:!0})).includes("is already configured in"))await gn(["opencode","plugin","update",pt]);let ie=await mc();if(!/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(ie))throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.");let de=["--param",`location[directory]=${process.cwd()}`];await gn(["opencode","api","integration.list",...de]);let fe=await gn(["opencode","api","plugin.list",...de],{stdoutOnly:!0}),we=Ti(fe);if(we)throw Error(we);if(!pc(fe).some(fc))throw Error("OpenCode lists no active cc-safety-net for this directory. Run `opencode api plugin.list` for details.")}}}return dc(P),{commands:[["opencode","plugin","-g","-f",pt]],afterInstall:()=>uy(P)}}function pc(P){return dy(P).filter((O)=>tn(O,"id")===Qt||eo(tn(tn(O,"source"),"target"))).map((O)=>tn(O,"state"))}function fc(P){return tn(P,"status")==="active"}function Ti(P){let O=pc(P);if(O.some(fc))return;let D=O.find((j)=>tn(j,"status")==="failed");if(!D)return;return`OpenCode reports cc-safety-net failed: ${String(tn(D,"error")).split(`
222
- `)[0]}`}function dy(P){if(!P)return[];try{let O=tn(JSON.parse(P),"data");return Array.isArray(O)?O:[]}catch{return[]}}async function mc(P=1){let O=await gn(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s|\scc-safety-net@latest\s*$/m.test(O)||P===ay)return O;return await new Promise((D)=>setTimeout(D,ly)),mc(P+1)}async function uy(P){let O=Tn(cc(P),"node_modules",Qt),D=Tn(O,"package.json");if(!Qr(D))throw Error(`The OpenCode plugin cache at ${O} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${pt}\` for details.`);let j=tn(JSON.parse(Pi(D,"utf-8")),"main");if(typeof j!=="string")throw Error(`The cached OpenCode plugin at ${O} declares no "main" entry.`);let J=Tn(O,j);if(typeof(await import(sy(J).href))[ac]==="function")return;throw Error(`The cached OpenCode plugin at ${J} does not export a callable ${ac}, so OpenCode would load nothing and fail open.`)}function Ii(P,O){try{return JSON.parse(vn(P))}catch(D){if(D instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${O}: ${D.message}`);throw D}}function eo(P){let O=typeof P==="string"?P:tn(P,"package");return typeof O==="string"&&(O===Qt||O.startsWith(`${Qt}@`))}function $i(P){return["plugin","plugins"].some((O)=>{let D=tn(P,O);return Array.isArray(D)&&D.some(eo)})}function py(P,O){let j=["plugin","plugins"].flatMap((J)=>{let Y=Ma(P,J,cy);if(!Y)return[];let re=[],ie=0,de=Y.start+1,fe=P.slice(Y.start+1,Y.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let we of fe){if(we[0].startsWith("//")||we[0].startsWith("/*"))continue;let Ce=Y.start+1+we.index;if(ie===0)de=Ce;if(we[0]==="{"||we[0]==="[")ie++;if(we[0]==="}"||we[0]==="]")ie--;if(ie!==0||we[0]===",")continue;let Se=Ce+we[0].length;if(eo(JSON.parse(vn(P.slice(de,Se)))))re.push({start:de,end:Se})}return re}).sort((J,Y)=>J.start-Y.start).reverse().reduce((J,Y)=>{let re=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(J.slice(Y.end));if(re?.[0].includes("/")){let ie=Y.end+re[0].length-1;return J.slice(0,Y.start)+J.slice(Y.end,ie)+J.slice(ie+1)}return Ha(J,Y)},P);return Ii(j,O),j}function gc(P){dc(P);let O=Ai(P),D=O.find((Y)=>Qr(Y)),j=[],J=[];for(let Y of O){if(!Qr(Y))continue;try{let re=Pi(Y,"utf-8");if(!$i(Ii(re,Y)))continue;cn(Y,py(re,Y)),J.push(Y)}catch(re){j.push(re instanceof Error?re.message:String(re))}}if(j.length>0)throw Error(j.join(`
223
- `));return{path:J[0]??D??Tn(Ei(P),Ri[0]),alreadyInstalled:J.length>0}}function Ot(P){let O=[];for(let D of P.openCodeVersion?.startsWith("2.")?_i(P.environment):Ai(P.environment))if(fy(D))try{let j=my(D,"utf-8"),J=vn(j),Y=JSON.parse(J);if($i(Y)){let re=Ti(P.openCodePluginListOutput);if(re)return{platform:"opencode",status:"disabled",method:"opencode api plugin.list",configPath:D,errors:[...O,re]};return{platform:"opencode",status:"configured",method:"plugin array",configPath:D,errors:O.length>0?O:void 0}}}catch(j){O.push(`Failed to parse ${gy(D)}: ${j instanceof Error?j.message:String(j)}`)}return{platform:"opencode",status:"n/a",errors:O.length>0?O:void 0}}import{join as yc}from"node:path";function Oi(P){let O=P.env.get("PI_CODING_AGENT_DIR");return yc(O?Nn(O,P.home):yc(P.home,".pi","agent"),"settings.json")}function Di(P){if(typeof P!=="string")return!1;return P==="npm:cc-safety-net"||P.startsWith("npm:cc-safety-net@")}function hc(P){let O=Oi(P.environment),D=xn(O);if(D.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(D.kind==="missing")return{platform:"pi",status:"n/a"};let j=tn(D.value,"packages");if(!Array.isArray(j))return{platform:"pi",status:"n/a"};let J=j.find((ie)=>Di(typeof ie==="string"?ie:tn(ie,"source")));if(J===void 0)return{platform:"pi",status:"n/a"};let Y=tn(J,"extensions");if(Array.isArray(Y)&&Y.some((ie)=>typeof ie==="string"&&ie.startsWith("-")))return{platform:"pi",status:"disabled",method:"package config",configPath:O,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:O}}var yy={amp:Aa,"antigravity-cli":Ta,"claude-code":Oa,codex:La,"copilot-cli":Za,cursor:sl,"deepseek-harness":ll,devin:yl,droid:Pl,"gemini-cli":Rl,"grok-build":Ll,"hermes-agent":Kl,"kimi-code":Yt,openclaw:sc,opencode:Ot,pi:hc};function Dt(P,O,D){let j={...D,cwd:O,environment:P};return gr.map((J)=>hy(yy[J](j)))}function hy(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 vy}from"node:path";var by=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}]),wy=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([])})})}),ky={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 vc(P){let O=vy(P.tmpdir,"cc-safety-net-self-test"),D=by.map((j)=>{let J=G(P,u("self-test",{command:j.command},{kind:"command",shell:"auto"},{configCwd:O,executionCwd:O},j.command),{guard:{dependencies:{loadPolicySnapshot:()=>wy,getModes:()=>ky,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),Y=j.expectBlocked?"blocked":"allowed",re=J.decision.kind==="deny"?"blocked":"allowed";return{command:j.command,description:j.description,expected:Y,actual:re,passed:Y===re,reason:J.decision.kind==="deny"?J.decision.reason:void 0,ruleId:J.decision.kind==="deny"?J.decision.ruleId:void 0}});return{passed:D.filter((j)=>j.passed).length,failed:D.filter((j)=>!j.passed).length,total:D.length,results:D}}function Li(P){let O=yn({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},P);if(Dn(O.errors))return null;return{json:O.flags.json,skipUpdateCheck:O.flags.skipUpdateCheck}}async function bc(P,O={}){let D=await Ut(!O.json,()=>{let j=Cy(P,O);return{ready:j,finish:()=>j}},()=>Mt(),{loadingMessage:"Checking system status…"});if(O.json)console.log(JSON.stringify(D,null,2));else Sy(D);return D.engineSelfTest.failed>0||D.findings.some((j)=>j.severity==="error")?1:0}async function Cy(P,O){let D=O.cwd??process.cwd(),j=await Sr((Me)=>Ot({environment:P,cwd:D,openCodeVersion:Me}).status!=="n/a",void 0,D),J=Dt(P,D,{ampPluginListOutput:j.ampPluginListOutput,codexPluginListOutput:j.codexPluginListOutput,copilotCliVersion:j.versions["copilot-cli"],openCodeVersion:j.versions.opencode,openCodePluginListOutput:j.openCodePluginListOutput}),Y=Vs(P,D),re=Js(P),ie=k(P,{cwd:D}),de=ie.policy,fe=T(de,P.env),we=V(de,fe.capabilities),Ce=br(P,7),Se=Sa(P,D),Ie=[wr(D),Ct(P)].filter((Me)=>xy(Me)),Ee=O.skipUpdateCheck?{currentVersion:pn(),latestVersion:null,updateAvailable:!1}:await Gn(),qe={hooks:J,engineSelfTest:vc(P),userConfig:Y.userConfig,projectConfig:Y.projectConfig,configState:je(ie),effectiveRules:Y.effectiveRules,environment:re,effectiveSafety:{selectedPreset:de.safety.level??"standard",level:fe.effectiveLevel,capabilities:fe.capabilities,ruleOverrides:de.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(we).filter(([,Me])=>Me.source==="rule_override"&&Me.override==="off"&&Me.inheritedEnabled&&Me.changesInherited).map(([Me])=>Me),ruleCounts:{stored:Object.keys(de.destructiveCommandRuleOverrides).length,effective:Object.values(we).filter((Me)=>Me.changesInherited).length},...ie.policyScopes?{policyScopes:ie.policyScopes}:{}},...Se.length>0?{v2Leftovers:Se}:{},...Ie.length>0?{legacyConfigs:Ie}:{},posture:sa(P,Y.userConfig.path),activity:Ce,update:Ee,system:j};return{...qe,findings:Ws(qe)}}function Sy(P){console.log(),console.log(Ys(P.hooks)),console.log(),console.log(Zs(P.engineSelfTest)),console.log(),console.log(Xs(P)),console.log(),console.log(Qs(P.environment)),console.log(),console.log(ea(P)),console.log(),console.log(na(P.findings)),console.log(),console.log(ta(P.activity)),console.log(),console.log(oa(P.system)),console.log(),console.log(ra(P.update)),console.log(ia(P))}import{existsSync as Py}from"node:fs";var Ry=/^[A-Za-z0-9_@%+=:,./-]+$/,wc="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function Ni(P){let O=yn({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},P);if(Dn(O.errors))return console.error(wc),console.error("Pass -- before a command that starts with dashes."),null;if(O.values.cwd!==void 0&&!Py(O.values.cwd))return console.error(`Error: --cwd path does not exist: ${O.values.cwd}`),null;let D=O.positionals.length===1?O.positionals[0]:O.positionals.map((j)=>Ry.test(j)?j:`'${j.replaceAll("'","'\\''")}'`).join(" ");if(!D)return console.error("Error: No command provided"),console.error(wc),null;return{json:O.flags.json,cwd:O.values.cwd,command:D}}function kc(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 xc(P,O){let j=O-18;return[`${P.dtl}${P.dh.repeat(O)}${P.dtr}`,`${P.dv} Command Analysis${" ".repeat(j)}${P.dv}`,`${P.dbl}${P.dh.repeat(O)}${P.dbr}`]}function ji(P){return JSON.stringify(P)}function Cc(P,O=0){return`[${P.map((j,J)=>zs(j,J,O)).join(",")}]`}function er(P,O,D=70){let j=P.split(" "),J=[],Y="";for(let re of j)if(Y&&Y.length+re.length+1>D)J.push(Y),Y=re;else Y=Y?`${Y} ${re}`:re;if(Y)J.push(Y);return J.map((re,ie)=>ie===0?re:`${O}${re}`)}function Sc(P,O,D){let j=[];switch(P.type){case"parse":return null;case"env-strip":return j.push(""),j.push(`STEP ${O} ${D.h} Strip environment variables`),j.push(` Removed: ${P.envVars.map((J)=>`${J}=<redacted>`).join(", ")}`),j.push(` Tokens: ${ji(P.output)}`),{lines:j,incrementStep:!0};case"leading-tokens-stripped":return j.push(""),j.push(`STEP ${O} ${D.h} Strip wrappers`),j.push(` Removed: ${P.removed.join(", ")}`),j.push(` Tokens: ${ji(P.output)}`),{lines:j,incrementStep:!0};case"shell-wrapper":return j.push(""),j.push(`STEP ${O} ${D.h} Detect shell wrapper`),j.push(` Wrapper: ${P.wrapper} -c`),j.push(` Inner: ${P.innerCommand}`),{lines:j,incrementStep:!0};case"interpreter":{if(j.push(""),j.push(`STEP ${O} ${D.h} Detect interpreter`),j.push(` Interpreter: ${P.interpreter}`),j.push(` Code: ${P.codeArg}`),P.paranoidBlocked)j.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:j,incrementStep:!0}}case"busybox":return j.push(""),j.push(`STEP ${O} ${D.h} Busybox wrapper`),j.push(` Subcommand: ${P.subcommand}`),{lines:j,incrementStep:!0};case"transparent-wrapper":return j.push(""),j.push(`STEP ${O} ${D.h} Transparent wrapper`),j.push(` Wrapper: ${P.wrapper}`),j.push(` Tokens: ${ji(P.output)}`),{lines:j,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(j.push(""),j.push(`STEP ${O} ${D.h} Match rules`),j.push(` Rule: ${P.rule}()`),P.matched)j.push(" Result: MATCHED");else j.push(" Result: No match");return{lines:j,incrementStep:!0}}case"worktree-relaxation":return j.push(""),j.push(`STEP ${O} ${D.h} Worktree relaxation`),j.push(` Mode: ${n.worktree.name}`),j.push(` Git cwd: ${P.gitCwd}`),j.push(" Result: Allowed local discard in linked worktree"),{lines:j,incrementStep:!0};case"temp-root-relaxation":return j.push(""),j.push(`STEP ${O} ${D.h} Temp-root relaxation`),j.push(` Git cwd: ${P.gitCwd}`),j.push(" Result: Allowed git discard in a temp-root repository"),{lines:j,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(P.embeddedCommandFound)return j.push(""),j.push(`STEP ${O} ${D.h} Fallback scan`),j.push(` Found: ${P.embeddedCommandFound}`),{lines:j,incrementStep:!0};return null}case"custom-rules-check":{if(P.rulesChecked){if(j.push(""),j.push(`STEP ${O} ${D.h} Custom rules`),P.matched)j.push(" Result: MATCHED");else j.push(" Result: No match");return{lines:j,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(P.matched)return j.push(""),j.push(`STEP ${O} ${D.h} Dangerous text check`),j.push(` Token: ${P.token}`),j.push(" Result: MATCHED"),{lines:j,incrementStep:!0};return null}case"strict-unparseable":return j.push(""),j.push(`STEP ${O} ${D.h} Strict mode check`),j.push(` Command: ${P.rawCommand}`),j.push(" Result: ✗ UNPARSEABLE"),{lines:j,incrementStep:!0};case"segment-skipped":return null;case"error":return j.push(""),j.push(`ERROR: ${P.message}`),{lines:j,incrementStep:!1};default:return P}}function Fi(P,O){let D=kc(O?.asciiOnly??!1),j=58,J=[],Y=1;J.push(...xc(D,58)),J.push("");let re=P.trace.steps.find((Ee)=>Ee.type==="error");if(re&&re.type==="error"){J.push("ERROR"),J.push(` ${re.message}`),J.push(""),J.push("RESULT"),J.push(` Status: ${P.result==="blocked"?nn.red("BLOCKED"):nn.green("ALLOWED")}`),J.push(""),J.push("CONFIG");let Ee=P.configSource??"none";return J.push(` Path: ${Ee}`),J.join(`
224
- `)}let ie=P.trace.steps.find((Ee)=>Ee.type==="parse");if(ie&&ie.type==="parse"){J.push("INPUT"),J.push(` ${ie.input}`),J.push(""),J.push(`STEP ${Y} ${D.h} Split shell commands`),Y++;for(let Ee=0;Ee<ie.segments.length;Ee++){let qe=ie.segments[Ee];if(qe){let Me=Math.random();J.push(` Segment ${Ee+1}: ${Cc(qe,Me)}`)}}}let de=P.trace.segments,fe=de.length>1;for(let Ee of de){if(fe){J.push("");let on="";if(ie&&ie.type==="parse"){let Po=ie.segments[Ee.index];if(Po)on=Po.join(" ")}let sn=54,an=on,rn=` Segment ${Ee.index+1}: `,fn=" ";if(on){if(rn.length+on.length+fn.length>sn){let lp=sn-rn.length-fn.length;an=`${on.substring(0,lp-1)}…`}}let On=on?`${rn}${an}${fn}`:` Segment ${Ee.index+1} `,sp=on?`${rn}${nn.cyan(an)}${fn}`:On,ws=58-On.length,ks=Math.floor(ws/2),ap=ws-ks;J.push(`${D.sh.repeat(ks)}${sp}${D.sh.repeat(ap)}`)}if(Ee.steps.find((on)=>on.type==="segment-skipped")){J.push(""),J.push(" (skipped — prior segment blocked)");continue}let Me=!1,en=!1;for(let on of Ee.steps){let sn=Sc(on,Y,D);if(sn){if(en=!0,on.type==="recurse"){J.push("");let an=" RECURSING ",rn=58-an.length-4;J.push(` ${D.tl}${D.h}${an}${D.h.repeat(rn)}`),J.push(` ${D.v}`),Me=!0;continue}for(let an of sn.lines)if(Me)J.push(` ${D.v} ${an}`);else J.push(an);if(sn.incrementStep)Y++}}if(Me)J.push(` ${D.v}`),J.push(` ${D.bl}${D.h.repeat(56)}`);if(!en)J.push(""),J.push(` ${nn.green("✓")} Allowed (no matching rules)`)}if(J.push(""),J.push("RESULT"),P.result==="blocked"){if(J.push(` Status: ${nn.red("BLOCKED")}`),P.customRule){if(J.push(` Rule: ${P.customRule.id}`),P.customRule.rulebook)J.push(` Rulebook: ${P.customRule.rulebook.name} ${P.customRule.rulebook.version}`);if(P.customRule.source)J.push(` Source: ${P.customRule.source}`);if(P.customRule.override)J.push(` Override: reason ${P.customRule.override.reason}`)}if(P.reason){let Ee=er(P.reason," ");J.push(` Reason: ${Ee[0]}`);for(let qe=1;qe<Ee.length;qe++)J.push(Ee[qe]??"")}}else J.push(` Status: ${nn.green("ALLOWED")}`);J.push(""),J.push("CONFIG");let we=P.configSource??"none",Ce=P.configValid?"":" (invalid)";J.push(` Path: ${we}${Ce}`);let Se=P.safetyPresetScope;J.push(` Safety preset: ${P.selectedPreset??"standard"}${Se?` (${kr(Se)})`:""}`),J.push(` Effective capabilities: ${P.effectiveLevel}`);let Ie=Object.entries(P.destructiveCommandRuleOverrides??{});if(J.push(` Rule customizations: ${Ie.length}`),P.ruleActivation)J.push(` Rule activation: ${P.ruleActivation.id} — ${P.ruleActivation.enabled?"on":"off"} via ${P.ruleActivation.source}`);return J.join(`
225
- `)}function Hi(P){return JSON.stringify(P,null,2)}import{resolve as Iy}from"node:path";var Ey=["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 Pc(P){let O=0,D={allocateSegment(){return O++},getNextSegmentIndex(){return O},recordGlobal(j){P.record({kind:"step",scope:"global",step:j})},recordSegment(j,J=D.currentSegmentIndex){if(J===void 0)return;P.record({kind:"step",scope:"segment",segmentIndex:J,step:j})}};return D}function Rc(P={}){let O=[],D=P.maxEvents??512,j={maxTextLength:P.maxTextLength??2048,maxListLength:P.maxListLength??128,maxObjectProperties:P.maxObjectProperties??P.maxListLength??128,maxDepth:P.maxDepth??16},J,Y=new Set;return{record(re){if(J)return;if(!re||O.length>=D)return;try{O.push(Gi(_y(re,j,Y)))}catch{}},finish(){if(J)return J;return J=Gi({events:Object.freeze(O)}),J}}}function _y(P,O,D){if(P.kind!=="step")throw TypeError("invalid trace event");let{scope:j,step:J}=P;no(J,D,O);let Y=Mi(J,O,D);if(j==="global")return{kind:"step",scope:"global",step:Y};if(j!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:P.segmentIndex,step:Y}}function no(P,O,D,j=0,J=new WeakSet){if(typeof P==="string"){let ie=P.slice(0,D.maxTextLength);if(!ze(ie))return;for(let de of nt(ie))for(let fe of de.match(/[^\s"'()$]+/g)??[])O.add(Ec(fe));return}if(!P||typeof P!=="object"||j>=D.maxDepth||J.has(P))return;if(J.add(P),Array.isArray(P)){let ie=Math.min(P.length,D.maxListLength);for(let de=0;de<ie;de++)no(P[de],O,D,j+1,J);return}let Y=0,re=new Set;for(let ie in P){if(!Object.hasOwn(P,ie))continue;if(Y>=D.maxObjectProperties)break;Y++,no(ie,O,D);let de=Ui(ie,D,O);if(re.has(de))continue;re.add(de),no(P[ie],O,D,j+1,J)}}function Mi(P,O,D,j=0,J=new WeakSet){if(typeof P==="string")return Ui(P,O,D);if(!P||typeof P!=="object")return P;if(j>=O.maxDepth)return;if(J.has(P))return;if(J.add(P),Array.isArray(P)){let ie=[],de=Math.min(P.length,O.maxListLength);for(let fe=0;fe<de;fe++)ie.push(Mi(P[fe],O,D,j+1,J));return ie}let Y={},re=0;for(let ie in P){if(!Object.hasOwn(P,ie))continue;if(re>=O.maxObjectProperties)break;re++;let de=Ui(ie,O,D);if(Object.hasOwn(Y,de))continue;Object.defineProperty(Y,de,{value:Mi(P[ie],O,D,j+1,J),enumerable:!0,configurable:!0,writable:!0})}return Y}function Ui(P,O,D){let j=P.slice(0,O.maxTextLength),J=ze(j)?Be(j):j,Y=D.size>0?Ty(J,D):J;return(Ay(Y)?Pe(Y):Y).slice(0,O.maxTextLength)}function Ay(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&&Ey.some((O)=>P.includes(O))||P.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(P)}function Ty(P,O){return P.replace(/[^\s"'()$]+/g,(D)=>O.has(Ec(D))?"<redacted>":D)}function Ec(P){let O=2166136261,D=2166136261;for(let j=0;j<P.length;j++)O=Math.imul(O^P.charCodeAt(j),16777619),D=Math.imul(D^P.charCodeAt(P.length-j-1),16777619);return`${O>>>0}:${D>>>0}:${P.length}`}function Gi(P){if(P&&typeof P==="object"&&!Object.isFrozen(P)){for(let O of Object.values(P))Gi(O);Object.freeze(P)}return P}function nr(P,O={},D){let j=Iy(O.cwd??process.cwd()),J=O.policySnapshot??k(D,{cwd:j,userConfigDir:O.userConfigDir}),Y=T(J.policy,D.env),re=Ue({policySnapshot:J,effectiveCapabilities:Y.capabilities,strict:Y.strict,paranoidRm:Y.paranoidRm,paranoidInterpreters:Y.paranoidInterpreters,worktreeMode:Y.worktreeMode}),ie={effectiveLevel:re.effectiveLevel,selectedPreset:J.policy.safety.level??"standard",...J.policyScopes?{safetyPresetScope:J.policyScopes.levelScope}:{},effectiveCapabilities:re.effectiveCapabilities,destructiveCommandRuleOverrides:J.policy.destructiveCommandRuleOverrides},{configSource:de,configValid:fe}=Oy(D,{cwd:j,userConfigDir:O.userConfigDir});if(!P||!P.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:de,configValid:fe,...ie};let we=y(P,"auto");if(we.status==="limited")throw new b;let Ce=we.dialect==="powershell"?y(P,"posix"):we,Se=dt(Ce),Ie=Rc(),Ee=Pc(Ie);Ee.recordGlobal({type:"parse",input:P,segments:Se.map((On)=>[...On])});let qe=u("Bash",{command:P},{kind:"command",shell:"auto"},{configCwd:j,executionCwd:j},P),Me=q(qe,{environment:D,trace:Ee,dependencies:{loadPolicySnapshot:()=>J}}),en=Me.decision.kind==="deny"?Me.decision:null;if(en&&(Me.stage==="policy-protection"||Me.stage==="secret-protection"))return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:$y(en),matched:!0,reason:en.reason}]}]},result:"blocked",reason:R(en.reason),segment:R(_c(en,P)),ruleId:R(en.ruleId),configSource:de,configValid:fe,...ie};let on=Ee.getNextSegmentIndex();if(en&&on>0&&on<Se.length)Ee.recordSegment({type:"segment-skipped",index:on,reason:"prior-segment-blocked"},on);let sn=Ie.finish(),an=en?.ruleId??Dy(qe,J,Y,D),rn=z.find((On)=>On.id===an&&On.activationCapability),fn=rn?re.policy.effectiveDestructiveCommandRules[rn.id]:void 0;return{trace:Ny(sn),result:en?"blocked":"allowed",reason:en?R(en.reason):void 0,segment:en?R(_c(en,P)):void 0,ruleId:en?R(en.ruleId):void 0,customRule:Ly(jy(en?.ruleId,J)),configSource:de,configValid:fe,...ie,...rn&&fn?{ruleActivation:{id:rn.id,...fn}}:{}}}function _c(P,O){return P.evidence?.segment??O}function $y(P){if(P.reason===He)return"policy-protection:findPolicyConfigMutationTargetInSemanticFacts";if(P.reason===Ge)return"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts";if(P.reason===x)return"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts";return"secret-protection:findSensitiveTargetInSemanticFacts"}function Oy(P,O){let D=_(O.cwd),j=W(P,O),J=X(P,{cwd:O.cwd,userConfigDir:O.userConfigDir});try{if(r(J.projectConfigTarget)!==null){if(Un(J.projectConfigTarget).errors.length===0)return{configSource:D,configValid:!0};return{configSource:D,configValid:!1}}}catch(Y){if(Y instanceof o)return{configSource:D,configValid:!1};throw Y}try{if(r(J.userConfigTarget)!==null){let Y=Un(J.userConfigTarget);return{configSource:j,configValid:Y.errors.length===0}}return{configSource:null,configValid:!0}}catch(Y){if(Y instanceof o)return{configSource:j,configValid:!1};throw Y}}function Dy(P,O,D,j){let J=O.policy,Y=_e({...J,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...J.destructiveCommandRuleOverrides,...Object.fromEntries(z.flatMap((ie)=>ie.activationCapability?[[ie.id,"on"]]:[]))}},O.state==="degraded"?{diagnostics:O.diagnostics,reason:O.reason}:void 0),re=q(P,{environment:j,dependencies:{loadPolicySnapshot:()=>Y,getModes:()=>({...D,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return re.decision.kind==="deny"?re.decision.ruleId:void 0}function Ly(P){if(!P)return;return{id:R(P.id),...P.rulebook?{rulebook:{name:R(P.rulebook.name),version:R(P.rulebook.version)}}:{},...P.source?{source:R(P.source)}:{},...P.override?{override:{type:"reason",reason:R(P.override.reason)}}:{}}}function Ny(P){let O=P.events.flatMap((j)=>j.kind==="step"&&j.scope==="global"?[j.step]:[]),D=new Map;for(let j of P.events){if(j.kind!=="step"||j.scope!=="segment")continue;let J=D.get(j.segmentIndex)??{index:j.segmentIndex,steps:[]};J.steps.push(j.step),D.set(j.segmentIndex,J)}return{steps:O,segments:[...D.values()]}}function jy(P,O){let D=P?.replace(/^custom\./,"");if(!D||!O.policy.rules.some((j)=>j.name===D))return;return O.ruleMetadata[D]??Object.freeze({id:D})}function Ac(P){return new Promise((O)=>{process.stdout.write(`${P}
226
- `,()=>O())})}async function Tc(P,O){let D=Ni(O);if(!D)return 1;try{let j=nr(D.command,{cwd:D.cwd},P),J=!!process.env.NO_COLOR||!process.stdout.isTTY;return await Ac(D.json?Hi(j):Fi(j,{asciiOnly:J})),0}catch(j){let J=Fy(j instanceof p?j.cause:j);if(J===void 0)throw j;if(D.json)return await Ac(JSON.stringify({error:J})),1;return console.error(J),1}}function Fy(P){if(P instanceof b)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 Ic="2.6.9",_n=" ",ft="cc-safety-net";function $c(P){return P.argument?`${P.flags} ${P.argument}`:P.flags}function Hy(P){return Math.max(...P.map((O)=>$c(O).length))}function My(P){return Math.max(...P.map((O)=>O.usage.length))}function Uy(P){return Math.max(...P.map((O)=>`${ft} ${O.usage}`.length))}function Gy(P,O){let D=`${ft} ${P.usage}`;return`${_n}${D.padEnd(O+2)}${P.description}`}function In(P,O){return`${_n}${P.padEnd(Math.max(40,P.length+2))}${O}`}function Lt(P,O=console.log){let D=[];if(D.push(`${ft} ${P.name}`),D.push(""),D.push(`${_n}${P.description}`),D.push(""),D.push("USAGE:"),D.push(`${_n}${ft} ${P.usage}`),D.push(""),P.subcommands&&P.subcommands.length>0){D.push("SUBCOMMANDS:");let j=My(P.subcommands);for(let J of P.subcommands)D.push(`${_n}${J.usage.padEnd(j+2)}${J.description}`);D.push("")}if(P.options.length>0){D.push("OPTIONS:");let j=Hy(P.options);for(let J of P.options){let Y=$c(J),re=J.default?`${J.description} (default: ${J.default})`:J.description;D.push(`${_n}${Y.padEnd(j+2)}${re}`)}D.push("")}if(P.examples&&P.examples.length>0){D.push("EXAMPLES:");for(let j of P.examples)D.push(`${_n}${j}`)}O(D.join(`
227
- `))}function qi(){let P=Uy(hr),O=[];O.push(`${ft} v${Ic}`),O.push(""),O.push("Blocks destructive commands and secret access."),O.push(""),O.push("COMMANDS:");for(let D of hr)O.push(Gy(D,P));O.push(""),O.push("GLOBAL OPTIONS:"),O.push(`${_n}-h, --help Show help (use with command for command-specific help)`),O.push(`${_n}-V, --version Show version`),O.push(""),O.push("HELP:"),O.push(`${_n}${ft} help <command> Show help for a specific command`),O.push(`${_n}${ft} <command> --help Show help for a specific command`),O.push(""),O.push("ENVIRONMENT VARIABLES:"),O.push(In(`${n.level.name}=standard|strict|paranoid`,"Set session safety level")),O.push(In(`${n.worktree.name}=1`,"Allow local git discards in linked worktrees")),O.push(In(`${n.debug.name}=1`,"Print diagnostic messages to stderr")),O.push(In(`${n.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),O.push(In(`${n.projectTightenOnly.name}=1`,"Ignore project policy settings that weaken the user policy")),O.push(In("CC_SAFETY_NET_HOME","Override rule config home directory")),O.push(""),O.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),O.push(In(`${n.strict.name}=1`,"Force safety.overrides.fail_closed on")),O.push(In(`${n.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),O.push(In(`${n.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),O.push(In(`${n.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),O.push(""),O.push("Documentation: https://ccsafetynet.com/docs"),console.log(O.join(`
228
- `))}function Oc(){console.log(Ic)}function tr(P,O=console.log){let D=vr(P);if(!D)return!1;if(D.name.toLowerCase()!==P.toLowerCase())return!1;return Lt(D,O),!0}import{existsSync as co,readFileSync as Hd}from"node:fs";import{join as lo}from"node:path";import*as Bn from"node:readline";function qy(P){return P==="install"?"Install":"Uninstall"}function By(P){return P==="install"?"Installing":"Uninstalling"}function Vy(P){return P==="install"?"into":"from"}function Nc(P){return P?.available===!0}function Jy(P,O){let D=new Set(O);return P.filter((j)=>D.has(j.target)).map((j)=>j.target)}function Dc(P,O,D){if(P.every((j)=>!j.available))return O;return Array.from({length:P.length},(j,J)=>J+1).map((j)=>(O+j*D+P.length)%P.length).find((j)=>Nc(P[j]))}function Ky(P,O,D){if(D.ctrl&&D.name==="c")return"interrupt";if(D.name==="escape"||O==="q")return"abort";if(P==="install"&&(O==="u"||O==="U"))return"update";if(D.name==="up"||O==="k")return"up";if(D.name==="down"||O==="j")return"down";if(D.name==="space"||O===" ")return"toggle";if(D.name==="return"||D.name==="enter")return"confirm";return null}function Wy(P){return{cursor:P.findIndex((O)=>O.available),selected:[]}}function zy(P,O,D){if(D==="confirm"||D==="update"||D==="abort"||D==="interrupt")return{state:P,done:D};if(D==="up")return{state:{...P,cursor:Dc(O,P.cursor,-1)}};if(D==="down")return{state:{...P,cursor:Dc(O,P.cursor,1)}};let j=O[P.cursor];if(!Nc(j))return{state:P};let J=P.selected.includes(j.target)?P.selected.filter((Y)=>Y!==j.target):Jy(O,[...P.selected,j.target]);return{state:{...P,selected:J}}}var jc="◉",Fc="◯",Hc=">",Mc=" ";function Yy(P,O,D){return["",`${qy(P)} CC Safety Net ${Vy(P)}:`,"",...O.map((j,J)=>{let Y=D.selected.includes(j.target),re=J===D.cursor,ie=Y?jc:Fc,de=re?Hc:Mc,fe=j.available?"":` (${j.unavailableReason??"not installed"})`,we=`${ie} ${j.label}${fe}`,Ce=!j.available?nn.dim(we):Y?nn.green(we):re?nn.bold(we):we;return`${de} ${Ce}`}),"",P==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":O.some((j)=>j.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${P}. q/Esc: close`].join(`
229
- `)}var Lc=["global-hook","plugin"];function Zy(P,O,D={}){let j=D.color!==!1?nn.bold:(Y)=>Y;return["","Install the Kimi Code integration as:","",...[`Global hook — ${O?"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((Y,re)=>{let ie=re===P,de=`${ie?jc:Fc} ${Y}`;return`${ie?Hc:Mc} ${ie?j(de):de}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
230
- `)}function Uc(P){let{input:O,output:D}=P;Bn.emitKeypressEvents(O);let j=O.isRaw===!0;O.setRawMode(!0),O.resume();let J=0,Y=()=>{if(J===0)return;Bn.moveCursor(D,0,-J),Bn.cursorTo(D,0),Bn.clearScreenDown(D)},re=()=>{Y();let ie=P.render();D.write(`${ie}
231
- `),J=ie.split(`
232
- `).length};return new Promise((ie)=>{let de=(we)=>{O.off("keypress",fe),O.setRawMode(j),O.pause(),Y(),ie(we)};function fe(we,Ce){P.onKey(we,Ce,{finish:de,draw:re})}O.on("keypress",fe),re()})}function Gc(P={}){let O=0;return Uc({input:P.input??process.stdin,output:P.output??process.stdout,render:()=>Zy(O,P.globalHookInstalled===!0),onKey:(D,j,J)=>{if(j.ctrl&&j.name==="c"){J.finish(null),(P.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(j.name==="escape"||D==="q")return J.finish(null);if(j.name==="return"||j.name==="enter")return J.finish(Lc[O]);if(j.name==="up"||j.name==="down"||D==="k"||D==="j")O=(O+1)%Lc.length,J.draw()}})}function Bi(P=process.stdin,O=process.stdout){return Boolean(P.isTTY&&O.isTTY&&typeof P.setRawMode==="function")}function qc(P,O,D={}){let j=D.output??process.stdout,J=Wy(O);return Uc({input:D.input??process.stdin,output:j,render:()=>Yy(P,O,J),onKey:(Y,re,ie)=>{let de=Ky(P,Y,re);if(!de)return;let fe=zy(J,O,de);if(J=fe.state,fe.done==="interrupt"){ie.finish(null),(D.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(fe.done==="abort")return ie.finish(null);if(fe.done==="update")return ie.finish("update");if(fe.done==="confirm"){if(J.selected.length===0){j.write("\x07"),ie.draw();return}ie.finish([...J.selected]),j.write(`${By(P)} selected integrations...
233
- `);return}ie.draw()}})}import{existsSync as Bc,lstatSync as Qy,mkdirSync as eh,mkdtempSync as nh,readdirSync as th,readFileSync as jt,rmSync as ro}from"node:fs";import{basename as rh,dirname as oh,join as Sn}from"node:path";import{fileURLToPath as ih}from"node:url";var Vi="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",mt="cc-safety-net",gt="cc-safety-net/index.ts";import{spawn as Xy}from"node:child_process";var Ji=(P,O)=>{let D=zn([...P],process.env);return new Promise((j)=>{let J=Xy(D.cmd,D.args,{cwd:O,stdio:["ignore","pipe","pipe"]}),Y=Ko(J),re=!1,ie=setTimeout(()=>{re=!0,J.kill()},120000);J.on("error",(de)=>{clearTimeout(ie),j({status:null,errorCode:de.code,stdout:Y.stdout,stderr:[de.message,Y.stderr].filter(Boolean).join(`
234
- `)})}),J.on("close",(de)=>{clearTimeout(ie),j({status:re?null:de,errorCode:re?"ETIMEDOUT":void 0,stdout:Y.stdout,stderr:Y.stderr})})})};var Nt="cc-safety-net.ts",Ki=Sn("amp",gt);function sh(P){return Sn(P.home,".config","amp","plugins","cc-safety-net.ts")}function ah(){let P=oh(ih(import.meta.url)),O=Sn(P,Ki),D=Sn(P,"..",Ki),j=Sn(P,"..","..","..","dist",Ki);return[O,D,j]}function lh(P=ah()){let O=P.find((D)=>Bc(D)&&Qy(D).isFile());if(!O)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return O}function Vc(P){try{return JSON.parse(P)}catch{return}}function oo(P){return P.subarray(0,Buffer.byteLength(Vi)).toString("utf-8")===Vi}async function rr(P,O,D){let j=await P(O,D);if(j.status===0)return j;throw Error([`Failed to run ${O.join(" ")}${j.status===null?"":` (exit ${j.status})`}.`,[j.stdout,j.stderr].filter(Boolean).join(`
222
+ `}function sr(_){return[{name:"__init__.py",content:Iy(_)},{name:"plugin.yaml",content:Ay(_)}]}import{mkdirSync as Oy,readdirSync as $y,readFileSync as pc,rmSync as Li}from"node:fs";import{basename as Dy,dirname as Ly,join as Hn}from"node:path";var Ny="__pycache__",jy=/^[a-z0-9][a-z0-9_-]{0,63}$/;function Hy(_){try{return pc(_,"utf-8").trim()}catch{return}}function Ni(_){let N=_.env.get("HERMES_HOME")?.trim();if(N&&Dy(Ly(N))==="profiles")return N;let j=N||Hn(_.home,".hermes"),J=Hn(j,"active_profile"),Y=Hy(J),re=Y?.toLowerCase();if(!re||re==="default")return j;if(!jy.test(re))throw Error(`Invalid Hermes profile name "${Y}" in ${J}; run \`hermes profile use <name>\` with a valid profile.`);return Hn(j,"profiles",re)}function ji(_){return Hn(Ni(_),"plugins",Pn)}function Hi(_){return _.startsWith(Di)}function Fi(_,N){let j=ji(_),J=dn(j);if(J&&(J.isSymbolicLink()||!J.isDirectory()))throw Error(`Refusing to ${N} ${j}: not a regular directory. Move or remove it and rerun ${N==="install"?"install":"uninstall"} --hermes-agent.`);return j}function fc(_,N){let j=dn(_);if(!j)return;if(j.isSymbolicLink()||!j.isFile())throw Error(`Refusing to ${N} ${_}: not a regular file. Move or remove it.`);let J=pc(_,"utf-8");if(!Hi(J))throw Error(`Refusing to ${N} unmanaged file at ${_}. Move or remove it.`);return J}function mc(_){let N=Fi(_,"install"),j=sr(pn());if(j.map((Y)=>fc(Hn(N,Y.name),"overwrite")).every((Y,re)=>Y===j[re]?.content))return{path:N,alreadyInstalled:!0};return Oy(N,{recursive:!0}),j.forEach((Y)=>{ln(Hn(N,Y.name),Y.content)}),{path:N,alreadyInstalled:!1}}function Mi(_){let N=Fi(_,"remove");if(!dn(N))return[];return sr(pn()).filter((j)=>fc(Hn(N,j.name),"remove")!==void 0)}function gc(_){let N=Fi(_,"remove");if(!dn(N))return{path:N,alreadyInstalled:!1};let j=Mi(_);if(j.forEach((J)=>{Li(Hn(N,J.name))}),Li(Hn(N,Ny),{recursive:!0,force:!0}),$y(N).length===0)Li(N,{recursive:!0});return{path:N,alreadyInstalled:j.length>0}}var ar="hermes-agent",yc=/^([^\s#][^:]*):/,Fy=/^\s+([A-Za-z_][\w-]*):/,hc=/^\s+-\s*(.*)$/;function My(_){return _.trim().replace(/^(["'])(.*)\1$/,"$2")}function Uy(_){let N=_.split(/\r?\n/),j=N.findIndex((re)=>yc.exec(re)?.[1]?.trim()==="plugins");if(j===-1)return[];let J=N.slice(j+1),Y=J.findIndex((re)=>yc.test(re));return Y===-1?J:J.slice(0,Y)}function vc(_,N){let j=Uy(_),J=j.findIndex((ie)=>Fy.exec(ie)?.[1]===N);if(J===-1)return[];let Y=j.slice(J+1),re=Y.findIndex((ie)=>!hc.test(ie));return(re===-1?Y:Y.slice(0,re)).map((ie)=>My(hc.exec(ie)?.[1]??""))}function Gy(_){try{return bc(wc(Ni(_),"config.yaml"),"utf-8")}catch{return}}function Ui(_){let N=Gy(_)??"";return vc(N,"enabled").includes(Pn)&&!vc(N,"disabled").includes(Pn)}function kc(_){return/^# version:\s*(.+)$/m.exec(_)?.[1]?.trim()}function By(_,N){let j=dn(_);if(!j)return{error:`${N.name} is missing from ${_}; run install --hermes-agent`};if(j.isSymbolicLink()||!j.isFile())return{error:`${_} is a symlink or not a regular file; move or remove it`};try{let J=bc(_,"utf-8");if(!Hi(J))return{error:`Unmanaged ${N.name} occupies ${_}; move or remove it`};if(kc(J)===pn()&&J!==N.content)return{error:`Modified ${N.name} occupies ${_}; run install --hermes-agent to restore it`};return{content:J}}catch(J){return{error:`Failed to read ${_}: ${J instanceof Error?J.message:String(J)}`}}}function qy(_){try{return{path:ji(_)}}catch(N){return{error:N instanceof Error?N.message:String(N)}}}function Cc(_){let N=qy(_.environment);if("error"in N)return{platform:ar,status:"n/a",errors:[N.error]};let j=N.path,J=Br(ar,j);if(J)return J;let Y=sr(pn()).map((fe)=>By(wc(j,fe.name),fe)),re=Y.flatMap((fe)=>("error"in fe)?[fe.error]:[]);if(re.length>0)return{platform:ar,status:"n/a",configPath:j,errors:re};let ie=Y.some((fe)=>("content"in fe)&&kc(fe.content)!==pn()),de=ie?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Ui(_.environment))return{platform:ar,status:"disabled",method:"plugin directory",configPath:j,errors:[`${Pn} is not enabled in Hermes; run \`hermes plugins enable ${Pn}\``,...de]};return{platform:ar,status:"configured",method:"plugin directory",configPath:j,errors:ie?de:void 0}}import{existsSync as Vy,readFileSync as Ky}from"node:fs";import{join as qi}from"node:path";var Jy=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/,Gi="cc-safety-net",uo="plugin config",Wy=new Set(["event","matcher","command","timeout"]),zy=new Set(["PreToolUse","PostToolUse","PostToolUseFailure","PermissionRequest","PermissionResult","UserPromptSubmit","UserPromptQueued","TurnStarted","Stop","StopFailure","Interrupt","SessionStart","SessionEnd","SessionHeartbeat","SubagentStart","SubagentStop","TaskStarted","PreCompact","PostCompact","Notification"]);function xc(_){return _.env.get("KIMI_CODE_HOME")||qi(_.home,".kimi-code")}function co(_,N){let j=[""],J="",Y=0;for(let re=0;re<_.length;re++){let ie=_[re];if(J!==""){let de=J==='"'&&ie==="\\"?_[++re]??"":"";if(j[j.length-1]+=ie+de,de===""&&ie===J)J="";continue}if(ie==="#"){let de=_.indexOf(`
223
+ `,re);re=(de===-1?_.length:de)-1;continue}if(ie===N&&Y===0){j.push("");continue}if(ie==='"'||ie==="'")J=ie;if(ie==="["||ie==="{")Y++;if(ie==="]"||ie==="}")Y--;j[j.length-1]+=ie}return j.map((re)=>re.trim()).filter((re)=>re!=="")}function Sc(_){let N=/^(?:"([^"]*)"|'([^']*)'|([^\s="']+))\s*=\s*([\s\S]+)$/.exec(_);return N?{key:N[1]??N[2]??N[3]??"",value:N[4]??""}:void 0}function Bi(_){return _===void 0?void 0:/^("""|'''|"|')([\s\S]*)\1$/.exec(_)?.[2]}function Yy(_){let N=_.split(/(?=^\s*\[)/m),j=N.filter((J)=>!/^\s*\[/.test(J)).flatMap((J)=>co(J,`
224
+ `)).map(Sc).find((J)=>J?.key==="hooks")?.value;if(j!==void 0)return co(j.slice(1,-1),",").map((J)=>co(J.slice(1,-1),","));return N.filter((J)=>/^\s*\[\[hooks]]/.test(J)).map((J)=>co(J.replace(/^\s*\[\[hooks]]/,""),`
225
+ `))}function Zy(_){let N=_.map(Sc),j=_.find((ke,Re)=>N[Re]===void 0),J=N.find((ke)=>ke!==void 0&&!Wy.has(ke.key))?.key,Y=N.find((ke,Re)=>ke!==void 0&&N.findIndex((Te)=>Te?.key===ke.key)<Re)?.key,re=(ke)=>N.find((Re)=>Re?.key===ke)?.value,ie=re("matcher"),de=re("timeout"),fe=Number(de?.replace(/(?<=[\da-f])_(?=[\da-f])/gi,""));return[[j!==void 0,`"${j}" is not a key = value pair`],[J!==void 0,`unknown key "${J}"`],[Y!==void 0,`duplicate key "${Y}"`],[!zy.has(Bi(re("event"))??""),'"event" is not a Kimi Code hook event'],[ie!==void 0&&Bi(ie)===void 0,'"matcher" is not a string'],[!Bi(re("command")),'"command" is missing or empty'],[de!==void 0&&!(Number.isInteger(fe)&&fe>=1&&fe<=600),'"timeout" is not an integer from 1 to 600']].find(([ke])=>ke)?.[1]}function Xy(_){let N=qi(xc(_),"plugins","installed.json"),j=vn(N);if(j.kind==="missing")return;let J=j.kind==="ok"?Ze(j.value,"plugins"):void 0;if(!Array.isArray(J))return{platform:"kimi-code",status:"n/a",configPath:N,errors:[`Cannot read ${N}, so doctor cannot tell whether the Kimi Code plugin is installed`]};let Y=J.find((re)=>Ze(re,"id")===Gi);if(Y===void 0)return;if(Ze(Y,"enabled")!==!0)return{platform:"kimi-code",status:"disabled",method:uo,configPath:N,errors:[`${Gi} is installed but not enabled in Kimi Code; run /plugins enable ${Gi}`]};return{platform:"kimi-code",status:"configured",method:uo,configPath:N}}function po(_){let N=qi(xc(_.environment),"config.toml"),j=()=>Xy(_.environment)??{platform:"kimi-code",status:"n/a",configPath:N};if(!Vy(N))return j();let J;try{J=Ky(N,"utf-8")}catch(ie){return{platform:"kimi-code",status:"n/a",configPath:N,errors:[`Failed to read ${N}: ${ie instanceof Error?ie.message:String(ie)}`]}}if(!Jy.test(J))return j();let re=(/"""|'''/.test(J)?[]:Yy(J)).flatMap((ie,de)=>{let fe=Zy(ie);return fe===void 0?[]:[`Kimi Code ignores every hook because hooks entry ${de+1} is invalid (${fe}); fix it in ${N}`]});return{platform:"kimi-code",status:re.length>0?"disabled":"configured",method:"hook config",configPath:N,errors:re.length>0?re:void 0}}import{readFileSync as $c}from"node:fs";import{join as cr}from"node:path";var un="cc-safety-net",xn="index.js",Ut="openclaw.plugin.json",Gt="package.json";var fo="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as Qy,lstatSync as eh,readdirSync as nh,readFileSync as th}from"node:fs";import{dirname as Pc,join as qn}from"node:path";import{fileURLToPath as rh}from"node:url";var Vi=qn("openclaw",un),yt=`run \`openclaw plugins enable ${un}\``,oh="config reload superseded by a newer runtime config source",ih=[xn,Ut,Gt];function Rc(_){let N=_.env.get("OPENCLAW_HOME")?.trim();return N?Ln(N,_.home):_.home}function Ec(_){let N=Rc(_),j=_.env.get("OPENCLAW_STATE_DIR")?.trim();if(j)return Ln(j,N);let J=_.env.get("OPENCLAW_CONFIG_PATH")?.trim();return J?Pc(Ln(J,N)):qn(N,".openclaw")}function _c(_){let N=_.env.get("OPENCLAW_CONFIG_PATH")?.trim();return N?Ln(N,Rc(_)):qn(Ec(_),"openclaw.json")}function lr(_){return qn(Ec(_),"extensions",un)}function sh(_){let N=nh(_);if(N.length===0)return!0;if(N.some((Y)=>!ih.includes(Y)))return!1;let j=qn(_,xn),J=dn(j);return J!==void 0&&!J.isSymbolicLink()&&J.isFile()&&th(j,"utf-8").startsWith(fo)}function Ki(_){let N=lr(_),j=dn(N);if(!j)return;if(!j.isSymbolicLink()&&j.isDirectory()&&sh(N))return;throw Error(`Refusing to modify ${N}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function Tc(){let _=Pc(rh(import.meta.url));return[qn(_,Vi),qn(_,"..",Vi),qn(_,"..","..","..","dist",Vi)]}function Ji(_=Tc()){return _.find((N)=>Qy(N)&&eh(N).isDirectory())}function ah(_=Tc()){let N=Ji(_);if(!N)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return N}function Ac(_=ah()){return[["openclaw","plugins","install",_,"--force","--accept-capabilities"]]}function lh(_){let N=(()=>{try{return JSON.parse(_)}catch{return}})(),j=Ze(Ze(N,"plugin"),"status");return typeof j==="string"?j:void 0}async function ch(){await fn(["openclaw","plugins","enable",un]).catch((_)=>{if(!(_ instanceof Error&&_.message.includes(oh)))throw _})}async function Ic(_){let N=async()=>lh(await fn(["openclaw","plugins","inspect",un,"--runtime","--json"],{stdoutOnly:!0})),j=await N(),J=j==="disabled"&&_;if(J)await ch();let Y=J?await N():j;if(Y==="loaded")return;throw Error(`${Y===void 0?`The ${un} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:Y==="disabled"?`OpenClaw reports the ${un} plugin with status "disabled"; ${yt}.`:`OpenClaw reports the ${un} plugin with status "${Y}".`} Run \`openclaw plugins inspect ${un} --runtime\` for details.`)}var mo="openclaw";function Bt(_,N){let j=cr(_,N),J=dn(j);if(!J)return{error:`${N} is missing from ${j}; run install --openclaw`};if(J.isSymbolicLink()||!J.isFile())return{error:`${j} is a symlink or not a regular file; move or remove it`};try{return{content:$c(j,"utf-8")}}catch(Y){return{error:`Failed to read ${j}: ${Y instanceof Error?Y.message:String(Y)}`}}}function Dc(_){try{return JSON.parse(yn(_))}catch{return}}function dh(_){let N=Bt(_,Ut);if("error"in N)return N.error;if(Ze(Dc(N.content),"id")===un)return;return`${cr(_,Ut)} is not a valid ${un} manifest; run install --openclaw`}function uh(_){let N=Bt(_,Gt);if("error"in N)return N.error;let j=Ze(Ze(Dc(N.content),"openclaw"),"extensions");if(Array.isArray(j)&&j.includes(`./${xn}`))return;return`${cr(_,Gt)} does not point OpenClaw at ${xn}; run install --openclaw`}function Oc(_){return Array.isArray(_)?_.filter((N)=>typeof N==="string"):[]}function ph(_){let N=_c(_);if(!dn(N))return`${un} is not enabled; ${yt}`;let j=(()=>{try{return JSON.parse(yn($c(N,"utf-8")))}catch{return}})();if(j===void 0)return`Failed to read ${N}; fix it, then ${yt}`;let J=Ze(j,"plugins");if(Ze(J,"enabled")===!1)return`plugins.enabled is false in ${N}; no OpenClaw plugin loads`;let Y=Ze(Ze(Ze(J,"entries"),un),"enabled");if(Oc(Ze(J,"deny")).includes(un)||Y===!1)return`${un} is disabled in ${N}; ${yt}`;let re=Oc(Ze(J,"allow"));if(re.length>0&&!re.includes(un))return`plugins.allow in ${N} does not list ${un}; add it, then ${yt}`;if(re.includes(un)||Y===!0)return;return`${un} is not enabled; ${yt}`}function Lc(_){return/^\/\/ version:\s*(.+)$/m.exec(_)?.[1]?.trim()}function fh(_,N,j){if(j===void 0)return[];let J=Bt(j,xn);if(!(("content"in J)&&Lc(J.content)===N))return[];return[xn,Ut,Gt].flatMap((re)=>{let ie=Bt(_,re),de=Bt(j,re);if("error"in ie||"error"in de||ie.content===de.content)return[];return[`Modified ${re} occupies ${cr(_,re)}; run install --openclaw to restore it`]})}function Nc(_){let N=lr(_.environment),j=Br(mo,N);if(j)return j;let J=Bt(N,xn),re=["error"in J?J.error:J.content.startsWith(fo)?void 0:`Unmanaged ${xn} occupies ${cr(N,xn)}; move or remove it`,dh(N),uh(N)].filter((ke)=>ke!==void 0),ie="content"in J?Lc(J.content):void 0,de=re.length>0?re:fh(N,ie,Ji());if(de.length>0)return{platform:mo,status:"n/a",configPath:N,errors:de};let fe=ie===pn()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],we=ph(_.environment);if(we)return{platform:mo,status:"disabled",method:"plugin directory",configPath:N,errors:[we,...fe]};return{platform:mo,status:"configured",method:"plugin directory",configPath:N,errors:fe.length>0?fe:void 0}}import{existsSync as Ch,readFileSync as xh}from"node:fs";import{basename as Sh}from"node:path";import{existsSync as go,readFileSync as zi,rmSync as mh}from"node:fs";import{join as An}from"node:path";import{pathToFileURL as gh}from"node:url";var dr="cc-safety-net",xt=`${dr}@latest`,Yi=["opencode.json","opencode.jsonc"],yh=60,hh=250,jc="CCSafetyNetPlugin",vh={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Hc(_){return An(_.env.get("XDG_CONFIG_HOME")||An(_.home,".config"),"opencode")}function Zi(_){return _.env.get("OPENCODE_CONFIG_DIR")||Hc(_)}function Xi(_){return Yi.map((N)=>An(Zi(_),N))}function Qi(_){return[...new Set([Zi(_),Hc(_)])].flatMap((N)=>Yi.map((j)=>An(N,j)))}function Fc(_){return An(_.env.get("XDG_CACHE_HOME")||An(_.home,".cache"),"opencode","packages",xt)}function Mc(_){mh(Fc(_),{recursive:!0,force:!0})}async function Uc(_){let N=(await fn(["opencode","--version"],{stdoutOnly:!0})).trim(),j=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(N),J=Number(j?.[1]),Y=Number(j?.[2]),re=Number(j?.[3]);if(!j||J!==1&&J!==2||J===1&&(Y<18||Y===18&&re<29)||J===2&&Y===0&&re<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${N||"an unknown version"}.`);if(J===2){for(let ie of Xi(_)){if(!go(ie))continue;let de=ns(zi(ie,"utf-8"),ie);if(["plugin","plugins"].some((we)=>{let ke=Ze(de,we);return Array.isArray(ke)&&ke.some((Re)=>yo(Re)&&(typeof Re==="string"?Re:Ze(Re,"package"))!==xt)}))throw Error(`Change the cc-safety-net package spec in ${ie} to ${xt}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[],afterInstall:async()=>{if((await fn(["opencode","plugin","add",xt],{stdoutOnly:!0})).includes("is already configured in"))await Wi(),await fn(["opencode","plugin","update",xt]);let de=await Wi();if(!/^cc-safety-net\s+\S+\s+cc-safety-net@latest\s*$/m.test(de))throw Error("OpenCode did not load cc-safety-net from cc-safety-net@latest. Run `opencode plugin list` for details.");let fe=["--param",`location[directory]=${process.cwd()}`];await fn(["opencode","api","integration.list",...fe]);let we=await fn(["opencode","api","plugin.list",...fe],{stdoutOnly:!0}),ke=es(we);if(ke)throw Error(ke);if(!Gc(we).some(Bc))throw Error("OpenCode lists no active cc-safety-net for this directory. Run `opencode api plugin.list` for details.")}}}return Mc(_),{commands:[["opencode","plugin","-g","-f",xt]],afterInstall:()=>wh(_)}}function Gc(_){return bh(_).filter((N)=>Ze(N,"id")===dr||yo(Ze(Ze(N,"source"),"target"))).map((N)=>Ze(N,"state"))}function Bc(_){return Ze(_,"status")==="active"}function es(_){let N=Gc(_);if(N.some(Bc))return;let j=N.find((J)=>Ze(J,"status")==="failed");if(!j)return;return`OpenCode reports cc-safety-net failed: ${String(Ze(j,"error")).split(`
226
+ `)[0]}`}function bh(_){if(!_)return[];try{let N=Ze(JSON.parse(_),"data");return Array.isArray(N)?N:[]}catch{return[]}}async function Wi(_=1){let N=await fn(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s|\scc-safety-net@latest\s*$/m.test(N)||_===yh)return N;return await new Promise((j)=>setTimeout(j,hh)),Wi(_+1)}async function wh(_){let N=An(Fc(_),"node_modules",dr),j=An(N,"package.json");if(!go(j))throw Error(`The OpenCode plugin cache at ${N} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${xt}\` for details.`);let J=Ze(JSON.parse(zi(j,"utf-8")),"main");if(typeof J!=="string")throw Error(`The cached OpenCode plugin at ${N} declares no "main" entry.`);let Y=An(N,J);if(typeof(await import(gh(Y).href))[jc]==="function")return;throw Error(`The cached OpenCode plugin at ${Y} does not export a callable ${jc}, so OpenCode would load nothing and fail open.`)}function ns(_,N){try{return JSON.parse(yn(_))}catch(j){if(j instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${N}: ${j.message}`);throw j}}function yo(_){let N=typeof _==="string"?_:Ze(_,"package");return typeof N==="string"&&(N===dr||N.startsWith(`${dr}@`))}function ts(_){return["plugin","plugins"].some((N)=>{let j=Ze(_,N);return Array.isArray(j)&&j.some(yo)})}function kh(_,N){let J=["plugin","plugins"].flatMap((Y)=>{let re=ml(_,Y,vh);if(!re)return[];let ie=[],de=0,fe=re.start+1,we=_.slice(re.start+1,re.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let ke of we){if(ke[0].startsWith("//")||ke[0].startsWith("/*"))continue;let Re=re.start+1+ke.index;if(de===0)fe=Re;if(ke[0]==="{"||ke[0]==="[")de++;if(ke[0]==="}"||ke[0]==="]")de--;if(de!==0||ke[0]===",")continue;let Te=Re+ke[0].length;if(yo(JSON.parse(yn(_.slice(fe,Te)))))ie.push({start:fe,end:Te})}return ie}).sort((Y,re)=>Y.start-re.start).reverse().reduce((Y,re)=>{let ie=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(Y.slice(re.end));if(ie?.[0].includes("/")){let de=re.end+ie[0].length-1;return Y.slice(0,re.start)+Y.slice(re.end,de)+Y.slice(de+1)}return fl(Y,re)},_);return ns(J,N),J}function qc(_){Mc(_);let N=Qi(_),j=N.find((re)=>go(re)),J=[],Y=[];for(let re of N){if(!go(re))continue;try{let ie=zi(re,"utf-8");if(!ts(ns(ie,re)))continue;ln(re,kh(ie,re)),Y.push(re)}catch(ie){J.push(ie instanceof Error?ie.message:String(ie))}}if(J.length>0)throw Error(J.join(`
227
+ `));return{path:Y[0]??j??An(Zi(_),Yi[0]),alreadyInstalled:Y.length>0}}function qt(_){let N=[];for(let j of _.openCodeVersion?.startsWith("2.")?Xi(_.environment):Qi(_.environment))if(Ch(j))try{let J=xh(j,"utf-8"),Y=yn(J),re=JSON.parse(Y);if(ts(re)){let ie=es(_.openCodePluginListOutput);if(ie)return{platform:"opencode",status:"disabled",method:"opencode api plugin.list",configPath:j,errors:[...N,ie]};return{platform:"opencode",status:"configured",method:"plugin array",configPath:j,errors:N.length>0?N:void 0}}}catch(J){N.push(`Failed to parse ${Sh(j)}: ${J instanceof Error?J.message:String(J)}`)}return{platform:"opencode",status:"n/a",errors:N.length>0?N:void 0}}import{join as Vc}from"node:path";var Jc="dist/pi/index.js",Kc=new Set([Jc,"index.js"]),Ph=/[*?[\]{}]/;function rs(_){let N=_.env.get("PI_CODING_AGENT_DIR");return Vc(N?Ln(N,_.home):Vc(_.home,".pi","agent"),"settings.json")}function os(_){if(typeof _!=="string")return!1;return _==="npm:cc-safety-net"||_.startsWith("npm:cc-safety-net@")}function Rh(_){if(!Array.isArray(_)||_.length===0)return!1;if(!_.every((J)=>typeof J==="string"))return!1;let N=(J)=>_.some((Y)=>Y.startsWith(J)&&Y.slice(1).replace(/^\.[/\\]/,"")===Jc);if(N("-"))return!1;if(N("+"))return!0;let j=_.filter((J)=>!/^[-+!]/.test(J));return(j.length===0||j.some((J)=>Kc.has(J)))&&!_.some((J)=>J.startsWith("!")&&(Kc.has(J.slice(1))||Ph.test(J)))}function Wc(_){let N=rs(_.environment),j=vn(N);if(j.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(j.kind==="missing")return{platform:"pi",status:"n/a"};let J=Ze(j.value,"packages");if(!Array.isArray(J))return{platform:"pi",status:"n/a"};let Y=J.find((ie)=>os(typeof ie==="string"?ie:Ze(ie,"source")));if(Y===void 0)return{platform:"pi",status:"n/a"};let re=Ze(Y,"extensions");if(re!==void 0&&!Rh(re))return{platform:"pi",status:"disabled",method:"package config",configPath:N,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:N}}var Eh={amp:Qa,"antigravity-cli":tl,"claude-code":al,codex:cl,"copilot-cli":El,cursor:Nl,"deepseek-harness":Hl,devin:Kl,droid:Ql,"gemini-cli":ec,"grok-build":dc,"hermes-agent":Cc,"kimi-code":po,openclaw:Nc,opencode:qt,pi:Wc};function Vt(_,N,j){let J={...j,cwd:N,environment:_};return Rr.map((Y)=>_h(Eh[Y](J)))}function _h(_){if(_.status==="not-inspected")return{platform:_.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:_.platform,detected:_.status!=="n/a",configured:_.status==="configured",inspectionStatus:_.status!=="n/a"?"verified":_.errors&&_.errors.length>0?"failed":"not-applicable",method:_.method,configPath:_.configPath,configPaths:_.configPaths,errors:_.errors}}import{join as Th}from"node:path";var Ah=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}]),Ih=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),commandTools:Object.freeze([]),safety:Object.freeze({}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),Oh={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 zc(_){let N=Th(_.tmpdir,"cc-safety-net-self-test"),j=Ah.map((J)=>{let Y=G(_,l("self-test",{command:J.command},{kind:"command",shell:"auto"},{configCwd:N,executionCwd:N},J.command),{guard:{dependencies:{loadPolicySnapshot:()=>Ih,getModes:()=>Oh,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),re=J.expectBlocked?"blocked":"allowed",ie=Y.decision.kind==="deny"?"blocked":"allowed";return{command:J.command,description:J.description,expected:re,actual:ie,passed:re===ie,reason:Y.decision.kind==="deny"?Y.decision.reason:void 0,ruleId:Y.decision.kind==="deny"?Y.decision.ruleId:void 0}});return{passed:j.filter((J)=>J.passed).length,failed:j.filter((J)=>!J.passed).length,total:j.length,results:j}}function is(_){let N=mn({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},_);if($n(N.errors))return null;return{json:N.flags.json,skipUpdateCheck:N.flags.skipUpdateCheck}}async function Yc(_,N={}){let j=await Xt(!N.json,()=>{let J=Dh(_,N);return{ready:J,finish:()=>J}},()=>Zt(),{loadingMessage:"Checking system status…"});if(N.json)console.log(JSON.stringify(j,null,2));else Lh(j);return j.engineSelfTest.failed>0||j.findings.some((J)=>J.severity==="error")?1:0}async function Dh(_,N){let j=N.cwd??process.cwd(),J=await Lr((Le)=>qt({environment:_,cwd:j,openCodeVersion:Le}).status!=="n/a",void 0,j),Y=Vt(_,j,{ampPluginListOutput:J.ampPluginListOutput,codexPluginListOutput:J.codexPluginListOutput,copilotCliVersion:J.versions["copilot-cli"],openCodeVersion:J.versions.opencode,openCodePluginListOutput:J.openCodePluginListOutput}),re=ga(_,j),ie=ya(_),de=R(_,{cwd:j}),fe=de.policy,we=P(fe,_.env),ke=V(fe,we.capabilities),Re=Ar(_,7),Te=Wa(_,j),Ee=[Ir(j),Lt(_)].filter((Le)=>$h(Le)),De=N.skipUpdateCheck?{currentVersion:pn(),latestVersion:null,updateAvailable:!1}:await Gn(),He={hooks:Y,engineSelfTest:zc(_),userConfig:re.userConfig,projectConfig:re.projectConfig,configState:ze(de),effectiveRules:re.effectiveRules,environment:ie,effectiveSafety:{selectedPreset:fe.safety.level??"standard",level:we.effectiveLevel,capabilities:we.capabilities,ruleOverrides:fe.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(ke).filter(([,Le])=>Le.source==="rule_override"&&Le.override==="off"&&Le.inheritedEnabled&&Le.changesInherited).map(([Le])=>Le),ruleCounts:{stored:Object.keys(fe.destructiveCommandRuleOverrides).length,effective:Object.values(ke).filter((Le)=>Le.changesInherited).length},...de.policyScopes?{policyScopes:de.policyScopes}:{}},...Te.length>0?{v2Leftovers:Te}:{},...Ee.length>0?{legacyConfigs:Ee}:{},posture:Aa(_,re.userConfig.path),activity:Re,update:De,system:J};return{...He,findings:va(He)}}function Lh(_){console.log(),console.log(wa(_.hooks)),console.log(),console.log(ka(_.engineSelfTest)),console.log(),console.log(Ca(_)),console.log(),console.log(xa(_.environment)),console.log(),console.log(Sa(_)),console.log(),console.log(Pa(_.findings)),console.log(),console.log(Ra(_.activity)),console.log(),console.log(_a(_.system)),console.log(),console.log(Ea(_.update)),console.log(Ta(_))}import{existsSync as Nh}from"node:fs";var jh=/^[A-Za-z0-9_@%+=:,./-]+$/,Zc="Usage: cc-safety-net explain [--json] [--cwd <path>] <command>";function ss(_){let N=mn({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"]},positionals:"tail"},_);if($n(N.errors))return console.error(Zc),console.error("Pass -- before a command that starts with dashes."),null;if(N.values.cwd!==void 0&&!Nh(N.values.cwd))return console.error(`Error: --cwd path does not exist: ${N.values.cwd}`),null;let j=N.positionals.length===1?N.positionals[0]:N.positionals.map((J)=>jh.test(J)?J:`'${J.replaceAll("'","'\\''")}'`).join(" ");if(!j)return console.error("Error: No command provided"),console.error(Zc),null;return{json:N.flags.json,cwd:N.values.cwd,command:j}}function Xc(_){if(_)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function Qc(_,N){let J=N-18;return[`${_.dtl}${_.dh.repeat(N)}${_.dtr}`,`${_.dv} Command Analysis${" ".repeat(J)}${_.dv}`,`${_.dbl}${_.dh.repeat(N)}${_.dbr}`]}function as(_){return JSON.stringify(_)}function ed(_,N=0){return`[${_.map((J,Y)=>ba(J,Y,N)).join(",")}]`}function ur(_,N,j=70){let J=_.split(" "),Y=[],re="";for(let ie of J)if(re&&re.length+ie.length+1>j)Y.push(re),re=ie;else re=re?`${re} ${ie}`:ie;if(re)Y.push(re);return Y.map((ie,de)=>de===0?ie:`${N}${ie}`)}function nd(_,N,j){let J=[];switch(_.type){case"parse":return null;case"env-strip":return J.push(""),J.push(`STEP ${N} ${j.h} Strip environment variables`),J.push(` Removed: ${_.envVars.map((Y)=>`${Y}=<redacted>`).join(", ")}`),J.push(` Tokens: ${as(_.output)}`),{lines:J,incrementStep:!0};case"leading-tokens-stripped":return J.push(""),J.push(`STEP ${N} ${j.h} Strip wrappers`),J.push(` Removed: ${_.removed.join(", ")}`),J.push(` Tokens: ${as(_.output)}`),{lines:J,incrementStep:!0};case"shell-wrapper":return J.push(""),J.push(`STEP ${N} ${j.h} Detect shell wrapper`),J.push(` Wrapper: ${_.wrapper} -c`),J.push(` Inner: ${_.innerCommand}`),{lines:J,incrementStep:!0};case"interpreter":{if(J.push(""),J.push(`STEP ${N} ${j.h} Detect interpreter`),J.push(` Interpreter: ${_.interpreter}`),J.push(` Code: ${_.codeArg}`),_.paranoidBlocked)J.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:J,incrementStep:!0}}case"busybox":return J.push(""),J.push(`STEP ${N} ${j.h} Busybox wrapper`),J.push(` Subcommand: ${_.subcommand}`),{lines:J,incrementStep:!0};case"transparent-wrapper":return J.push(""),J.push(`STEP ${N} ${j.h} Transparent wrapper`),J.push(` Wrapper: ${_.wrapper}`),J.push(` Tokens: ${as(_.output)}`),{lines:J,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"rule-check":{if(J.push(""),J.push(`STEP ${N} ${j.h} Match rules`),J.push(` Rule: ${_.rule}()`),_.matched)J.push(" Result: MATCHED");else J.push(" Result: No match");return{lines:J,incrementStep:!0}}case"worktree-relaxation":return J.push(""),J.push(`STEP ${N} ${j.h} Worktree relaxation`),J.push(` Mode: ${n.worktree.name}`),J.push(` Git cwd: ${_.gitCwd}`),J.push(" Result: Allowed local discard in linked worktree"),{lines:J,incrementStep:!0};case"temp-root-relaxation":return J.push(""),J.push(`STEP ${N} ${j.h} Temp-root relaxation`),J.push(` Git cwd: ${_.gitCwd}`),J.push(" Result: Allowed git discard in a temp-root repository"),{lines:J,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(_.embeddedCommandFound)return J.push(""),J.push(`STEP ${N} ${j.h} Fallback scan`),J.push(` Found: ${_.embeddedCommandFound}`),{lines:J,incrementStep:!0};return null}case"custom-rules-check":{if(_.rulesChecked){if(J.push(""),J.push(`STEP ${N} ${j.h} Custom rules`),_.matched)J.push(" Result: MATCHED");else J.push(" Result: No match");return{lines:J,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(_.matched)return J.push(""),J.push(`STEP ${N} ${j.h} Dangerous text check`),J.push(` Token: ${_.token}`),J.push(" Result: MATCHED"),{lines:J,incrementStep:!0};return null}case"strict-unparseable":return J.push(""),J.push(`STEP ${N} ${j.h} Strict mode check`),J.push(` Command: ${_.rawCommand}`),J.push(" Result: ✗ UNPARSEABLE"),{lines:J,incrementStep:!0};case"segment-skipped":return null;case"error":return J.push(""),J.push(`ERROR: ${_.message}`),{lines:J,incrementStep:!1};default:return _}}function ls(_,N){let j=Xc(N?.asciiOnly??!1),J=58,Y=[],re=1;Y.push(...Qc(j,58)),Y.push("");let ie=_.trace.steps.find((De)=>De.type==="error");if(ie&&ie.type==="error"){Y.push("ERROR"),Y.push(` ${ie.message}`),Y.push(""),Y.push("RESULT"),Y.push(` Status: ${_.result==="blocked"?en.red("BLOCKED"):en.green("ALLOWED")}`),Y.push(""),Y.push("CONFIG");let De=_.configSource??"none";return Y.push(` Path: ${De}`),Y.join(`
228
+ `)}let de=_.trace.steps.find((De)=>De.type==="parse");if(de&&de.type==="parse"){Y.push("INPUT"),Y.push(` ${de.input}`),Y.push(""),Y.push(`STEP ${re} ${j.h} Split shell commands`),re++;for(let De=0;De<de.segments.length;De++){let He=de.segments[De];if(He){let Le=Math.random();Y.push(` Segment ${De+1}: ${ed(He,Le)}`)}}}let fe=_.trace.segments,we=fe.length>1;for(let De of fe){if(we){Y.push("");let tn="";if(de&&de.type==="parse"){let Uo=de.segments[De.index];if(Uo)tn=Uo.join(" ")}let rn=54,sn=tn,nn=` Segment ${De.index+1}: `,an=" ";if(tn){if(nn.length+tn.length+an.length>rn){let af=rn-nn.length-an.length;sn=`${tn.substring(0,af-1)}…`}}let Sn=tn?`${nn}${sn}${an}`:` Segment ${De.index+1} `,of=tn?`${nn}${en.cyan(sn)}${an}`:Sn,qs=58-Sn.length,Vs=Math.floor(qs/2),sf=qs-Vs;Y.push(`${j.sh.repeat(Vs)}${of}${j.sh.repeat(sf)}`)}if(De.steps.find((tn)=>tn.type==="segment-skipped")){Y.push(""),Y.push(" (skipped — prior segment blocked)");continue}let Le=!1,Ye=!1;for(let tn of De.steps){let rn=nd(tn,re,j);if(rn){if(Ye=!0,tn.type==="recurse"){Y.push("");let sn=" RECURSING ",nn=58-sn.length-4;Y.push(` ${j.tl}${j.h}${sn}${j.h.repeat(nn)}`),Y.push(` ${j.v}`),Le=!0;continue}for(let sn of rn.lines)if(Le)Y.push(` ${j.v} ${sn}`);else Y.push(sn);if(rn.incrementStep)re++}}if(Le)Y.push(` ${j.v}`),Y.push(` ${j.bl}${j.h.repeat(56)}`);if(!Ye)Y.push(""),Y.push(` ${en.green("✓")} Allowed (no matching rules)`)}if(Y.push(""),Y.push("RESULT"),_.result==="blocked"){if(Y.push(` Status: ${en.red("BLOCKED")}`),_.customRule){if(Y.push(` Rule: ${_.customRule.id}`),_.customRule.rulebook)Y.push(` Rulebook: ${_.customRule.rulebook.name} ${_.customRule.rulebook.version}`);if(_.customRule.source)Y.push(` Source: ${_.customRule.source}`);if(_.customRule.override)Y.push(` Override: reason ${_.customRule.override.reason}`)}if(_.reason){let De=ur(_.reason," ");Y.push(` Reason: ${De[0]}`);for(let He=1;He<De.length;He++)Y.push(De[He]??"")}}else Y.push(` Status: ${en.green("ALLOWED")}`);Y.push(""),Y.push("CONFIG");let ke=_.configSource??"none",Re=_.configValid?"":" (invalid)";Y.push(` Path: ${ke}${Re}`);let Te=_.safetyPresetScope;Y.push(` Safety preset: ${_.selectedPreset??"standard"}${Te?` (${Or(Te)})`:""}`),Y.push(` Effective capabilities: ${_.effectiveLevel}`);let Ee=Object.entries(_.destructiveCommandRuleOverrides??{});if(Y.push(` Rule customizations: ${Ee.length}`),_.ruleActivation)Y.push(` Rule activation: ${_.ruleActivation.id} — ${_.ruleActivation.enabled?"on":"off"} via ${_.ruleActivation.source}`);return Y.join(`
229
+ `)}function cs(_){return JSON.stringify(_,null,2)}import{resolve as Gh}from"node:path";var Hh=["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 td(_){let N=0,j={allocateSegment(){return N++},getNextSegmentIndex(){return N},recordGlobal(J){_.record({kind:"step",scope:"global",step:J})},recordSegment(J,Y=j.currentSegmentIndex){if(Y===void 0)return;_.record({kind:"step",scope:"segment",segmentIndex:Y,step:J})}};return j}function rd(_={}){let N=[],j=_.maxEvents??512,J={maxTextLength:_.maxTextLength??2048,maxListLength:_.maxListLength??128,maxObjectProperties:_.maxObjectProperties??_.maxListLength??128,maxDepth:_.maxDepth??16},Y,re=new Set;return{record(ie){if(Y)return;if(!ie||N.length>=j)return;try{N.push(ps(Fh(ie,J,re)))}catch{}},finish(){if(Y)return Y;return Y=ps({events:Object.freeze(N)}),Y}}}function Fh(_,N,j){if(_.kind!=="step")throw TypeError("invalid trace event");let{scope:J,step:Y}=_;ho(Y,j,N);let re=ds(Y,N,j);if(J==="global")return{kind:"step",scope:"global",step:re};if(J!=="segment")throw TypeError("invalid trace event scope");return{kind:"step",scope:"segment",segmentIndex:_.segmentIndex,step:re}}function ho(_,N,j,J=0,Y=new WeakSet){if(typeof _==="string"){let de=_.slice(0,j.maxTextLength);if(!nt(de))return;for(let fe of ht(de))for(let we of fe.match(/[^\s"'()$]+/g)??[])N.add(od(we));return}if(!_||typeof _!=="object"||J>=j.maxDepth||Y.has(_))return;if(Y.add(_),Array.isArray(_)){let de=Math.min(_.length,j.maxListLength);for(let fe=0;fe<de;fe++)ho(_[fe],N,j,J+1,Y);return}let re=0,ie=new Set;for(let de in _){if(!Object.hasOwn(_,de))continue;if(re>=j.maxObjectProperties)break;re++,ho(de,N,j);let fe=us(de,j,N);if(ie.has(fe))continue;ie.add(fe),ho(_[de],N,j,J+1,Y)}}function ds(_,N,j,J=0,Y=new WeakSet){if(typeof _==="string")return us(_,N,j);if(!_||typeof _!=="object")return _;if(J>=N.maxDepth)return;if(Y.has(_))return;if(Y.add(_),Array.isArray(_)){let de=[],fe=Math.min(_.length,N.maxListLength);for(let we=0;we<fe;we++)de.push(ds(_[we],N,j,J+1,Y));return de}let re={},ie=0;for(let de in _){if(!Object.hasOwn(_,de))continue;if(ie>=N.maxObjectProperties)break;ie++;let fe=us(de,N,j);if(Object.hasOwn(re,fe))continue;Object.defineProperty(re,fe,{value:ds(_[de],N,j,J+1,Y),enumerable:!0,configurable:!0,writable:!0})}return re}function us(_,N,j){let J=_.slice(0,N.maxTextLength),Y=nt(J)?tt(J):J,re=j.size>0?Uh(Y,j):Y;return(Mh(re)?Ne(re):re).slice(0,N.maxTextLength)}function Mh(_){return _.includes("PRIVATE KEY")||_.includes("://")||_.includes("eyJ")||_.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(_)||_.length>=14&&Hh.some((N)=>_.includes(N))||_.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(_)}function Uh(_,N){return _.replace(/[^\s"'()$]+/g,(j)=>N.has(od(j))?"<redacted>":j)}function od(_){let N=2166136261,j=2166136261;for(let J=0;J<_.length;J++)N=Math.imul(N^_.charCodeAt(J),16777619),j=Math.imul(j^_.charCodeAt(_.length-J-1),16777619);return`${N>>>0}:${j>>>0}:${_.length}`}function ps(_){if(_&&typeof _==="object"&&!Object.isFrozen(_)){for(let N of Object.values(_))ps(N);Object.freeze(_)}return _}function pr(_,N={},j){let J=Gh(N.cwd??process.cwd()),Y=N.policySnapshot??R(j,{cwd:J,userConfigDir:N.userConfigDir}),re=P(Y.policy,j.env),ie=Ve({policySnapshot:Y,effectiveCapabilities:re.capabilities,strict:re.strict,paranoidRm:re.paranoidRm,paranoidInterpreters:re.paranoidInterpreters,worktreeMode:re.worktreeMode}),de={effectiveLevel:ie.effectiveLevel,selectedPreset:Y.policy.safety.level??"standard",...Y.policyScopes?{safetyPresetScope:Y.policyScopes.levelScope}:{},effectiveCapabilities:ie.effectiveCapabilities,destructiveCommandRuleOverrides:Y.policy.destructiveCommandRuleOverrides},{configSource:fe,configValid:we}=qh(j,{cwd:J,userConfigDir:N.userConfigDir});if(!_||!_.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:fe,configValid:we,...de};let ke=y(_,"auto");if(ke.status==="limited")throw new b;let Re=ke.dialect==="powershell"?y(_,"posix"):ke,Te=kt(Re),Ee=rd(),De=td(Ee);De.recordGlobal({type:"parse",input:_,segments:Te.map((Sn)=>[...Sn])});let He=l("Bash",{command:_},{kind:"command",shell:"auto"},{configCwd:J,executionCwd:J},_),Le=q(He,{environment:j,trace:De,dependencies:{loadPolicySnapshot:()=>Y}}),Ye=Le.decision.kind==="deny"?Le.decision:null;if(Ye&&(Le.stage==="policy-protection"||Le.stage==="secret-protection"))return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:Bh(Ye),matched:!0,reason:Ye.reason}]}]},result:"blocked",reason:T(Ye.reason),segment:T(id(Ye,_)),ruleId:T(Ye.ruleId),configSource:fe,configValid:we,...de};let tn=De.getNextSegmentIndex();if(Ye&&tn>0&&tn<Te.length)De.recordSegment({type:"segment-skipped",index:tn,reason:"prior-segment-blocked"},tn);let rn=Ee.finish(),sn=Ye?.ruleId??Vh(He,Y,re,j),nn=z.find((Sn)=>Sn.id===sn&&Sn.activationCapability),an=nn?ie.policy.effectiveDestructiveCommandRules[nn.id]:void 0;return{trace:Jh(rn),result:Ye?"blocked":"allowed",reason:Ye?T(Ye.reason):void 0,segment:Ye?T(id(Ye,_)):void 0,ruleId:Ye?T(Ye.ruleId):void 0,customRule:Kh(Wh(Ye?.ruleId,Y)),configSource:fe,configValid:we,...de,...nn&&an?{ruleActivation:{id:nn.id,...an}}:{}}}function id(_,N){return _.evidence?.segment??N}function Bh(_){if(_.reason===Ke)return"policy-protection:findPolicyConfigMutationTargetInSemanticFacts";if(_.reason===qe)return"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts";if(_.reason===v)return"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts";return"secret-protection:findSensitiveTargetInSemanticFacts"}function qh(_,N){let j=I(N.cwd),J=W(_,N),Y=X(_,{cwd:N.cwd,userConfigDir:N.userConfigDir});try{if(r(Y.projectConfigTarget)!==null){if(Un(Y.projectConfigTarget).errors.length===0)return{configSource:j,configValid:!0};return{configSource:j,configValid:!1}}}catch(re){if(re instanceof o)return{configSource:j,configValid:!1};throw re}try{if(r(Y.userConfigTarget)!==null){let re=Un(Y.userConfigTarget);return{configSource:J,configValid:re.errors.length===0}}return{configSource:null,configValid:!0}}catch(re){if(re instanceof o)return{configSource:J,configValid:!1};throw re}}function Vh(_,N,j,J){let Y=N.policy,re=Oe({...Y,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...Y.destructiveCommandRuleOverrides,...Object.fromEntries(z.flatMap((de)=>de.activationCapability?[[de.id,"on"]]:[]))}},N.state==="degraded"?{diagnostics:N.diagnostics,reason:N.reason}:void 0),ie=q(_,{environment:J,dependencies:{loadPolicySnapshot:()=>re,getModes:()=>({...j,strict:!0,paranoidRm:!0,paranoidInterpreters:!0}),findSensitiveTarget:()=>null}});return ie.decision.kind==="deny"?ie.decision.ruleId:void 0}function Kh(_){if(!_)return;return{id:T(_.id),..._.rulebook?{rulebook:{name:T(_.rulebook.name),version:T(_.rulebook.version)}}:{},..._.source?{source:T(_.source)}:{},..._.override?{override:{type:"reason",reason:T(_.override.reason)}}:{}}}function Jh(_){let N=_.events.flatMap((J)=>J.kind==="step"&&J.scope==="global"?[J.step]:[]),j=new Map;for(let J of _.events){if(J.kind!=="step"||J.scope!=="segment")continue;let Y=j.get(J.segmentIndex)??{index:J.segmentIndex,steps:[]};Y.steps.push(J.step),j.set(J.segmentIndex,Y)}return{steps:N,segments:[...j.values()]}}function Wh(_,N){let j=_?.replace(/^custom\./,"");if(!j||!N.policy.rules.some((J)=>J.name===j))return;return N.ruleMetadata[j]??Object.freeze({id:j})}function sd(_){return new Promise((N)=>{process.stdout.write(`${_}
230
+ `,()=>N())})}async function ad(_,N){let j=ss(N);if(!j)return 1;try{let J=pr(j.command,{cwd:j.cwd},_),Y=!!process.env.NO_COLOR||!process.stdout.isTTY;return await sd(j.json?cs(J):ls(J,{asciiOnly:Y})),0}catch(J){let Y=zh(J instanceof f?J.cause:J);if(Y===void 0)throw J;if(j.json)return await sd(JSON.stringify({error:Y})),1;return console.error(Y),1}}function zh(_){if(_ instanceof b)return _.message;if(_ instanceof m)return _.message;if(_ instanceof s&&a[_.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var ld="2.6.11",En=" ",Pt="cc-safety-net";function cd(_){return _.argument?`${_.flags} ${_.argument}`:_.flags}function Yh(_){return Math.max(..._.map((N)=>cd(N).length))}function Zh(_){return Math.max(..._.map((N)=>N.usage.length))}function Xh(_){return Math.max(..._.map((N)=>`${Pt} ${N.usage}`.length))}function Qh(_,N){let j=`${Pt} ${_.usage}`;return`${En}${j.padEnd(N+2)}${_.description}`}function In(_,N){return`${En}${_.padEnd(Math.max(40,_.length+2))}${N}`}function Kt(_,N=console.log){let j=[];if(j.push(`${Pt} ${_.name}`),j.push(""),j.push(`${En}${_.description}`),j.push(""),j.push("USAGE:"),j.push(`${En}${Pt} ${_.usage}`),j.push(""),_.subcommands&&_.subcommands.length>0){j.push("SUBCOMMANDS:");let J=Zh(_.subcommands);for(let Y of _.subcommands)j.push(`${En}${Y.usage.padEnd(J+2)}${Y.description}`);j.push("")}if(_.options.length>0){j.push("OPTIONS:");let J=Yh(_.options);for(let Y of _.options){let re=cd(Y),ie=Y.default?`${Y.description} (default: ${Y.default})`:Y.description;j.push(`${En}${re.padEnd(J+2)}${ie}`)}j.push("")}if(_.examples&&_.examples.length>0){j.push("EXAMPLES:");for(let J of _.examples)j.push(`${En}${J}`)}N(j.join(`
231
+ `))}function fs(){let _=Xh(_r),N=[];N.push(`${Pt} v${ld}`),N.push(""),N.push("Blocks destructive commands and secret access."),N.push(""),N.push("COMMANDS:");for(let j of _r)N.push(Qh(j,_));N.push(""),N.push("GLOBAL OPTIONS:"),N.push(`${En}-h, --help Show help (use with command for command-specific help)`),N.push(`${En}-V, --version Show version`),N.push(""),N.push("HELP:"),N.push(`${En}${Pt} help <command> Show help for a specific command`),N.push(`${En}${Pt} <command> --help Show help for a specific command`),N.push(""),N.push("ENVIRONMENT VARIABLES:"),N.push(In(`${n.level.name}=standard|strict|paranoid`,"Set session safety level")),N.push(In(`${n.worktree.name}=1`,"Allow local git discards in linked worktrees")),N.push(In(`${n.debug.name}=1`,"Print diagnostic messages to stderr")),N.push(In(`${n.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),N.push(In(`${n.projectTightenOnly.name}=1`,"Ignore project policy settings that weaken the user policy")),N.push(In("CC_SAFETY_NET_HOME","Override rule config home directory")),N.push(""),N.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),N.push(In(`${n.strict.name}=1`,"Force safety.overrides.fail_closed on")),N.push(In(`${n.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),N.push(In(`${n.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),N.push(In(`${n.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),N.push(""),N.push("Documentation: https://ccsafetynet.com/docs"),console.log(N.join(`
232
+ `))}function dd(){console.log(ld)}function fr(_,N=console.log){let j=Tr(_);if(!j)return!1;if(j.name.toLowerCase()!==_.toLowerCase())return!1;return Kt(j,N),!0}import{existsSync as Po,readFileSync as yu}from"node:fs";import{join as So}from"node:path";import*as Vn from"node:readline";function ev(_){return _==="install"?"Install":"Uninstall"}function nv(_){return _==="install"?"Installing":"Uninstalling"}function tv(_){return _==="install"?"into":"from"}function fd(_){return _?.available===!0}function rv(_,N){let j=new Set(N);return _.filter((J)=>j.has(J.target)).map((J)=>J.target)}function ud(_,N,j){if(_.every((J)=>!J.available))return N;return Array.from({length:_.length},(J,Y)=>Y+1).map((J)=>(N+J*j+_.length)%_.length).find((J)=>fd(_[J]))}function ov(_,N,j){if(j.ctrl&&j.name==="c")return"interrupt";if(j.name==="escape"||N==="q")return"abort";if(_==="install"&&(N==="u"||N==="U"))return"update";if(j.name==="up"||N==="k")return"up";if(j.name==="down"||N==="j")return"down";if(j.name==="space"||N===" ")return"toggle";if(j.name==="return"||j.name==="enter")return"confirm";return null}function iv(_){return{cursor:_.findIndex((N)=>N.available),selected:[]}}function sv(_,N,j){if(j==="confirm"||j==="update"||j==="abort"||j==="interrupt")return{state:_,done:j};if(j==="up")return{state:{..._,cursor:ud(N,_.cursor,-1)}};if(j==="down")return{state:{..._,cursor:ud(N,_.cursor,1)}};let J=N[_.cursor];if(!fd(J))return{state:_};let Y=_.selected.includes(J.target)?_.selected.filter((re)=>re!==J.target):rv(N,[..._.selected,J.target]);return{state:{..._,selected:Y}}}var md="◉",gd="◯",yd=">",hd=" ";function av(_,N,j){return["",`${ev(_)} CC Safety Net ${tv(_)}:`,"",...N.map((J,Y)=>{let re=j.selected.includes(J.target),ie=Y===j.cursor,de=re?md:gd,fe=ie?yd:hd,we=J.available?"":` (${J.unavailableReason??"not installed"})`,ke=`${de} ${J.label}${we}`,Re=!J.available?en.dim(ke):re?en.green(ke):ie?en.bold(ke):ke;return`${fe} ${Re}`}),"",_==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":N.some((J)=>J.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${_}. q/Esc: close`].join(`
233
+ `)}var pd=["global-hook","plugin"];function lv(_,N,j={}){let J=j.color!==!1?en.bold:(re)=>re;return["","Install the Kimi Code integration as:","",...[`Global hook — ${N?"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((re,ie)=>{let de=ie===_,fe=`${de?md:gd} ${re}`;return`${de?yd:hd} ${de?J(fe):fe}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
234
+ `)}function vd(_){let{input:N,output:j}=_;Vn.emitKeypressEvents(N);let J=N.isRaw===!0;N.setRawMode(!0),N.resume();let Y=0,re=()=>{if(Y===0)return;Vn.moveCursor(j,0,-Y),Vn.cursorTo(j,0),Vn.clearScreenDown(j)},ie=()=>{re();let de=_.render();j.write(`${de}
235
+ `),Y=de.split(`
236
+ `).length};return new Promise((de)=>{let fe=(ke)=>{N.off("keypress",we),N.setRawMode(J),N.pause(),re(),de(ke)};function we(ke,Re){_.onKey(ke,Re,{finish:fe,draw:ie})}N.on("keypress",we),ie()})}function bd(_={}){let N=0;return vd({input:_.input??process.stdin,output:_.output??process.stdout,render:()=>lv(N,_.globalHookInstalled===!0),onKey:(j,J,Y)=>{if(J.ctrl&&J.name==="c"){Y.finish(null),(_.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(J.name==="escape"||j==="q")return Y.finish(null);if(J.name==="return"||J.name==="enter")return Y.finish(pd[N]);if(J.name==="up"||J.name==="down"||j==="k"||j==="j")N=(N+1)%pd.length,Y.draw()}})}function ms(_=process.stdin,N=process.stdout){return Boolean(_.isTTY&&N.isTTY&&typeof _.setRawMode==="function")}function wd(_,N,j={}){let J=j.output??process.stdout,Y=iv(N);return vd({input:j.input??process.stdin,output:J,render:()=>av(_,N,Y),onKey:(re,ie,de)=>{let fe=ov(_,re,ie);if(!fe)return;let we=sv(Y,N,fe);if(Y=we.state,we.done==="interrupt"){de.finish(null),(j.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(we.done==="abort")return de.finish(null);if(we.done==="update")return de.finish("update");if(we.done==="confirm"){if(Y.selected.length===0){J.write("\x07"),de.draw();return}de.finish([...Y.selected]),J.write(`${nv(_)} selected integrations...
237
+ `);return}de.draw()}})}import{existsSync as kd,lstatSync as dv,mkdirSync as uv,mkdtempSync as pv,readdirSync as fv,readFileSync as Wt,rmSync as bo}from"node:fs";import{basename as mv,dirname as gv,join as Cn}from"node:path";import{fileURLToPath as yv}from"node:url";var gs="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",Rt="cc-safety-net",_t="cc-safety-net/index.ts";import{spawn as cv}from"node:child_process";var ys=(_,N)=>{let j=Xn([..._],process.env);return new Promise((J)=>{let Y=cv(j.cmd,j.args,{cwd:N,stdio:["ignore","pipe","pipe"]}),re=di(Y),ie=!1,de=setTimeout(()=>{ie=!0,Y.kill()},120000);Y.on("error",(fe)=>{clearTimeout(de),J({status:null,errorCode:fe.code,stdout:re.stdout,stderr:[fe.message,re.stderr].filter(Boolean).join(`
238
+ `)})}),Y.on("close",(fe)=>{clearTimeout(de),J({status:ie?null:fe,errorCode:ie?"ETIMEDOUT":void 0,stdout:re.stdout,stderr:re.stderr})})})};var Jt="cc-safety-net.ts",hs=Cn("amp",_t);function hv(_){return Cn(_.home,".config","amp","plugins","cc-safety-net.ts")}function vv(){let _=gv(yv(import.meta.url)),N=Cn(_,hs),j=Cn(_,"..",hs),J=Cn(_,"..","..","..","dist",hs);return[N,j,J]}function bv(_=vv()){let N=_.find((j)=>kd(j)&&dv(j).isFile());if(!N)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return N}function Cd(_){try{return JSON.parse(_)}catch{return}}function wo(_){return _.subarray(0,Buffer.byteLength(gs)).toString("utf-8")===gs}async function mr(_,N,j){let J=await _(N,j);if(J.status===0)return J;throw Error([`Failed to run ${N.join(" ")}${J.status===null?"":` (exit ${J.status})`}.`,[J.stdout,J.stderr].filter(Boolean).join(`
235
239
  `).trim()].filter(Boolean).join(`
236
- `))}async function Jc(P){let O=await P(["amp","plugins","repositories","--json"]);if(O.status===null)throw Error(`${O.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 (${O.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
237
- ${O.stderr}`.trim());if(O.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${O.status}). Sign in with "amp login" and rerun install --amp.
238
- ${[O.stdout,O.stderr].filter(Boolean).join(`
239
- `)}`.trim());let D=Vc(O.stdout),j=(Array.isArray(D)?D:[]).filter((J)=>tn(J,"scope")==="user"&&tn(J,"exists")===!0&&tn(J,"viewerCanWrite")===!0).map((J)=>tn(J,"cloneRef")).find((J)=>typeof J==="string"&&J.length>0);if(!j)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 j}async function Kc(P,O,D){let j=nh(Sn(O.tmpdir,"cc-safety-net-amp-"));try{return await rr(P,["amp","clone","user-plugins",j]),await D(j)}finally{ro(j,{recursive:!0,force:!0})}}function Wi(P){return`rerun ${P==="overwrite"?"install":"uninstall"} --amp`}function Wc(P,O,D){let j=Sn(P,O),J=dn(j);if(!J)return;if(J.isSymbolicLink()||!J.isFile())throw Error(`Refusing to ${D} ${O} in your Amp personal plugins repository: not a regular file. Remove it there and ${Wi(D)}.`);let Y=jt(j);if(oo(Y))return Y;throw Error(`Refusing to ${D} unmanaged file ${O} in your Amp personal plugins repository. Remove it there and ${Wi(D)}.`)}function zc(P,O){let D=Sn(P,mt),j=dn(D);if(!j)return;if(j.isSymbolicLink()||!j.isDirectory())throw Error(`Refusing to ${O} ${mt} in your Amp personal plugins repository: not a regular directory. Remove it there and ${Wi(O)}.`);return Wc(P,gt,O)}function ch(P){let O=Sn(P,Nt),D=dn(O);if(!D||D.isSymbolicLink()||!D.isFile())return;let j=jt(O);return oo(j)?j:void 0}async function Yc(P,O,D,j){if(await rr(P,D,O),(await rr(P,["git","status","--porcelain"],O)).stdout.trim()==="")return!1;return await rr(P,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",j],O),await rr(P,["git","push","origin","HEAD"],O),!0}function to(P,O){dh(P,O),uh(P,O)}function Zc(P,O){if(O==="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 dh(P,O){let D=sh(P),j=dn(D);if(!j)return;if(!j.isSymbolicLink()&&j.isFile()&&oo(jt(D))){ro(D);return}Zc(D,O)}function uh(P,O){let D=Sn(P.home,".config","amp","plugins",mt),j=dn(D);if(!j)return;if(!j.isSymbolicLink()&&j.isDirectory()&&ph(D)){ro(D,{recursive:!0});return}Zc(D,O)}function ph(P){let O=rh(gt);if(th(P).join("\x00")!==O)return!1;let D=Sn(P,O),j=dn(D);return!!j&&!j.isSymbolicLink()&&j.isFile()&&oo(jt(D))}function fh(P){let O=l(P);if(!Bc(O))return"";let D=Vc(jt(O,"utf-8"));if(!D||typeof D!=="object"||Array.isArray(D))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(E(D,P.home))};
240
- `}async function Xc(P,O=lh(),D=Ji){let j=Buffer.concat([jt(O),Buffer.from(fh(P),"utf-8")]),J=await Jc(D);return Kc(D,P,async(Y)=>{let re=`${J}/${mt}`,ie=zc(Y,"overwrite"),de=Wc(Y,Nt,"overwrite");if(ie?.equals(j)&&!de)return to(P,"fail"),{path:re,alreadyInstalled:!0};if(eh(Sn(Y,mt),{recursive:!0}),cn(Sn(Y,gt),j),de)ro(Sn(Y,Nt));let fe=await Yc(D,Y,["git","add","--",gt,...de?[Nt]:[]],`chore: update cc-safety-net plugin to v${pn()}`);return to(P,"fail"),{path:re,alreadyInstalled:!fe}})}async function Qc(P,O=Ji){let D=await Jc(O);return Kc(O,P,async(j)=>{let J=zc(j,"remove"),Y=ch(j),re=`${D}/${Y&&!J?Nt:mt}`;if(!J&&!Y)return to(P,"keep"),{path:re,alreadyInstalled:!1};return await Yc(O,j,["git","rm","--",...J?[gt]:[],...Y?[Nt]:[]],`chore: remove cc-safety-net plugin v${pn()}`),to(P,"keep"),{path:re,alreadyInstalled:!0}})}import{existsSync as ed,mkdirSync as mh,readFileSync as gh}from"node:fs";import{dirname as yh}from"node:path";var zi=Cn["antigravity-cli"],yt="cc-safety-net";function ht(P){return Boolean(P)&&typeof P==="object"&&!Array.isArray(P)}function so(){return{PreToolUse:[{hooks:[{type:"command",command:zi,timeout:30}]}]}}function nd(P){try{let O=JSON.parse(gh(P,"utf-8"));if(!O||typeof O!=="object"||Array.isArray(O))throw Error("Antigravity hooks config must be a JSON object");return O}catch(O){if(O instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${P}: ${O.message}`);throw O}}function td(P){let O=P[yt];if(O===void 0){let j=so();return P[yt]=j,{definition:j,preToolUse:j.PreToolUse??[]}}if(!ht(O))throw Error(`Antigravity hooks config entry "${yt}" must be an object`);let D=Array.isArray(O.PreToolUse)?O.PreToolUse:[];return O.PreToolUse=D,{definition:O,preToolUse:D}}function rd(P){if(!Array.isArray(P.PreToolUse))return!1;return P.PreToolUse.some((O)=>ht(O)&&Array.isArray(O.hooks)&&O.hooks.some((D)=>ht(D)&&D.command===zi))}function hh(P){return Object.values(P).some((O)=>ht(O)&&O.enabled!==!1&&rd(O))}function vh(P){if(P[yt]===void 0)return!1;let O=td(P);if(O.definition.enabled!==!1||!rd(O.definition))return!1;return O.definition.enabled=!0,!0}function bh(P){if(P[yt]===void 0){P[yt]=so();return}let O=td(P);O.definition.enabled=!0,O.preToolUse.push(so().PreToolUse?.[0]??{hooks:[]})}function wh(P){let O=!1;for(let D of Object.values(P)){if(!ht(D)||!Array.isArray(D.PreToolUse))continue;D.PreToolUse=D.PreToolUse.flatMap((j)=>{if(!ht(j)||!Array.isArray(j.hooks))return[j];let J=j.hooks.filter((Y)=>!ht(Y)||Y.command!==zi);if(J.length!==j.hooks.length)O=!0;return J.length===0?[]:[{...j,hooks:J}]})}return O}function io(P,O){cn(P,`${JSON.stringify(O,null,2)}
241
- `)}function od(P){let O=Gt(P.home);if(mh(yh(O),{recursive:!0}),!ed(O))return io(O,{[yt]:so()}),{path:O,alreadyInstalled:!1};let D=nd(O);if(hh(D))return{path:O,alreadyInstalled:!0};if(vh(D))return io(O,D),{path:O,alreadyInstalled:!1};return bh(D),io(O,D),{path:O,alreadyInstalled:!1}}function id(P){let O=Gt(P.home);if(!ed(O))return{path:O,alreadyInstalled:!1};let D=nd(O);if(!wh(D))return{path:O,alreadyInstalled:!1};return io(O,D),{path:O,alreadyInstalled:!0}}import{existsSync as Xi,readlinkSync as Ch}from"node:fs";import{join as Vn}from"node:path";import{spawn as kh}from"node:child_process";var $n=En.map((P)=>({target:P.id,flag:P.flag,label:mn(P.id),probeCommand:P.probeCommand}));function Yi(P){let O=new Set(P);return $n.map((D)=>D.target).filter((D)=>O.has(D))}async function sd(P,O){for(let D of P)await O(D)}var xh=5000;function or(P,O=xh){return new Promise((D)=>{let j=zn([...P],process.env),J=kh(j.cmd,j.args,{env:process.env,stdio:"ignore"}),Y=!1,re=(de)=>{if(Y)return;Y=!0,clearTimeout(ie),D(de)},ie=setTimeout(()=>{J.kill(),re(!1)},O);J.on("error",()=>re(!1)),J.on("close",(de)=>re(de===0))})}function ad(P=or,O={}){let D=new Set(O.configuredTargets??[]);return Promise.all($n.map(async(j)=>({target:j.target,flag:j.flag,label:j.label,...cd(O.action,await P(j.probeCommand)||j.target==="cursor"&&await P(Os),D.has(j.target))})))}function ld(P,O){let D=new Set(O.configuredTargets??[]);return P.map((j)=>({...j,...cd(O.action,j.available,D.has(j.target))}))}function cd(P,O,D){if(P==="uninstall")return D?{available:!0}:{available:!1,unavailableReason:"not installed"};if(P==="install"&&D)return{available:!1,unavailableReason:"already installed"};if(!O)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}var Jn="cc-safety-net",fd=["npx","-y","@deepseek-ai/dsh"],dd="DeepSeek Harness",ud=["@deepseek-ai","dsh-desktop"],md="Quit DeepSeek Harness Desktop, then run this command again: Desktop plugins can only change while it is closed.",Zi=(P)=>`DeepSeek Harness Desktop is not in its default location, so ${P} ${Jn} from its Plugins page.`,gd=(P,O)=>Xi(Vn(ri(P),O,"package.json"));function Qi(P,O){let D=O.platform??process.platform,j=gd(P,"desktop"),J=D==="darwin"?[Vn(P.home,"Applications"),O.systemApplications??"/Applications"].map((Y)=>Vn(Y,`${dd}.app`,"Contents","Resources","runtime","cli","bin","dsh")):D==="win32"?[Vn(P.env.get("LOCALAPPDATA")||Vn(P.home,"AppData","Local"),"Programs",dd,"resources","runtime","cli","bin","dsh.cmd")]:[];return{profile:j,cli:j?J.find((Y)=>Xi(Y)):void 0}}function yd(P,O=process.platform){if(O==="win32")return Xi(Vn(P.env.get("APPDATA")||Vn(P.home,"AppData","Roaming"),...ud,"lockfile"));let D=Sh(Vn(P.home,"Library","Application Support",...ud,"SingletonLock")),j=Number(/-(\d+)$/.exec(D??"")?.[1]);return Number.isInteger(j)&&j>0&&Ph(j)}function Sh(P){try{return Ch(P)}catch{return}}function Ph(P){try{return process.kill(P,0),!0}catch(O){return O.code==="EPERM"}}async function hd(P,O={}){let D=Qi(P,O);if(D.cli&&yd(P,O.platform))throw Error(md);let j=!D.cli||gd(P,"web")||await(O.probe??or)(Eo),J=[...D.cli?[{profile:"desktop",label:"Desktop",dsh:[D.cli]}]:[],...j?[{profile:"web",label:"web",dsh:fd}]:[]];return{commands:J.map((Y)=>[...Y.dsh,"plugin","--profile",Y.profile,"add",`${Jn}@${pn()}`]),afterInstall:async()=>{let Y=new Set(oi(P).filter((ie)=>ie.enabled).map((ie)=>ie.name)),re=J.filter((ie)=>!Y.has(ie.profile));if(re.length>0)throw Error(`DeepSeek Harness installed ${Jn} in the ${pd(re)} but did not enable it. Enable it from the Plugins page.`)},message:[`Added ${Jn} to the DeepSeek Harness ${pd(J)}.`,...D.profile&&!D.cli?[Zi("add")]:[]].join(`
242
- `)}}function pd(P){return`${P.map((O)=>O.label).join(" and ")} profile${P.length>1?"s":""}`}function vd(P,O={}){let D=new Set(oi(P).map((Y)=>Y.name));if(!D.has("desktop")&&!D.has("web"))throw Error(`${Jn} is not installed in the DeepSeek Harness web or Desktop profile`);let j=D.has("desktop")?Qi(P,O).cli:void 0,J=D.has("desktop")&&!j;if(J&&!D.has("web"))throw Error(Zi("remove"));if(j&&yd(P,O.platform))throw Error(md);return{commands:[...j?[[j,"plugin","--profile","desktop","remove",Jn]]:[],...D.has("web")?[[...fd,"plugin","--profile","web","remove",Jn]]:[]],...J?{afterUninstall:()=>{throw Error(`Removed ${Jn} from the DeepSeek Harness web profile, but ${Zi("remove")}`)}}:{}}}function bd(P,O,D={}){let j=Qi(O,D).cli!==void 0;return P.map((J)=>J.target==="deepseek-harness"&&j?{...J,available:!0,unavailableReason:void 0}:J)}import{existsSync as Rh,readdirSync as Eh,rmSync as _h}from"node:fs";import{join as Ah}from"node:path";function wd(P,O=process.platform,D){if(!Rh(P))return;let j=O==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);Eh(P).filter((J)=>J!==D&&j.test(J)).forEach((J)=>{_h(Ah(P,J),{recursive:!0,force:!0})})}import{existsSync as kd,readdirSync as Th,rmSync as Ih}from"node:fs";import{join as Ft}from"node:path";function ao(P,O=process.platform){let D=Ft(P.env.get("npm_config_cache")||(O==="win32"?Ft(P.env.get("LOCALAPPDATA")||Ft(P.home,"AppData","Local"),"npm-cache"):Ft(P.home,".npm")),"_npx");if(!kd(D))return;Th(D).filter((j)=>kd(Ft(D,j,"node_modules","cc-safety-net"))).forEach((j)=>{Ih(Ft(D,j),{recursive:!0,force:!0})})}import{existsSync as Ed,mkdirSync as Oh,readFileSync as _d}from"node:fs";import{dirname as Dh,join as Rd}from"node:path";function $h(P,O){if(P[O]!=="#")return O;let D=P.indexOf(`
243
- `,O+1);return D===-1?P.length:D+1}function es(P,O,D){let j=new RegExp(`^(\\s*)${O}\\s*=\\s*\\[`),J=0;for(let Y of P.split(`
244
- `)){if(/^\s*\[/.test(Y))return;let re=j.exec(Y);if(re){let ie=J+re[0].lastIndexOf("[");return{start:ie,end:qo(P,ie,{skipComment:$h,...D})}}J+=Y.length+1}return}function xd(P,O,D){let j=P.slice(0,O.end).trimEnd(),J=Fa(P,O.end),Y=J===""?" ":`${J} `,re=!j.endsWith("[")&&!j.endsWith(",");return`${j}${re?",":""}
245
- ${Y}${D}${P.slice(O.end)}`}function Cd(P,O,D){let j=P.indexOf(D,O.start);if(j===-1||j>O.end)return P;return`${P.slice(0,j)}${P.slice(j+D.length).replace(/^\s*,/,"")}`}function Sd(P,O){let D=new RegExp(`^\\s*${O}\\s*=\\s*\\[\\s*]\\s*(?:#.*)?$`),j=P.split(`
246
- `),J=j.findIndex((ie)=>/^\s*\[/.test(ie)),Y=J===-1?j:j.slice(0,J),re=J===-1?[]:j.slice(J);return[...Y.filter((ie)=>!D.test(ie)),...re].join(`
247
- `)}function Pd(P,O,D){let j=new RegExp(`^\\s*\\[\\[${O}]]\\s*$`,"m");return P.split(/(?=^\s*\[)/m).filter((J)=>!j.test(J)||!J.includes(D)).join("").trimEnd()}var ir=Cn["kimi-code"],ns=`[[hooks]]
240
+ `))}async function xd(_){let N=await _(["amp","plugins","repositories","--json"]);if(N.status===null)throw Error(`${N.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 (${N.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
241
+ ${N.stderr}`.trim());if(N.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${N.status}). Sign in with "amp login" and rerun install --amp.
242
+ ${[N.stdout,N.stderr].filter(Boolean).join(`
243
+ `)}`.trim());let j=Cd(N.stdout),J=(Array.isArray(j)?j:[]).filter((Y)=>Ze(Y,"scope")==="user"&&Ze(Y,"exists")===!0&&Ze(Y,"viewerCanWrite")===!0).map((Y)=>Ze(Y,"cloneRef")).find((Y)=>typeof Y==="string"&&Y.length>0);if(!J)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 J}async function Sd(_,N,j){let J=pv(Cn(N.tmpdir,"cc-safety-net-amp-"));try{return await mr(_,["amp","clone","user-plugins",J]),await j(J)}finally{bo(J,{recursive:!0,force:!0})}}function vs(_){return`rerun ${_==="overwrite"?"install":"uninstall"} --amp`}function Pd(_,N,j){let J=Cn(_,N),Y=dn(J);if(!Y)return;if(Y.isSymbolicLink()||!Y.isFile())throw Error(`Refusing to ${j} ${N} in your Amp personal plugins repository: not a regular file. Remove it there and ${vs(j)}.`);let re=Wt(J);if(wo(re))return re;throw Error(`Refusing to ${j} unmanaged file ${N} in your Amp personal plugins repository. Remove it there and ${vs(j)}.`)}function Rd(_,N){let j=Cn(_,Rt),J=dn(j);if(!J)return;if(J.isSymbolicLink()||!J.isDirectory())throw Error(`Refusing to ${N} ${Rt} in your Amp personal plugins repository: not a regular directory. Remove it there and ${vs(N)}.`);return Pd(_,_t,N)}function wv(_){let N=Cn(_,Jt),j=dn(N);if(!j||j.isSymbolicLink()||!j.isFile())return;let J=Wt(N);return wo(J)?J:void 0}async function Ed(_,N,j,J){if(await mr(_,j,N),(await mr(_,["git","status","--porcelain"],N)).stdout.trim()==="")return!1;return await mr(_,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",J],N),await mr(_,["git","push","origin","HEAD"],N),!0}function vo(_,N){kv(_,N),Cv(_,N)}function _d(_,N){if(N==="keep")return;throw Error(`Local Amp plugin ${_} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function kv(_,N){let j=hv(_),J=dn(j);if(!J)return;if(!J.isSymbolicLink()&&J.isFile()&&wo(Wt(j))){bo(j);return}_d(j,N)}function Cv(_,N){let j=Cn(_.home,".config","amp","plugins",Rt),J=dn(j);if(!J)return;if(!J.isSymbolicLink()&&J.isDirectory()&&xv(j)){bo(j,{recursive:!0});return}_d(j,N)}function xv(_){let N=mv(_t);if(fv(_).join("\x00")!==N)return!1;let j=Cn(_,N),J=dn(j);return!!J&&!J.isSymbolicLink()&&J.isFile()&&wo(Wt(j))}function Sv(_){let N=u(_);if(!kd(N))return"";let j=Cd(Wt(N,"utf-8"));if(!j||typeof j!=="object"||Array.isArray(j))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(k(j,_.home))};
244
+ `}async function Td(_,N=bv(),j=ys){let J=Buffer.concat([Wt(N),Buffer.from(Sv(_),"utf-8")]),Y=await xd(j);return Sd(j,_,async(re)=>{let ie=`${Y}/${Rt}`,de=Rd(re,"overwrite"),fe=Pd(re,Jt,"overwrite");if(de?.equals(J)&&!fe)return vo(_,"fail"),{path:ie,alreadyInstalled:!0};if(uv(Cn(re,Rt),{recursive:!0}),ln(Cn(re,_t),J),fe)bo(Cn(re,Jt));let we=await Ed(j,re,["git","add","--",_t,...fe?[Jt]:[]],`chore: update cc-safety-net plugin to v${pn()}`);return vo(_,"fail"),{path:ie,alreadyInstalled:!we}})}async function Ad(_,N=ys){let j=await xd(N);return Sd(N,_,async(J)=>{let Y=Rd(J,"remove"),re=wv(J),ie=`${j}/${re&&!Y?Jt:Rt}`;if(!Y&&!re)return vo(_,"keep"),{path:ie,alreadyInstalled:!1};return await Ed(N,J,["git","rm","--",...Y?[_t]:[],...re?[Jt]:[]],`chore: remove cc-safety-net plugin v${pn()}`),vo(_,"keep"),{path:ie,alreadyInstalled:!0}})}import{existsSync as Id,mkdirSync as Pv,readFileSync as Rv}from"node:fs";import{dirname as Ev}from"node:path";var bs=kn["antigravity-cli"],Tt="cc-safety-net";function At(_){return Boolean(_)&&typeof _==="object"&&!Array.isArray(_)}function Co(){return{PreToolUse:[{hooks:[{type:"command",command:bs,timeout:30}]}]}}function Od(_){try{let N=JSON.parse(Rv(_,"utf-8"));if(!N||typeof N!=="object"||Array.isArray(N))throw Error("Antigravity hooks config must be a JSON object");return N}catch(N){if(N instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${_}: ${N.message}`);throw N}}function $d(_){let N=_[Tt];if(N===void 0){let J=Co();return _[Tt]=J,{definition:J,preToolUse:J.PreToolUse??[]}}if(!At(N))throw Error(`Antigravity hooks config entry "${Tt}" must be an object`);let j=Array.isArray(N.PreToolUse)?N.PreToolUse:[];return N.PreToolUse=j,{definition:N,preToolUse:j}}function Dd(_){if(!Array.isArray(_.PreToolUse))return!1;return _.PreToolUse.some((N)=>At(N)&&Array.isArray(N.hooks)&&N.hooks.some((j)=>At(j)&&j.command===bs))}function _v(_){return Object.values(_).some((N)=>At(N)&&N.enabled!==!1&&Dd(N))}function Tv(_){if(_[Tt]===void 0)return!1;let N=$d(_);if(N.definition.enabled!==!1||!Dd(N.definition))return!1;return N.definition.enabled=!0,!0}function Av(_){if(_[Tt]===void 0){_[Tt]=Co();return}let N=$d(_);N.definition.enabled=!0,N.preToolUse.push(Co().PreToolUse?.[0]??{hooks:[]})}function Iv(_){let N=!1;for(let j of Object.values(_)){if(!At(j)||!Array.isArray(j.PreToolUse))continue;j.PreToolUse=j.PreToolUse.flatMap((J)=>{if(!At(J)||!Array.isArray(J.hooks))return[J];let Y=J.hooks.filter((re)=>!At(re)||re.command!==bs);if(Y.length!==J.hooks.length)N=!0;return Y.length===0?[]:[{...J,hooks:Y}]})}return N}function ko(_,N){ln(_,`${JSON.stringify(N,null,2)}
245
+ `)}function Ld(_){let N=Qt(_.home);if(Pv(Ev(N),{recursive:!0}),!Id(N))return ko(N,{[Tt]:Co()}),{path:N,alreadyInstalled:!1};let j=Od(N);if(_v(j))return{path:N,alreadyInstalled:!0};if(Tv(j))return ko(N,j),{path:N,alreadyInstalled:!1};return Av(j),ko(N,j),{path:N,alreadyInstalled:!1}}function Nd(_){let N=Qt(_.home);if(!Id(N))return{path:N,alreadyInstalled:!1};let j=Od(N);if(!Iv(j))return{path:N,alreadyInstalled:!1};return ko(N,j),{path:N,alreadyInstalled:!0}}import{existsSync as Cs,readlinkSync as Dv}from"node:fs";import{join as Kn}from"node:path";import{spawn as Ov}from"node:child_process";var On=Rn.map((_)=>({target:_.id,flag:_.flag,label:cn(_.id),probeCommand:_.probeCommand}));function ws(_){let N=new Set(_);return On.map((j)=>j.target).filter((j)=>N.has(j))}async function jd(_,N){for(let j of _)await N(j)}var $v=5000;function gr(_,N=$v){return new Promise((j)=>{let J=Xn([..._],process.env),Y=Ov(J.cmd,J.args,{env:process.env,stdio:"ignore"}),re=!1,ie=(fe)=>{if(re)return;re=!0,clearTimeout(de),j(fe)},de=setTimeout(()=>{Y.kill(),ie(!1)},N);Y.on("error",()=>ie(!1)),Y.on("close",(fe)=>ie(fe===0))})}function Hd(_=gr,N={}){let j=new Set(N.configuredTargets??[]);return Promise.all(On.map(async(J)=>({target:J.target,flag:J.flag,label:J.label,...Md(N.action,await _(J.probeCommand)||J.target==="cursor"&&await _(ra),j.has(J.target))})))}function Fd(_,N){let j=new Set(N.configuredTargets??[]);return _.map((J)=>({...J,...Md(N.action,J.available,j.has(J.target))}))}function Md(_,N,j){if(_==="uninstall")return j?{available:!0}:{available:!1,unavailableReason:"not installed"};if(_==="install"&&j)return{available:!1,unavailableReason:"already installed"};if(!N)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}var Jn="cc-safety-net",qd=["npx","-y","@deepseek-ai/dsh"],Ud="DeepSeek Harness",Gd=["@deepseek-ai","dsh-desktop"],Vd="Quit DeepSeek Harness Desktop, then run this command again: Desktop plugins can only change while it is closed.",ks=(_)=>`DeepSeek Harness Desktop is not in its default location, so ${_} ${Jn} from its Plugins page.`,Kd=(_,N)=>Cs(Kn(wi(_),N,"package.json"));function xs(_,N){let j=N.platform??process.platform,J=Kd(_,"desktop"),Y=j==="darwin"?[Kn(_.home,"Applications"),N.systemApplications??"/Applications"].map((re)=>Kn(re,`${Ud}.app`,"Contents","Resources","runtime","cli","bin","dsh")):j==="win32"?[Kn(_.env.get("LOCALAPPDATA")||Kn(_.home,"AppData","Local"),"Programs",Ud,"resources","runtime","cli","bin","dsh.cmd")]:[];return{profile:J,cli:J?Y.find((re)=>Cs(re)):void 0}}function Jd(_,N=process.platform){if(N==="win32")return Cs(Kn(_.env.get("APPDATA")||Kn(_.home,"AppData","Roaming"),...Gd,"lockfile"));let j=Lv(Kn(_.home,"Library","Application Support",...Gd,"SingletonLock")),J=Number(/-(\d+)$/.exec(j??"")?.[1]);return Number.isInteger(J)&&J>0&&Nv(J)}function Lv(_){try{return Dv(_)}catch{return}}function Nv(_){try{return process.kill(_,0),!0}catch(N){return N.code==="EPERM"}}async function Wd(_,N={}){let j=xs(_,N);if(j.cli&&Jd(_,N.platform))throw Error(Vd);let J=!j.cli||Kd(_,"web")||await(N.probe??gr)(Bo),Y=[...j.cli?[{profile:"desktop",label:"Desktop",dsh:[j.cli]}]:[],...J?[{profile:"web",label:"web",dsh:qd}]:[]];return{commands:Y.map((re)=>[...re.dsh,"plugin","--profile",re.profile,"add",`${Jn}@${pn()}`]),afterInstall:async()=>{let re=new Set(ki(_).filter((de)=>de.enabled).map((de)=>de.name)),ie=Y.filter((de)=>!re.has(de.profile));if(ie.length>0)throw Error(`DeepSeek Harness installed ${Jn} in the ${Bd(ie)} but did not enable it. Enable it from the Plugins page.`)},message:[`Added ${Jn} to the DeepSeek Harness ${Bd(Y)}.`,...j.profile&&!j.cli?[ks("add")]:[]].join(`
246
+ `)}}function Bd(_){return`${_.map((N)=>N.label).join(" and ")} profile${_.length>1?"s":""}`}function zd(_,N={}){let j=new Set(ki(_).map((re)=>re.name));if(!j.has("desktop")&&!j.has("web"))throw Error(`${Jn} is not installed in the DeepSeek Harness web or Desktop profile`);let J=j.has("desktop")?xs(_,N).cli:void 0,Y=j.has("desktop")&&!J;if(Y&&!j.has("web"))throw Error(ks("remove"));if(J&&Jd(_,N.platform))throw Error(Vd);return{commands:[...J?[[J,"plugin","--profile","desktop","remove",Jn]]:[],...j.has("web")?[[...qd,"plugin","--profile","web","remove",Jn]]:[]],...Y?{afterUninstall:()=>{throw Error(`Removed ${Jn} from the DeepSeek Harness web profile, but ${ks("remove")}`)}}:{}}}function Yd(_,N,j={}){let J=xs(N,j).cli!==void 0;return _.map((Y)=>Y.target==="deepseek-harness"&&J?{...Y,available:!0,unavailableReason:void 0}:Y)}import{existsSync as jv,readdirSync as Hv,rmSync as Fv}from"node:fs";import{join as Mv}from"node:path";function Zd(_,N=process.platform,j){if(!jv(_))return;let J=N==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);Hv(_).filter((Y)=>Y!==j&&J.test(Y)).forEach((Y)=>{Fv(Mv(_,Y),{recursive:!0,force:!0})})}import{existsSync as Xd,readdirSync as Uv,rmSync as Gv}from"node:fs";import{join as zt}from"node:path";function xo(_,N=process.platform){let j=zt(_.env.get("npm_config_cache")||(N==="win32"?zt(_.env.get("LOCALAPPDATA")||zt(_.home,"AppData","Local"),"npm-cache"):zt(_.home,".npm")),"_npx");if(!Xd(j))return;Uv(j).filter((J)=>Xd(zt(j,J,"node_modules","cc-safety-net"))).forEach((J)=>{Gv(zt(j,J),{recursive:!0,force:!0})})}import{existsSync as ou,mkdirSync as qv,readFileSync as iu}from"node:fs";import{dirname as Vv,join as ru}from"node:path";function Bv(_,N){if(_[N]!=="#")return N;let j=_.indexOf(`
247
+ `,N+1);return j===-1?_.length:j+1}function Ss(_,N,j){let J=new RegExp(`^(\\s*)${N}\\s*=\\s*\\[`),Y=0;for(let re of _.split(`
248
+ `)){if(/^\s*\[/.test(re))return;let ie=J.exec(re);if(ie){let de=Y+ie[0].lastIndexOf("[");return{start:de,end:ai(_,de,{skipComment:Bv,...j})}}Y+=re.length+1}return}function Qd(_,N,j){let J=_.slice(0,N.end).trimEnd(),Y=pl(_,N.end),re=Y===""?" ":`${Y} `,ie=!J.endsWith("[")&&!J.endsWith(",");return`${J}${ie?",":""}
249
+ ${re}${j}${_.slice(N.end)}`}function eu(_,N,j){let J=_.indexOf(j,N.start);if(J===-1||J>N.end)return _;return`${_.slice(0,J)}${_.slice(J+j.length).replace(/^\s*,/,"")}`}function nu(_,N){let j=new RegExp(`^\\s*${N}\\s*=\\s*\\[\\s*]\\s*(?:#.*)?$`),J=_.split(`
250
+ `),Y=J.findIndex((de)=>/^\s*\[/.test(de)),re=Y===-1?J:J.slice(0,Y),ie=Y===-1?[]:J.slice(Y);return[...re.filter((de)=>!j.test(de)),...ie].join(`
251
+ `)}function tu(_,N,j){let J=new RegExp(`^\\s*\\[\\[${N}]]\\s*$`,"m");return _.split(/(?=^\s*\[)/m).filter((Y)=>!J.test(Y)||!Y.includes(j)).join("").trimEnd()}var yr=kn["kimi-code"],Ps=`[[hooks]]
248
252
  event = "PreToolUse"
249
- command = "${ir}"`,Ad=`{ event = "PreToolUse", command = "${ir}" }`,Td={stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"};function Id(P){return Rd(P.env.get("KIMI_CODE_HOME")??Rd(P.home,".kimi-code"),"config.toml")}function Lh(P){let O=es(P,"hooks",Td);if(O&&P.slice(O.start+1,O.end).trim())return xd(P,O,Ad);let D=Sd(P,"hooks").trimEnd();if(D==="")return`${ns}
250
- `;return`${D}
251
-
252
- ${ns}
253
- `}function $d(P){let O=Id(P);if(Oh(Dh(O),{recursive:!0}),!Ed(O))return cn(O,`${ns}
254
- `),{path:O,alreadyInstalled:!1};let D=_d(O,"utf-8");if(D.includes(ir))return{path:O,alreadyInstalled:!0};return cn(O,Lh(D)),{path:O,alreadyInstalled:!1}}function Od(P){let O=Id(P);if(!Ed(O))return{path:O,alreadyInstalled:!1};let D=_d(O,"utf-8");if(!D.includes(ir))return{path:O,alreadyInstalled:!1};let j=es(D,"hooks",Td),J=j?Cd(D,j,Ad):`${Pd(D,"hooks",ir)}
255
- `;return cn(O,J),{path:O,alreadyInstalled:!0}}var ts="safety-net@cc-marketplace",Dd=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),Ld=new Set(["antigravity-cli","cursor","devin","droid","grok-build","hermes-agent","kimi-code"]);function rs(P){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Md(P){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(P??"")}function Nh(P){return/^Marketplace `cc-marketplace`\s*$/m.test(P??"")}var Ud={"claude-code":{installCommands:(P)=>{let O=$r(P,"cc-safety-net@cc-marketplace");return{commands:[...O?[["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"]],...Or(P).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:$r(P,ts)?[["claude","plugin","uninstall",ts]]:[],update:O}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(P,O)=>{let D=O??await gn(["codex","plugin","list"]),j=Md(D);return{commands:[j||Nh(D)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:rs(D)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:j}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:Da},"copilot-cli":{installCommands:async()=>{let P=await gn(["copilot","plugin","list"]),O=[...Ja(P)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...Ka(P)?[["copilot","plugin","uninstall",qa]]:[]];if(Ba(P))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",An]],cleanupCommands:O,update:!0};return{commands:[Va(await gn(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",An]],cleanupCommands:O}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(P)=>{let O=pi(P);if(O.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(O.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:Ci,installCommands:(P)=>{let O=!co(lo(Zt(P),Pn));return{commands:ec(),afterInstall:()=>nc(O)}},uninstallCommands:[["openclaw","plugins","uninstall",un,"--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(`
256
- `)},opencode:{installCommands:uc},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]},"deepseek-harness":{installCommands:(P)=>hd(P),uninstallCommands:(P)=>vd(P)}};function Gd(P,O=(D)=>D){try{let D=JSON.parse(O(Hd(P,"utf-8")));if(!D||typeof D!=="object"||Array.isArray(D))throw Error(`Settings file ${P} must be a JSON object`);return D}catch(D){if(D instanceof SyntaxError)throw Error(`Failed to parse ${P}: ${D.message}`);throw D}}function jh(P){let O=lo(Vt(P),"settings.json");if(!co(O))return;let D=Gd(O,vn),j=D.enabledPlugins;if(!j||typeof j!=="object"||Array.isArray(j))return;if(j[An]!==!1)return;let J=Hd(O,"utf-8"),Y=J.replace(new RegExp(`("${An}"\\s*:\\s*)false`),"$1true");return j[An]=!0,cn(O,Y!==J?Y:`${JSON.stringify(D,null,2)}
257
- `),`Enabled ${An} plugin in ${O}`}function Fh(P){let O=Oi(P);if(!co(O))return;let D=Gd(O);if(!Array.isArray(D.packages))return;let j=D.packages.find((J)=>!!J&&typeof J==="object"&&!Array.isArray(J)&&Di(J.source)&&("extensions"in J));if(!j)return;return delete j.extensions,cn(O,`${JSON.stringify(D,null,2)}
258
- `),`Enabled npm:cc-safety-net extensions in ${O}`}function Nd(P,O){let D=yn({label:O,booleans:Object.fromEntries($n.map((Y)=>[Y.target,[Y.flag]]))},P),j=D.errors[0];if(j)throw Error(j);let J=$n.filter((Y)=>D.flags[Y.target]).map((Y)=>Y.target);if(J.length!==1)throw Error(`Choose exactly one ${O} target: ${$n.map((Y)=>Y.flag).join(", ")}`);return J[0]}async function qd(P,O=St){let[D,j,J]=await Promise.all([O(["amp","plugins","list"],30000),O(["codex","plugin","list"],30000),O(["copilot","--binary-version"])]);return{codexPluginListOutput:j,hooks:Dt(P,process.cwd(),{ampPluginListOutput:D,codexPluginListOutput:j,copilotCliVersion:J})}}async function Hh(P,O,D=St){let j=await qd(P,D);return j.hooks.filter((J)=>O==="install"?J.configured:J.detected&&J.method!==Ur||J.inspectionStatus==="not-inspected").filter((J)=>J.platform!=="codex"||!rs(j.codexPluginListOutput)||Md(j.codexPluginListOutput)).map((J)=>J.platform)}function Mh(P,O,D,j){if(D.length>0)return{finish:async()=>[Nd(D,O)]};if(!j.selectTargets&&!Bi(j.input,j.output))return{finish:async()=>[Nd(D,O)]};let J=j.detectConfiguredTargets??(()=>Hh(P,O,j.fetchVersion)),Y=Promise.all([ad(j.probeTargets).then((re)=>bd(re,P)),J()]);return{ready:Y,finish:async()=>{let[re,ie]=await Y,de=ld(re,{action:O,configuredTargets:ie}),fe=j.selectTargets?await j.selectTargets(O,Fd(O,de)):await qc(O,Fd(O,de),{input:j.input,output:j.output});if(fe==="update")return fe;if(!fe||fe.length===0)return null;return Yi(fe)}}}async function Uh(P,O,D=!1,j){let J=Ud[P];J.beforeInstall?.(O);let Y=typeof J.installCommands==="function"?await J.installCommands(O,j):{commands:J.installCommands};return await Wo(Y.commands),await Xa(Y.cleanupCommands??[]),await Y.afterInstall?.(),[`${Y.update||D?"Updated":"Installed"} ${mn(P)} integration`,Y.message??J.postInstallMessage].filter(Boolean).join(`
259
- `)}async function Gh(P,O){let D=Ud[P];if(!D.uninstallCommands)throw Error(`${mn(P)} uninstall is not supported`);let j=typeof D.uninstallCommands==="function"?D.uninstallCommands(O):{commands:D.uninstallCommands};return await Wo(j.commands),j.afterUninstall?.(),`Uninstalled ${mn(P)} integration`}function qh(P){let O=gc(P);return O.alreadyInstalled?`Uninstalled OpenCode plugin from ${O.path}`:`OpenCode plugin not installed in ${O.path}`}var Bd={"antigravity-cli":{install:od,uninstall:id},cursor:{install:ol,uninstall:il},devin:{install:ml,uninstall:gl},droid:{install:Cl,uninstall:Sl},"grok-build":{install:$l,uninstall:Ol},"kimi-code":{install:$d,uninstall:Od}};function Bh(P,O,D,j=!1){if(P==="install"&&!j)ao(D);let J=Bd[O][P](D),Y=mn(O),re=P!=="install"?"Uninstalled":j?"Updated":"Installed";return P==="install"&&J.alreadyInstalled?j?`${Y} hook up to date in ${J.path}`:`${Y} hook already installed in ${J.path}`:P==="uninstall"&&!J.alreadyInstalled?`${Y} hook not installed in ${J.path}`:`${re} ${Y} hook ${P==="install"?"in":"from"} ${J.path}`}var Vd={amp:{install:Xc,uninstall:Qc,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:Hl,uninstall:Ml,afterInstall:async(P)=>{let O=ki(P);return await gn(["hermes","plugins","enable",Rn,"--no-allow-tool-override"]),!O},beforeUninstall:async(P)=>{wi(P);try{await gn(["hermes","plugins","disable",Rn])}catch(O){console.warn(`${O instanceof Error?O.message:String(O)}
260
- Removing the plugin files anyway; ${Rn} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function Vh(P,O,D,j=!1){let J=Vd[O];if(P==="uninstall")await J.beforeUninstall?.(D);let Y=P==="install"?await J.install(D):await J.uninstall(D),re=P==="install"&&await J.afterInstall?.(D),ie=mn(O),de=!re&&(P==="install"&&Y.alreadyInstalled||P==="uninstall"&&!Y.alreadyInstalled);return[de?P==="install"?`${ie} plugin ${j?"up to date":"already installed"} at ${Y.path}`:`${ie} plugin not installed at ${Y.path}`:`${P!=="install"?"Uninstalled":j?"Updated":"Installed"} ${ie} plugin ${P==="install"?"at":"from"} ${Y.path}`,de?void 0:J.restartNote].filter(Boolean).join(`
261
- `)}var Jh={"copilot-cli":{afterInstall:jh},cursor:{afterUninstall:el},"hermes-agent":{beforeInstall:(P,O)=>{if(!O)ao(P)}},openclaw:{beforeUninstall:Ci},pi:{afterInstall:Fh}};function Kh(P){return P in Bd}function Wh(P){return P in Vd}var jd=["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/tree/plugin"," 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(`
262
- `);function zh(P){if(Yt({environment:P,cwd:process.cwd()}).status!=="configured")return jd;return[jd,"",nn.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(`
253
+ command = "${yr}"`,su=`{ event = "PreToolUse", command = "${yr}" }`,au={stringError:"Unterminated string in Kimi Code config",bracketError:"Unmatched hooks array in Kimi Code config"};function lu(_){return ru(_.env.get("KIMI_CODE_HOME")??ru(_.home,".kimi-code"),"config.toml")}function Kv(_){let N=Ss(_,"hooks",au);if(N&&_.slice(N.start+1,N.end).trim())return Qd(_,N,su);let j=nu(_,"hooks").trimEnd();if(j==="")return`${Ps}
254
+ `;return`${j}
255
+
256
+ ${Ps}
257
+ `}function cu(_){let N=lu(_);if(qv(Vv(N),{recursive:!0}),!ou(N))return ln(N,`${Ps}
258
+ `),{path:N,alreadyInstalled:!1};let j=iu(N,"utf-8");if(j.includes(yr))return{path:N,alreadyInstalled:!0};return ln(N,Kv(j)),{path:N,alreadyInstalled:!1}}function du(_){let N=lu(_);if(!ou(N))return{path:N,alreadyInstalled:!1};let j=iu(N,"utf-8");if(!j.includes(yr))return{path:N,alreadyInstalled:!1};let J=Ss(j,"hooks",au),Y=J?eu(j,J,su):`${tu(j,"hooks",yr)}
259
+ `;return ln(N,Y),{path:N,alreadyInstalled:!0}}var Rs="safety-net@cc-marketplace",uu=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),pu=new Set(["antigravity-cli","cursor","devin","droid","grok-build","hermes-agent","kimi-code"]);function Es(_){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(_??"")}function hu(_){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(_??"")}function Jv(_){return/^Marketplace `cc-marketplace`\s*$/m.test(_??"")}var vu={"claude-code":{installCommands:(_)=>{let N=Kr(_,"cc-safety-net@cc-marketplace");return{commands:[...N?[["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"]],...ii(_).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:Kr(_,Rs)?[["claude","plugin","uninstall",Rs]]:[],update:N}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(_,N)=>{let j=N??await fn(["codex","plugin","list"]),J=hu(j);return{commands:[J||Jv(j)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:Es(j)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:J}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:ll},"copilot-cli":{installCommands:async()=>{let _=await fn(["copilot","plugin","list"]),N=[...wl(_)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...kl(_)?[["copilot","plugin","uninstall",hl]]:[]];if(vl(_))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",Tn]],cleanupCommands:N,update:!0};return{commands:[bl(await fn(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",Tn]],cleanupCommands:N}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(_)=>{let N=Ii(_);if(N.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(N.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:Ki,installCommands:(_)=>{let N=!Po(So(lr(_),xn));return{commands:Ac(),afterInstall:()=>Ic(N)}},uninstallCommands:[["openclaw","plugins","uninstall",un,"--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(`
260
+ `)},opencode:{installCommands:Uc},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]},"deepseek-harness":{installCommands:(_)=>Wd(_),uninstallCommands:(_)=>zd(_)}};function bu(_,N=(j)=>j){try{let j=JSON.parse(N(yu(_,"utf-8")));if(!j||typeof j!=="object"||Array.isArray(j))throw Error(`Settings file ${_} must be a JSON object`);return j}catch(j){if(j instanceof SyntaxError)throw Error(`Failed to parse ${_}: ${j.message}`);throw j}}function Wv(_){let N=So(tr(_),"settings.json");if(!Po(N))return;let j=bu(N,yn),J=j.enabledPlugins;if(!J||typeof J!=="object"||Array.isArray(J))return;if(J[Tn]!==!1)return;let Y=yu(N,"utf-8"),re=Y.replace(new RegExp(`("${Tn}"\\s*:\\s*)false`),"$1true");return J[Tn]=!0,ln(N,re!==Y?re:`${JSON.stringify(j,null,2)}
261
+ `),`Enabled ${Tn} plugin in ${N}`}function zv(_){let N=rs(_);if(!Po(N))return;let j=bu(N);if(!Array.isArray(j.packages))return;let J=j.packages.find((Y)=>!!Y&&typeof Y==="object"&&!Array.isArray(Y)&&os(Y.source)&&("extensions"in Y));if(!J)return;return delete J.extensions,ln(N,`${JSON.stringify(j,null,2)}
262
+ `),`Enabled npm:cc-safety-net extensions in ${N}`}function fu(_,N){let j=mn({label:N,booleans:Object.fromEntries(On.map((re)=>[re.target,[re.flag]]))},_),J=j.errors[0];if(J)throw Error(J);let Y=On.filter((re)=>j.flags[re.target]).map((re)=>re.target);if(Y.length!==1)throw Error(`Choose exactly one ${N} target: ${On.map((re)=>re.flag).join(", ")}`);return Y[0]}async function wu(_,N=Nt){let[j,J,Y]=await Promise.all([N(["amp","plugins","list"],30000),N(["codex","plugin","list"],30000),N(["copilot","--binary-version"])]);return{codexPluginListOutput:J,hooks:Vt(_,process.cwd(),{ampPluginListOutput:j,codexPluginListOutput:J,copilotCliVersion:Y})}}async function Yv(_,N,j=Nt){let J=await wu(_,j);return J.hooks.filter((Y)=>N==="install"?Y.configured:Y.detected&&Y.method!==eo||Y.inspectionStatus==="not-inspected").filter((Y)=>!xu(Y)).filter((Y)=>Y.platform!=="codex"||!Es(J.codexPluginListOutput)||hu(J.codexPluginListOutput)).map((Y)=>Y.platform)}function Zv(_,N,j,J){if(j.length>0)return{finish:async()=>[fu(j,N)]};if(!J.selectTargets&&!ms(J.input,J.output))return{finish:async()=>[fu(j,N)]};let Y=J.detectConfiguredTargets??(()=>Yv(_,N,J.fetchVersion)),re=Promise.all([Hd(J.probeTargets).then((ie)=>Yd(ie,_)),Y()]);return{ready:re,finish:async()=>{let[ie,de]=await re,fe=Fd(ie,{action:N,configuredTargets:de}),we=J.selectTargets?await J.selectTargets(N,gu(N,fe)):await wd(N,gu(N,fe),{input:J.input,output:J.output});if(we==="update")return we;if(!we||we.length===0)return null;return ws(we)}}}async function Xv(_,N,j=!1,J){let Y=vu[_];Y.beforeInstall?.(N);let re=typeof Y.installCommands==="function"?await Y.installCommands(N,J):{commands:Y.installCommands};return await ui(re.commands),await _l(re.cleanupCommands??[]),await re.afterInstall?.(),[`${re.update||j?"Updated":"Installed"} ${cn(_)} integration`,re.message??Y.postInstallMessage].filter(Boolean).join(`
263
+ `)}async function Qv(_,N){let j=vu[_];if(!j.uninstallCommands)throw Error(`${cn(_)} uninstall is not supported`);let J=typeof j.uninstallCommands==="function"?j.uninstallCommands(N):{commands:j.uninstallCommands};return await ui(J.commands),J.afterUninstall?.(),`Uninstalled ${cn(_)} integration`}function eb(_){let N=qc(_);return N.alreadyInstalled?`Uninstalled OpenCode plugin from ${N.path}`:`OpenCode plugin not installed in ${N.path}`}var ku={"antigravity-cli":{install:Ld,uninstall:Nd},cursor:{install:Dl,uninstall:Ll},devin:{install:ql,uninstall:Vl},droid:{install:Zl,uninstall:Xl},"grok-build":{install:sc,uninstall:ac},"kimi-code":{install:cu,uninstall:du}};function nb(_,N,j,J=!1){if(_==="install"&&!J)xo(j);let Y=ku[N][_](j),re=cn(N),ie=_!=="install"?"Uninstalled":J?"Updated":"Installed";return _==="install"&&Y.alreadyInstalled?J?`${re} hook up to date in ${Y.path}`:`${re} hook already installed in ${Y.path}`:_==="uninstall"&&!Y.alreadyInstalled?`${re} hook not installed in ${Y.path}`:`${ie} ${re} hook ${_==="install"?"in":"from"} ${Y.path}`}var Cu={amp:{install:Td,uninstall:Ad,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:mc,uninstall:gc,afterInstall:async(_)=>{let N=Ui(_);return await fn(["hermes","plugins","enable",Pn,"--no-allow-tool-override"]),!N},beforeUninstall:async(_)=>{Mi(_);try{await fn(["hermes","plugins","disable",Pn])}catch(N){console.warn(`${N instanceof Error?N.message:String(N)}
264
+ Removing the plugin files anyway; ${Pn} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function tb(_,N,j,J=!1){let Y=Cu[N];if(_==="uninstall")await Y.beforeUninstall?.(j);let re=_==="install"?await Y.install(j):await Y.uninstall(j),ie=_==="install"&&await Y.afterInstall?.(j),de=cn(N),fe=!ie&&(_==="install"&&re.alreadyInstalled||_==="uninstall"&&!re.alreadyInstalled);return[fe?_==="install"?`${de} plugin ${J?"up to date":"already installed"} at ${re.path}`:`${de} plugin not installed at ${re.path}`:`${_!=="install"?"Uninstalled":J?"Updated":"Installed"} ${de} plugin ${_==="install"?"at":"from"} ${re.path}`,fe?void 0:Y.restartNote].filter(Boolean).join(`
265
+ `)}var rb={"copilot-cli":{afterInstall:Wv},cursor:{afterUninstall:Al},"hermes-agent":{beforeInstall:(_,N)=>{if(!N)xo(_)}},openclaw:{beforeUninstall:Ki},pi:{afterInstall:zv}};function ob(_){return _ in ku}function ib(_){return _ in Cu}var mu=["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/tree/plugin"," 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(`
266
+ `);function xu(_){return _.platform==="kimi-code"&&_.method===uo}function Su(_){return po({environment:_,cwd:process.cwd()}).method==="hook config"}function sb(_){if(!Su(_))return mu;return[mu,"",en.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(`
263
267
  `))].join(`
264
- `)}function Fd(P,O){return O.map((D)=>P==="install"&&D.target==="kimi-code"&&D.unavailableReason==="already installed"?{...D,available:!0,unavailableReason:void 0,label:`${D.label} (global hook installed)`}:D)}function Yh(P,O){if(P.selectKimiInstallMethod)return P.selectKimiInstallMethod();if(!Bi(P.input,P.output))return Promise.resolve("global-hook");return Gc({input:P.input,output:P.output,globalHookInstalled:Yt({environment:O,cwd:process.cwd()}).status==="configured"})}async function Jd(P,O,D,j=!1,J){let Y=Jh[O];if(P==="install")Y?.beforeInstall?.(D,j);if(P==="uninstall")Y?.beforeUninstall?.(D);if(Kh(O))return[Bh(P,O,D,j),P==="uninstall"?await Y?.afterUninstall?.(D):void 0].filter(Boolean).join(`
265
- `);if(Wh(O))return Vh(P,O,D,j);if(P==="uninstall")return O==="opencode"?qh(D):Gh(O,D);return[await Uh(O,D,j,J),await Y?.afterInstall?.(D)].filter(Boolean).join(`
266
- `)}function Zh(P){let O=yn({label:"update"},P).errors[0];if(O)throw Error(O)}async function Xh(P,O=St){let D=await qd(P,O),j=lo(Vt(P),"installed-plugins");return{targets:Yi([...D.hooks.filter((Y)=>Y.platform!=="copilot-cli"&&Y.detected&&Y.method!==Ur&&Y.method!==ei).map((Y)=>Y.platform),...[Dr,Ga,Ua].flatMap((Y)=>co(lo(j,...Y))?["copilot-cli"]:[]),...$r(P,ts)?["claude-code"]:[],...rs(D.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:D.codexPluginListOutput}}async function Qh(P){let O=c(),D=P.output??process.stdout,j=(P.scriptPath??process.argv[1]??"").split(/[\\/]/),J=j.find((Ie)=>/^bunx-\d+-/.test(Ie)),Y=J!==void 0||j.includes("_npx")?null:(P.checkLatestVersion??Gn)(),re=async()=>{let Ie=Y&&await Y;if(Ie?.updateAvailable)D.write(`
267
- Update available: cc-safety-net ${Ie.currentVersion} → ${Ie.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
268
- `)},ie=Xh(O,P.fetchVersion??St).then(async(Ie)=>{let Ee=new Set(Ie.targets);return{targets:Ie.targets,codexPluginListOutput:Ie.codexPluginListOutput,available:new Map(await Promise.all($n.filter((qe)=>Ee.has(qe.target)&&Dd.has(qe.target)).map(async(qe)=>[qe.target,await or(qe.probeCommand)])))}}),de=await Ut(P.showBanner??!0,()=>({ready:ie,finish:()=>ie}),()=>Mt({input:P.input??process.stdin,output:D}),{loadingMessage:"Checking installed integrations…",output:D}),fe=await Promise.resolve().then(()=>(wd(O.tmpdir,process.platform,J),null)).catch((Ie)=>sr(Ie));if(de.targets.length===0){if(D.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),fe!==null)console.error(fe);return await re(),fe===null?0:1}let we=de.targets.some((Ie)=>Ld.has(Ie))?await Promise.resolve().then(()=>(ao(O),null)).catch((Ie)=>sr(Ie)):null,Ce=await Er(Promise.all(de.targets.map((Ie)=>{if(Dd.has(Ie)&&!de.available.get(Ie))return Promise.resolve({message:`${mn(Ie)} not found; skipped`,failed:!1});if(we!==null&&Ld.has(Ie))return Promise.resolve({message:we,failed:!0});return Jd("install",Ie,O,!0,de.codexPluginListOutput).then((Ee)=>({message:Ee,failed:!1}),(Ee)=>({message:sr(Ee),failed:!0}))})),{loadingMessage:`Updating ${de.targets.length} integration${de.targets.length===1?"":"s"}…`,output:D}),Se=fe===null?Ce:[...Ce,{message:fe,failed:!0}];return Se.forEach((Ie)=>Ie.failed?console.error(Ie.message):D.write(`${Ie.message}
269
- `)),await re(),Se.some((Ie)=>Ie.failed)?1:0}function os(P,O={}){return Promise.resolve().then(()=>Zh(P)).then(()=>Qh(O)).catch((D)=>(console.error(sr(D)),1))}async function ar(P,O,D={}){try{let j=c(),J=await Ut(!0,()=>Mh(j,P,O,D),()=>Mt({input:D.input??process.stdin,output:D.output??process.stdout}),{loadingMessage:P==="install"?"Checking available integrations…":"Checking installed integrations…",output:D.output??process.stdout});if(!J)return(D.output??process.stdout).write(`Cancelled: nothing was ${P}ed.
270
- `),0;if(J==="update")return(D.runUpdate??(()=>os([],{fetchVersion:D.fetchVersion,input:D.input,output:D.output,showBanner:!1})))();let Y=D.output??process.stdout;return await sd(J,async(re)=>{if(re==="kimi-code"&&P==="install"){let de=await Yh(D,j);if(de===null){Y.write(`Cancelled: Kimi Code integration was not installed.
271
- `);return}if(de==="plugin"){Y.write(`${zh(j)}
272
- `);return}}let ie=await Er(Jd(P,re,j),{loadingMessage:`${P==="install"?"Installing":"Uninstalling"} ${mn(re)} integration…`,output:Y});Y.write(`${ie}
273
- `)}),0}catch(j){return console.error(sr(j)),1}}function sr(P){let O=P instanceof Error?P.message:String(P),D=typeof P==="object"&&P!==null&&"code"in P?P.code:null;if(D==="EACCES"||D==="EPERM")return`${O}
274
- Check file permissions for the target config file and parent directory.`;if(D==="ENOENT")return`${O}
275
- Check that the target config path and parent directory exist.`;if(D==="ENOTDIR")return`${O}
276
- Check that every parent path component is a directory.`;return O}import{mkdirSync as iv}from"node:fs";import{dirname as sv}from"node:path";import{createInterface as av}from"node:readline";import{existsSync as Wd,readFileSync as ev}from"node:fs";function vt(P,O){let D=tt(P,O);return{policy:D.policy,errors:ce(Xe(D.issues,et,(j)=>j.kind==="custom")," "," ")}}function lr(P,O){return vt(P,O).errors}function Kd(P,O){return{"safety.level":P.safety.level,...is("safety.overrides",P.safety.overrides),"workflow.worktree_mode":String(P.workflow.worktree_mode),"destructive_command_protection.enabled":String(P.destructive_command_protection.enabled),...is("destructive_command_protection.overrides",P.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":ss(P.destructive_command_protection.allow_paths),"secret_protection.enabled":String(P.secret_protection.enabled),...is("secret_protection.overrides",P.secret_protection.overrides),"secret_protection.deny_paths":ss(P.secret_protection.deny_paths),"secret_protection.allow_paths":ss(P.secret_protection.allow_paths),...O?{"audit.retention_days":String(P.audit.retention_days)}:{}}}function uo(P,O,D){let j=Kd(P,D),J=Kd(O,D);return[...new Set([...Object.keys(j),...Object.keys(J)])].flatMap((Y)=>j[Y]===J[Y]?[]:[{field:Y,before:j[Y],after:J[Y]}])}function cr(P,O){let D=l(P,O);if(!Wd(D))return{baseline:E(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,P.home),diagnostics:[]};let j=bt(D),J=vt(j.value,P.home);return{baseline:J.policy,diagnostics:j.errors.length>0?j.errors:J.errors}}function bt(P){if(!Wd(P))return{errors:[`${P}: file not found`]};try{return{value:JSON.parse(ev(P,"utf-8")),errors:[]}}catch(O){let D=O instanceof Error?O.message:String(O);return{errors:[`${P}: ${O instanceof SyntaxError?`Invalid JSON: ${D}`:D}`]}}}function po(P,O){let D=nv(P)?P:{};return{version:O.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((j)=>D[j]!==void 0).map((j)=>[j,D[j]]))}}function is(P,O){return Object.fromEntries(Object.entries(O).flatMap(([D,j])=>j===void 0?[]:[[`${P}.${D}`,String(j)]]))}function ss(P){return P.length===0?"(none)":P.join(", ")}function nv(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{chmodSync as tv,existsSync as zd,mkdirSync as rv,readFileSync as Yd}from"node:fs";import{dirname as ov}from"node:path";function Zd(P,O={}){let D=l(P,O);if(!zd(D))return{path:D,exists:!1,raw:"",policy:F(),errors:[]};let j=Yd(D,"utf-8");if(!j.trim())return{path:D,exists:!0,raw:j,policy:F(),errors:["Config file is empty"]};try{let J=vt(JSON.parse(j),P.home);return{path:D,exists:!0,raw:j,policy:J.policy,errors:J.errors}}catch(J){return{path:D,exists:!0,raw:j,policy:F(),errors:[`Invalid JSON: ${J instanceof Error?J.message:String(J)}`]}}}function Hn(P,O,D={}){let j=l(P,D),J=vt(O,P.home);if(J.errors.length>0)return{path:j,policy:F(),errors:J.errors};let Y=J.policy;return rv(ov(j),{recursive:!0,mode:448}),g(se(j),`${JSON.stringify(Y,null,2)}
277
- `,384),tv(j,384),{path:j,policy:Y,errors:[]}}function Xd(P,O){let D=vt(O,P.home);if(D.errors.length>0)return{errors:D.errors};return{preview:Le(D.policy,P.env),errors:[]}}function Qd(P,O={}){let D=l(P,O);if(!zd(D))return Hn(P,te,O);let j=Yd(D,"utf-8");if(!j.trim())return Hn(P,te,O);try{return Hn(P,E(JSON.parse(j),P.home),O)}catch{return Hn(P,te,O)}}var eu=new Set(["check","apply"]),nu="(unset)";async function ru(P,O,D={}){let j=yn({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},O),J=j.positionals[0],Y=[...j.errors,...J&&!eu.has(J)?[`Unknown policy subcommand: ${J}`]:[],...J&&eu.has(J)&&!j.positionals[1]?[`policy ${J} requires a file`]:[],...j.positionals.slice(2).map((qe)=>`Unexpected policy argument: ${qe}`)];if(Y.length>0){for(let qe of Y)console.error(qe);return 1}let re=j.positionals[1];if(!J||!re)return Lt(yr,console.error),1;let ie=D.cwd??process.cwd(),de=j.flags.global?l(P):h(ie);if(!j.flags.global&&L(P,{cwd:ie}))return console.error(`${de} is the user policy, not a project policy; use --global for the user scope, or run from a project directory`),1;let fe=bt(re),we=[...fe.errors,...lr(fe.value,P.home).map((qe)=>`${re}: ${qe}`),...!j.flags.global&&dv(fe.value)&&fe.value.audit!==void 0?[`${re}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(we.length>0){for(let qe of we)console.error(qe);return 1}let Ce=E(fe.value,P.home);if(console.log(`Scope: ${j.flags.global?"user":"project"} (${de})`),console.log(`Proposal: ${re}`),j.flags.global)tu(E(bt(de).value,P.home),Ce,!0);if(!j.flags.global){let qe=cr(P).baseline;console.log("Effective policy (user + project merged):"),tu(ee(qe,ue(bt(de).value,P.home).policy).policy,ee(qe,ue(fe.value,P.home).policy).policy,!1)}if(J==="check")return 0;let Se=D.input??process.stdin,Ie=D.output??process.stdout;if(!Se.isTTY||!Ie.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${re}${j.flags.global?" --global":""}`),1;if(!await lv(`Apply this policy to ${de}? [y/N] `,Se,Ie))return console.log("Cancelled; nothing was written."),0;return cv(P,de,fe.value,Ce,j.flags.global),console.log(`Policy applied: ${de}`),0}function lv(P,O,D){let j=av({input:O,output:D,terminal:!1});return new Promise((J)=>{j.once("close",()=>J(!1)),j.question(P,(Y)=>{J(/^y(es)?$/i.test(Y.trim())),j.close()})})}function cv(P,O,D,j,J){if(J){Hn(P,j);return}iv(sv(O),{recursive:!0}),wn(O,po(D,j))}function tu(P,O,D){let j=uo(P,O,D);if(j.length===0){console.log("No changes.");return}console.log(`Changes (${j.length}):`);for(let J of j)console.log(` ${J.field}: ${J.before??nu} -> ${J.after??nu}`)}function dv(P){return!!P&&typeof P==="object"&&!Array.isArray(P)}import{join as Cb}from"node:path";var ou="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- `caffeinate`, `exec`, `nice`, `nohup`, `setsid`, `stdbuf`, `time`, and `timeout` are built-in transparent wrappers and need no configuration. Configure only other wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n\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 fo(P,O){if(!P.ok){cu(P);return}au(P,O)}function su(P,O,D){if(P.ok)console.log(D);if(!P.add){fo(P,`Added rulebook source: ${O}`);return}if(!P.ok){cu(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((j)=>{console.log(` - ${j}`)});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((j)=>j.slice(0,7)).join(", ")}.`);au(P,"Rule config updated.")}function au(P,O){for(let D of P.changes??[])console.log(D);console.log(O),console.log(""),uv(P.entries)}function uv(P){if(P.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${P.length}):`);for(let O of P)console.log(` - ${O.name} ${O.version} (${pv(O.ruleCount)})`),console.log(` Source: ${O.spec}`)}function pv(P){return`${P} ${P===1?"rule":"rules"}`}function lu(P){wt("Active sources",P.rulebooks,(O)=>[`[${O.source}] ${O.name} ${O.version}`,` Source: ${O.spec}`]),wt("Active rules",P.rules,(O)=>[`[${mv(P,O.name)}] ${O.name}`,...fv(O),` Reason: ${O.reason}`]),wt("Disabled rules",iu(P,"off"),(O)=>[O.key]),wt("Reason overrides",iu(P,"reason"),(O)=>[O.key,` Reason: ${O.value.reason}`]),wt("Transparent wrappers",P.transparent_wrappers,(O)=>[O]),wt("Issues",P.errors,(O)=>[O]),wt("Warnings",P.warnings,(O)=>[O])}function wt(P,O,D){if(O.length===0){console.log(`${P}: (none)`);return}console.log(`${P} (${O.length}):`);for(let j of O){let[J,...Y]=D(j);console.log(` - ${J}`);for(let re of Y)console.log(` ${re}`)}}function fv(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 mv(P,O){return P.rulebooks.find((D)=>D.rules.includes(O))?.source??"project"}function iu(P,O){return Object.entries({...P.userConfig?.overrides,...P.projectConfig?.overrides}).filter((D)=>{if(O==="off")return D[1]==="off";return!!D[1]&&typeof D[1]==="object"}).map(([D,j])=>({key:D,value:j}))}function cu(P){for(let O of P.errors)console.error(O)}import{dirname as $u,join as ko}from"node:path";import{join as us,resolve as Rv}from"node:path";function as(P){let O=m(P);if(O.errors.length>0)return{ok:!1,result:{ok:!1,errors:O.errors,entries:[]}};return{ok:!0,config:O.config??ut}}function du(P){wn(P,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function uu(P){wn(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 ho}from"node:path";var gv="custom.";function mo(P){if(P.rulebook_version!==2)return[];let O=P.rules.map((D)=>({name:D.name,command:D.command,block_args:[],match:D.match,reason:D.reason,intent:D.intent}));return(P.tests??[]).flatMap((D,j)=>{let J=ls(y(D.command));if(J.length===0)return[`tests[${j}]: could not parse fixture command: ${D.command}`];let Y=J.reduce((re,ie)=>re??A(ie,O)?.id.slice(gv.length),void 0);if(D.expect==="blocked"){if(Y===D.rule)return[];let re=Y?`"${Y}" matched first`:"no rule matched";return[`tests[${j}]: expected "${D.rule}" to block "${D.command}" but ${re}`]}return Y?[`tests[${j}]: expected "${D.command}" to be allowed but "${Y}" matched`]:[]})}function ls(P){return P.nodes.flatMap((O)=>{if(O.kind==="group"||O.kind==="function")return ls(O.body);if(O.kind!=="command")return[];let D=ve(ne(O.dialect,O.words)).words.map(t);return[...D.length>0?[D]:[],...O.nested.flatMap((j)=>ls(j))]})}var go=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function yo(P={}){return{requests:0,responseBytes:0,maxRequests:P.maxRequests??go.maxRequests,maxResponseBytes:P.maxResponseBytes??go.maxResponseBytes}}function Mn(P){return{controller:new AbortController,budget:yo(),resolveUrl:P}}function pu(P){return P instanceof Error&&P.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function fu(P){if(P.requests>=P.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.requests++}function mu(P,O){if(O>P.maxResponseBytes-P.responseBytes)throw P.responseBytes+=O,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");P.responseBytes+=O}var hu=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function gu(P,O,D=S(ho(ho(O)),"rules policy"),j=Mn()){if(w(P))return bv(P,j);return vv(P,O,D)}async function vu(P,O,D,j,J,Y){if(!w(P))return gu(P,O,D,j);let re=J?null:yv(P,O,D);if(re)return re;if(!J&&!Y)throw Error(`${P} is not vendored; run rule update ${P} to vendor it`);return gu(P,O,D,j)}function yv(P,O,D=S(ho(ho(O)),"rules policy")){let j=N(P),J=M(O,j.name),Y=r(i(D,J));if(Y===null)return null;let re=le(cs(Y,`Invalid rulebook ${J}.`));if(re.name!==j.name)throw Error(`rulebook name "${re.name}" in ${J} must match "${j.name}"`);return{spec:P,rulebook:re,content:Y}}async function bu(P,O={}){if(!Z(P))throw Error(`Invalid GitHub repository source: ${P}`);let[D,j]=P.split("/");if(!D||!j)throw Error(`Invalid GitHub repository source: ${P}`);if(O.ref!==void 0&&!ae(O.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${O.ref}`);let J=O.operation??Mn(),Y=O.ref??await hv(D,j,P,J),re=await ku(D,j,Y,P,J),ie=await vo(`https://api.github.com/repos/${D}/${j}/git/trees/${re}?recursive=1`,"tree",J),de=ie.response;if(!de.ok)throw Error(`Failed to inspect ${P}: GitHub tree returned ${de.status}`);let fe=JSON.parse(ie.content);if(!Array.isArray(fe?.tree))throw Error(`Failed to inspect ${P}: unexpected GitHub tree response`);let we=fe.tree,Ce=[...new Set(we.flatMap((Se)=>{if(!Se||typeof Se!=="object")return[];let Ie=Se;if(Ie.type!=="blob"||typeof Ie.path!=="string")return[];let Ee=Ie.path.match(ct);return Ee?.[1]?[Ee[1]]:[]}))].sort();if(Ce.length===0)throw Error(`No rulebooks found in ${P} under ${he}/`);return{source:P,owner:D,repo:j,ref:Y,commit:re,names:Ce}}async function hv(P,O,D,j){let J=await vo(`https://api.github.com/repos/${P}/${O}`,"metadata",j),Y=J.response;if(!Y.ok)throw Error(`Failed to inspect ${D}: GitHub returned ${Y.status}`);let ie=JSON.parse(J.content)?.default_branch;if(typeof ie!=="string"||ie==="")throw Error(`Failed to inspect ${D}: missing default branch`);if(!ae(ie))throw Error(`GitHub returned an invalid default branch: ${ie}`);return ie}function vv(P,O,D){lt(P);let j=M(O,P),J=r(i(D,j));if(J===null)throw Error(`Rulebook source not found: ${P}`);let Y=wu(cs(J,"Invalid local rulebook source."));if(Y.name!==P)throw Error(`rulebook name "${Y.name}" must match local source "${P}"`);return{spec:P,rulebook:Y,content:J}}async function bv(P,O){let D=N(P),j=await ku(D.owner,D.repo,D.ref,P,O),J=await vo(`https://raw.githubusercontent.com/${D.owner}/${D.repo}/${j}/${D.path}`,"raw",O),Y=J.response;if(!Y.ok)throw Error(`Failed to fetch ${P}: GitHub raw returned ${Y.status}`);let re=J.content,ie=wu(cs(re,"Invalid GitHub rulebook response."));if(ie.name!==D.name)throw Error(`rulebook name "${ie.name}" must match GitHub source "${D.name}"`);return{spec:P,rulebook:ie,content:re}}function wu(P){let O=le(P),D=mo(O);if(D.length>0)throw Error(D.join("; "));return O}function cs(P,O){try{return JSON.parse(P)}catch{throw Error(O)}}async function ku(P,O,D,j,J){let Y=await vo(`https://api.github.com/repos/${P}/${O}/commits/${encodeURIComponent(D)}`,"commit",J),re=Y.response;if(!re.ok)throw Error(`Failed to resolve ${j}: GitHub returned ${re.status}`);let ie=JSON.parse(Y.content);if(typeof ie?.sha!=="string"||ie.sha==="")throw Error(`Failed to resolve commit for ${j}`);return ie.sha}async function wv(P,O,D={}){if(D.signal?.aborted)throw D.signal.reason;let j=D.budget??yo(),J=new AbortController,Y=()=>J.abort(D.signal?.reason);D.signal?.addEventListener("abort",Y,{once:!0});let re=!1,ie=setTimeout(()=>{if(J.signal.aborted)return;re=!0,J.abort()},D.timeoutMs??hu.timeoutMs);try{if(D.signal?.aborted)throw D.signal.reason;fu(j);let de=await fetch(P,{signal:J.signal,redirect:"error"});if(!de.ok)return xu(de),{response:de,content:""};return{response:de,content:await kv(de,O,j,()=>J.abort())}}catch(de){if(re)throw Error("GitHub request timed out",{cause:de});if(D.signal?.aborted)throw D.signal.reason;throw de}finally{clearTimeout(ie),D.signal?.removeEventListener("abort",Y)}}function vo(P,O,D){return wv(D.resolveUrl?.(P)??P,O,{budget:D.budget,signal:D.controller.signal})}async function kv(P,O,D=yo(),j){let J=hu[`${O}Bytes`],Y=Number(P.headers.get("content-length"));if(Number.isFinite(Y)&&Y>J)throw xu(P),Error(`GitHub ${O} response exceeds ${J} bytes`);if(!P.body)return"";let re=P.body.getReader(),ie=[],de=0;while(!0){let fe=await re.read();if(fe.done)break;try{mu(D,fe.value.byteLength)}catch(we){throw j?.(),yu(re),we}if(de+=fe.value.byteLength,de>J)throw j?.(),yu(re),Error(`GitHub ${O} response exceeds ${J} bytes`);ie.push(Buffer.from(fe.value))}return Buffer.concat(ie,de).toString("utf-8")}function xu(P){if(!P.body)return;Cu(()=>P.body?.cancel())}function yu(P){Cu(()=>P.cancel())}function Cu(P){try{Promise.resolve(P()).catch(()=>{})}catch{}}var xv=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function Su(P,O){let D=Eu(P.rules,O);if(D.length>0)return{ok:!0,specs:D};return Ru(P.rules,O)}function Pu(P,O){let D=Eu(P,O);if(D.length>0)return{ok:!0,specs:D};let j=Sv(P,O);if(j.length>0)return{ok:!0,specs:j};let J=Pv(P,O);if(!J.ok)return J;if(J.specs.length>0)return{ok:!0,specs:J.specs};return Ru(P,O)}function Ru(P,O){let D=P.filter((j)=>ds(j)?.name===O);if(D.length===1)return{ok:!0,specs:D};return Cv(O,D)}function Cv(P,O){return{ok:!1,result:{ok:!1,errors:O.length===0?[`No configured rulebook matches ${P}`]:[`Ambiguous rulebook match ${P}: ${O.join(", ")}`],entries:[]}}}function Eu(P,O){return P.filter((D)=>D===O)}function Sv(P,O){let D=O.match(xv),j=D?.[1],J=D?.[2],Y=D?.[3];if(!j||!J||!Y||!ae(Y))return[];return _u(P,(re)=>re.owner===j&&re.repo===J&&re.ref===Y)}function Pv(P,O){if(!Z(O))return{ok:!0,specs:[]};let[D,j]=O.split("/"),J=_u(P,(re)=>re.owner===D&&re.repo===j);if(new Set(J.map((re)=>ds(re)?.ref).filter((re)=>!!re)).size<2)return{ok:!0,specs:J};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${O}. Use an explicit ref:`,` cc-safety-net rule remove ${O}#<ref>`],entries:[]}}}function ds(P){try{return N(P)}catch{return null}}function _u(P,O){return P.filter((D)=>{let j=ds(D);return j?O(j):!1})}async function wo(P,O={}){let D=ps(O);return Ev(P,D,await bo(P,D,Mn()))}function Ev(P,O,D){if(!D.ok)return D;let j=kn(P,O),J=[...new Set(B(j.configPath,j.filesystemScope))];if(J.length===0)return D;return{ok:!1,errors:J,entries:D.entries}}async function bo(P,O,D,j={},J=new Set,Y=new Set){try{let re=kn(P,O),ie=as(re.configTarget);if(!ie.ok)return ie.result;let de=ie.config,fe=O.only?Su(de,O.only):{ok:!0,specs:de.rules};if(!fe.ok)return fe.result;let we=new Set([...O.refresh?fe.specs:[],...J]),Ce=(rn)=>vu(rn,re.configDir,re.filesystemScope,D,we.has(rn),!O.refresh||we.has(rn)),Se=await Fv(de.rules,O.refresh?(rn)=>Ce(rn).then((fn)=>({ok:!0,item:fn})).catch((fn)=>{if(pu(fn))throw fn;return{ok:!1,spec:rn,message:fn instanceof Error?fn.message:String(fn)}}):async(rn)=>({ok:!0,item:await Ce(rn)}),D),Ie=Se.filter((rn)=>!rn.ok),Ee=Se.filter((rn)=>rn.ok).map((rn)=>rn.item),qe=Ee.flatMap((rn)=>_v(rn,de.rules)),Me=Ee.flatMap((rn)=>Av(rn,Y,re)),en=new Set([...qe,...Me].map((rn)=>rn.spec)),on=[...Ie,...qe,...Me],sn=[],an=Iv(sn,()=>Ee.flatMap((rn)=>en.has(rn.spec)||on.length>0&&Y.has(rn.spec)?[]:Tv(rn,re,j,sn)));return{ok:on.length===0,errors:on.map((rn)=>`Failed to update ${rn.spec}: ${rn.message}`),entries:Ee.map(Ov),changes:an}}catch(re){return ur(re)}}function _v(P,O){if(!w(P.spec))return[];let D=Ne(P.spec),j=O.filter((J)=>J!==P.spec&&Ne(J).toLowerCase()===D.toLowerCase());if(j.length===0)return[];return[{ok:!1,spec:P.spec,message:`rulebook name "${D}" is also claimed by ${j.join(", ")}; rename one of them`}]}function Av(P,O,D){if(!O.has(P.spec)||!w(P.spec))return[];let j=M(D.configDir,P.rulebook.name),J=r(i(D.filesystemScope,j));if(J===null||J===P.content)return[];return[{ok:!1,spec:P.spec,message:`${j} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Tv(P,O,D,j){if(!w(P.spec))return[];let J=M(O.configDir,P.rulebook.name),Y=i(O.filesystemScope,J),re=r(Y);if(re===P.content)return[];return j?.push({target:Y,previous:re}),g(Y,P.content,void 0,D._testAfterPolicyRename),$v(P,re)}function Iv(P,O){try{return O()}catch(D){for(let j of[...P].reverse()){if(j.previous===null){H(j.target);continue}g(j.target,j.previous)}throw D}}function $v(P,O){if(O===null)return[`Vendored ${P.spec} (${P.rulebook.version})`];let D=xe(O),j="problem"in D?null:D.rulebook,J=new Map(j?.rules.map((re)=>[re.name,JSON.stringify(re)])??[]),Y=new Set(P.rulebook.rules.map((re)=>re.name));return[`Updated ${P.spec} (${j?.version??"unreadable"} -> ${P.rulebook.version})`,...[...Y].filter((re)=>!J.has(re)).map((re)=>` + ${re}`),...[...J.keys()].filter((re)=>!Y.has(re)).map((re)=>` - ${re}`),...P.rulebook.rules.filter((re)=>{let ie=J.get(re.name);return ie!==void 0&&ie!==JSON.stringify(re)}).map((re)=>` ~ ${re.name}`)]}function Ov(P){return{spec:P.spec,name:P.rulebook.name,version:P.rulebook.version,ruleCount:P.rulebook.rules.length}}async function Au(P,O,D={}){return Dv(P,O,Mv(D),Mn())}async function Dv(P,O,D,j,J={}){let Y=null,re=!1;try{let ie=kn(P,D),de=r(ie.configTarget);Y={target:ie.configTarget,content:de};let fe=as(ie.configTarget);if(!fe.ok)return fe.result;let we=fe.config,Ce=Z(O);Lv(O,D,Ce);let Se=Ce?await bu(O,{ref:D.ref,operation:j}):null,Ie=Se?Nv(Se,D.rulebooks):[],Ee=Se?Ie.map((sn)=>jv(we.rules,Se,sn)??`${O}#${Se.ref}/${sn}`):[O],qe=Ee.filter((sn)=>!we.rules.includes(sn)),Me=[...we.rules,...qe];if(Me.length>ye)return Hv();if(Me.length!==we.rules.length)re=!0,wn(ie.configTarget,{version:1,rules:Me,overrides:we.overrides??{},transparent_wrappers:we.transparent_wrappers??[]},void 0,J._testAfterPolicyRename);let en=await bo(P,D,j,J,new Set(qe),new Set(qe));if(!en.ok)dr(ie.configTarget,de);if(!en.ok||!Se)return en;let on=Ie.filter((sn,an)=>qe.includes(Ee[an]??""));return{...en,add:{source:O,ref:Se.ref,selected:Ie,added:on,alreadyConfigured:Ie.filter((sn)=>!on.includes(sn)),commits:qe.length>0?[Se.commit]:[]}}}catch(ie){if(re&&Y)try{dr(Y.target,Y.content)}catch(de){return ur(de)}return ur(ie)}}function Lv(P,O,D){if(!D&&O.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!D&&O.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${P}`);if(O.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let j=O.rulebooks?.filter((J)=>!d.test(J))??[];if(j.length>0)throw Error(`Invalid rulebook names: ${j.join(", ")}`)}function Nv(P,O){let D=O?[...new Set(O)]:P.names,j=D.filter((J)=>!P.names.includes(J));if(j.length>0)throw Error(`Rulebooks not found in ${P.source} at ${P.ref}: ${j.join(", ")}
278
- Available rulebooks: ${P.names.join(", ")}`);return D}function jv(P,O,D){let j=`${O.source}#${O.ref}/${D}`;if(P.includes(j))return j;let J=`${O.source}#${O.commit}/${D}`;return P.find((Y)=>Y===J)}async function Fv(P,O,D=Mn()){if(P.length>ye)throw Error(be);let j=[],J=0,Y,re=Array.from({length:Math.min(P.length,go.concurrency)},async()=>{while(!Y){let ie=J;if(ie>=P.length)return;J++;try{j[ie]=await O(P[ie],ie,D.controller.signal)}catch(de){if(!Y)Y={value:de},J=P.length,D.controller.abort(de);return}}});if(await Promise.all(re),Y)throw Y.value;return j}function Hv(){return{ok:!1,errors:[be],entries:[]}}function ps(P){return{cwd:P.cwd,userConfigDir:P.userConfigDir,userConfigPath:P.userConfigPath,projectConfigPath:P.projectConfigPath,global:P.global,only:P.only,refresh:P.refresh}}function Mv(P){return{...ps(P),ref:P.ref,rulebooks:P.rulebooks}}function Uv(P){return{...ps(P),deleteSource:P.deleteSource}}async function Tu(P,O,D={}){try{return await Gv(P,O,Uv(D),{})}catch(j){return ur(j)}}async function Gv(P,O,D,j){let J=kn(P,D),Y=m(J.configTarget);if(Y.errors.length>0)return{ok:!1,errors:Y.errors,entries:[]};if(!Y.config)return{ok:!1,errors:[`No config found at ${J.configPath}`],entries:[]};let re=Pu(Y.config.rules,O);if(!re.ok)return re.result;let ie=D.deleteSource?qv(J.configDir,re.specs,J.filesystemScope):{ok:!0,dirs:[]};if(!ie.ok)return ie.result;let de=r(J.configTarget);if(de===null)return ur(Error("Rules config is unavailable."));try{wn(J.configTarget,{version:1,rules:Y.config.rules.filter((Ce)=>!re.specs.includes(Ce)),overrides:Y.config.overrides??{},transparent_wrappers:Y.config.transparent_wrappers??[]},void 0,j._testAfterPolicyRename)}catch(Ce){throw dr(J.configTarget,de),Ce}let fe=await bo(P,D,Mn(),j);if(!fe.ok)return dr(J.configTarget,de),fe;let we=Bv(ie.dirs,j,J.filesystemScope);if(!we.ok){dr(J.configTarget,de);let Ce=await bo(P,D,Mn(),j);if(!Ce.ok)return{ok:!1,errors:[...we.result.errors,...Ce.errors],entries:Ce.entries};return we.result}return fe}function qv(P,O,D){let j=O.flatMap((ie)=>d.test(ie)?[]:["--delete-source can only delete local rulebook sources"]),J=O.map((ie)=>us(P,ie)),Y=j.length>0?[]:J.flatMap((ie)=>Iu(ie,D)),re=[...j,...Y];return re.length>0?{ok:!1,result:{ok:!1,errors:re,entries:[]}}:{ok:!0,dirs:J}}function Iu(P,O){let D=Rv(P),j=i(O,D),J=me(j);if(!J)return[`Local rulebook source directory not found: ${P}`];let Y=J.find((re)=>re.name==="rulebook.json");if(!Y)return[`Local rulebook source directory is missing rulebook.json: ${P}`];if(Y.kind!=="file")throw new o(O.label);if(r(i(O,us(D,"rulebook.json"))),J.length>1)return[`Local rulebook source directory contains extra files: ${P}. delete manually if you really want to remove the directory.`];return[]}function Bv(P,O,D){let j=P.flatMap((J)=>{try{if(!me(i(D,J)))return[];let Y=Iu(J,D);if(Y.length>0)return Y;return Vv(J,O,D),[]}catch(Y){return[`Failed to delete local rulebook source ${J}: ${Y instanceof Error?Y.message:String(Y)}`]}});return j.length>0?{ok:!1,result:{ok:!1,errors:j,entries:[]}}:{ok:!0}}function Vv(P,O,D){if(O._testDeleteLocalSourceDir){O._testDeleteLocalSourceDir(P);return}H(i(D,us(P,ge))),at(i(D,P))}function dr(P,O){if(O===null){H(P);return}g(P,O)}function ur(P){return{ok:!1,errors:[P instanceof Error?P.message:String(P)],entries:[]}}var Jv=".safety-net.json",Kv="~/.cc-safety-net/config.json";async function Lu(P,O){let D=L(P,{cwd:O.cwd});if(D)console.log(`Skipped the project scope: ${_(O.cwd)} is the user rule config, not a project rule config`);return[D||await Ou(P,{legacyPath:wa({cwd:O.cwd}),configPath:_(O.cwd),defaultRulebookName:"project-rules",migratedFrom:Jv,cleanup:O.cleanup,syncOptions:{cwd:O.cwd}}),await Ou(P,{legacyPath:Ct(P),configPath:W(P),defaultRulebookName:"user-rules",migratedFrom:Kv,cleanup:O.cleanup,syncOptions:{cwd:O.cwd,global:!0}})].every((J)=>J)?0:1}async function Ou(P,O){let D=kn(P,O.syncOptions),j=i(D.filesystemScope,O.legacyPath),J=r(j);if(J===null)return console.log(`No legacy config found at ${O.legacyPath}`),!0;let Y=zv(J);if(!Y.ok){for(let Ie of Y.errors)console.error(Ie);return!1}let re=m(D.configTarget);if(re.errors.length>0){for(let Ie of re.errors)console.error(Ie);return!1}let ie=re.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},de=Yv($u(O.configPath),ie.rules,O.defaultRulebookName,O.migratedFrom,D.filesystemScope),fe=ko($u(O.configPath),de,"rulebook.json"),we=i(D.filesystemScope,fe),Ce=[Du(D.configTarget),Du(we)],Se=await Wv(P,O,D.configTarget,we,de,Y.config.rules,ie.rules.includes(de)?ie.rules:[...ie.rules,de],ie.overrides??{},ie.transparent_wrappers??[]);if(!Se.ok){Qv(Ce);for(let Ie of Se.errors)console.error(Ie);return!1}if(!O.cleanup)return console.log(`Migrated legacy config at ${O.legacyPath}. Legacy file is no longer used.`),!0;if(!Xv(D.configTarget,we,de,O.migratedFrom,Y.config.rules))return console.error(`Migration cleanup verification failed for ${O.legacyPath}`),!1;return H(j),console.log(`Deleted legacy config at ${O.legacyPath}`),!0}async function Wv(P,O,D,j,J,Y,re,ie,de){try{return wn(D,{version:1,rules:re,overrides:ie,transparent_wrappers:de}),wn(j,Zv(J,O.migratedFrom,Y)),await wo(P,O.syncOptions)}catch(fe){return{ok:!1,errors:[fe instanceof Error?fe.message:String(fe)]}}}function zv(P){try{let O=JSON.parse(P),D=Io(O);if(D.errors.length>0)return{ok:!1,errors:D.errors};return{ok:!0,config:{version:1,rules:O.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function Yv(P,O,D,j,J){let Y=O.find((re)=>eb(i(J,ko(P,re,"rulebook.json")))===j);if(Y)return Y;if(r(i(J,ko(P,D,"rulebook.json")))===null)return D;for(let re=2;;re++){let ie=`${D}-${re}`;if(r(i(J,ko(P,ie,"rulebook.json")))===null)return ie}}function Zv(P,O,D){return{rulebook_version:1,name:P,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:O,allowed_commands:[...new Set(D.map((j)=>j.command))],rules:D,tests:D.map((j)=>({command:[j.command,j.subcommand,j.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:j.name}))}}function Xv(P,O,D,j,J){if(!m(P).config?.rules.includes(D))return!1;try{let re=r(O);if(re===null)return!1;let ie=JSON.parse(re);return ie.migrated_from===j&&JSON.stringify(ie.rules)===JSON.stringify(J)}catch{return!1}}function Du(P){return{target:P,content:r(P)}}function Qv(P){for(let O of P){if(O.content===null){H(O.target);continue}g(O.target,O.content)}}function eb(P){let O=r(P);if(O===null)return null;try{let D=JSON.parse(O);return typeof D.migrated_from==="string"?D.migrated_from:null}catch{return null}}import{mkdir as nb,readFile as tb,writeFile as rb}from"node:fs/promises";import{dirname as ob,join as ib}from"node:path";var sb=86400000,ab=604800000;async function ju(P,O=Date.now()){if(P.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let D=We(P);if(!D)return null;let j=ib(D,".cc-safety-net","update-check.json"),J=await lb(j,O);if(!J.lastCheck||O-J.lastCheck>sb){let ie=await Gn();if(J.lastCheck=O,ie.latestVersion)J.latestVersion=ie.latestVersion;if(!await Nu(j,J))return null;if(ie.error)return null}let Y=J.latestVersion,re=pn();if(!Y||!jo(Y,re))return null;if(J.notifiedVersion===Y&&J.notifiedAt!==void 0&&O-J.notifiedAt<ab)return null;if(J.notifiedVersion=Y,J.notifiedAt=O,!await Nu(j,J))return null;return`UPDATE_AVAILABLE: cc-safety-net v${Y} is available (running v${re}). 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 lb(P,O){let D=await tb(P,"utf8").then((Y)=>JSON.parse(Y)).catch(()=>{return});if(!D||typeof D!=="object"||Array.isArray(D))return{};let j=D,J=(Y)=>typeof Y==="number"&&Number.isFinite(Y)&&Y<=O?Y:void 0;return{lastCheck:J(j.lastCheck),latestVersion:typeof j.latestVersion==="string"?j.latestVersion:void 0,notifiedVersion:typeof j.notifiedVersion==="string"?j.notifiedVersion:void 0,notifiedAt:J(j.notifiedAt)}}async function Nu(P,O){return nb(ob(P),{recursive:!0,mode:448}).then(()=>rb(P,JSON.stringify(O),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as cb,resolve as fs}from"node:path";var Fu="CC Safety Net Config",db="═".repeat(Fu.length),ub="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",pb=new Set(["rule.json","rule.lock","cache"]);function Hu(P,O={}){try{return fb(P,O)}catch(D){if(D instanceof o)return console.error(D.message),1;throw D}}function fb(P,O){let D=O.cwd??process.cwd(),j=X(P,{cwd:D}),J=Ct(P),Y=wr(D),re=fs(D,he),ie=i(j.userScope,J),de=i(j.projectScope,Y),fe=!1,we=!1,Ce=[],Se=[],Ie=mb(i(j.projectScope,re));if(yb(),r(j.userConfigTarget)!==null){let Ee=Un(j.userConfigTarget);if(Ee.errors.push(...B(j.userConfigPath,j.userScope)),Ce.push({scope:"User",path:j.userConfigPath,result:Ee,schema:"rules",target:j.userConfigTarget}),Ee.errors.length>0)fe=!0}if(r(ie)!==null)if(we=!0,r(j.userConfigTarget)!==null)Se.push(xo("user","cleanup"));else{let Ee=$o(ie);if(Ce.push({scope:"User",path:J,result:Ee,schema:"legacy",inactive:!0,target:ie}),Se.push(xo("user",Ee.errors.length>0?"fix-or-delete":"migrate")),Ee.errors.length>0)fe=!0}if(r(j.projectConfigTarget)!==null){let Ee=Un(j.projectConfigTarget);if(Ee.errors.push(...B(j.projectConfigPath,j.projectScope)),Ce.push({scope:"Project",path:fs(j.projectConfigPath),result:Ee,schema:"rules",target:j.projectConfigTarget}),Ee.errors.length>0)fe=!0;if(r(de)!==null)we=!0,Se.push(xo("project","cleanup"))}else if(r(de)!==null){we=!0,fe=!0;let Ee=$o(de);Ce.push({scope:"Project",path:fs(Y),result:Ee,schema:"legacy",inactive:!0,target:de}),Se.push(xo("project",Ee.errors.length>0?"fix-or-delete":"migrate"))}if(Ie?.result.errors.length)fe=!0;if(Ce.length===0&&!Ie)return console.log(`
279
- No config files found. Using built-in rules only.`),0;for(let Ee of Ce)if(Ee.inactive)vb(Ee.scope,Ee.path,Ee.result);else if(Ee.result.errors.length>0)bb(Ee.scope,Ee.path,Ee.result.errors);else{if(Ee.schema==="rules"&&xb(Ee.target))console.log(`
280
- Added $schema to ${Ee.scope.toLowerCase()} config.`);hb(Ee.scope,Ee.path,Ee.result,Ee.schema)}for(let Ee of Se)console.error(`
281
- ${nn.red(Ee)}`);if(Ie)if(Ie.result.errors.length>0)kb(Ie.path,Ie.result.errors);else wb(Ie.path,Ie.result);if(fe)return console.error(`
282
- Config validation failed.`),1;return console.log(we?`
268
+ `)}function gu(_,N){return N.map((j)=>_==="install"&&j.target==="kimi-code"&&j.unavailableReason==="already installed"?{...j,available:!0,unavailableReason:void 0,label:`${j.label} (global hook installed)`}:j)}function ab(_,N){if(_.selectKimiInstallMethod)return _.selectKimiInstallMethod();if(!ms(_.input,_.output))return Promise.resolve("global-hook");return bd({input:_.input,output:_.output,globalHookInstalled:Su(N)})}async function Pu(_,N,j,J=!1,Y){let re=rb[N];if(_==="install")re?.beforeInstall?.(j,J);if(_==="uninstall")re?.beforeUninstall?.(j);if(ob(N))return[nb(_,N,j,J),_==="uninstall"?await re?.afterUninstall?.(j):void 0].filter(Boolean).join(`
269
+ `);if(ib(N))return tb(_,N,j,J);if(_==="uninstall")return N==="opencode"?eb(j):Qv(N,j);return[await Xv(N,j,J,Y),await re?.afterInstall?.(j)].filter(Boolean).join(`
270
+ `)}function lb(_){let N=mn({label:"update"},_).errors[0];if(N)throw Error(N)}async function cb(_,N=Nt){let j=await wu(_,N),J=So(tr(_),"installed-plugins");return{targets:ws([...j.hooks.filter((re)=>re.platform!=="copilot-cli"&&re.detected&&re.method!==eo&&re.method!==hi).map((re)=>re.platform),...[Jr,yl,gl].flatMap((re)=>Po(So(J,...re))?["copilot-cli"]:[]),...Kr(_,Rs)?["claude-code"]:[],...Es(j.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:j.codexPluginListOutput,kimiPlugin:j.hooks.some(xu)}}async function db(_){let N=c(),j=_.output??process.stdout,J=(_.scriptPath??process.argv[1]??"").split(/[\\/]/),Y=J.find((Ee)=>/^bunx-\d+-/.test(Ee)),re=Y!==void 0||J.includes("_npx")?null:(_.checkLatestVersion??Gn)(),ie=async()=>{let Ee=re&&await re;if(Ee?.updateAvailable)j.write(`
271
+ Update available: cc-safety-net ${Ee.currentVersion} → ${Ee.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
272
+ `)},de=cb(N,_.fetchVersion??Nt).then(async(Ee)=>{let De=new Set(Ee.targets);return{targets:Ee.targets,codexPluginListOutput:Ee.codexPluginListOutput,kimiPlugin:Ee.kimiPlugin,available:new Map(await Promise.all(On.filter((He)=>De.has(He.target)&&uu.has(He.target)).map(async(He)=>[He.target,await gr(He.probeCommand)])))}}),fe=await Xt(_.showBanner??!0,()=>({ready:de,finish:()=>de}),()=>Zt({input:_.input??process.stdin,output:j}),{loadingMessage:"Checking installed integrations…",output:j}),we=await Promise.resolve().then(()=>(Zd(N.tmpdir,process.platform,Y),null)).catch((Ee)=>hr(Ee));if(fe.targets.length===0){if(j.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),we!==null)console.error(we);return await ie(),we===null?0:1}let ke=fe.targets.some((Ee)=>pu.has(Ee))?await Promise.resolve().then(()=>(xo(N),null)).catch((Ee)=>hr(Ee)):null,Re=await Hr(Promise.all(fe.targets.map((Ee)=>{if(Ee==="kimi-code"&&fe.kimiPlugin)return Promise.resolve({message:"Kimi Code plugin skipped: update it in Kimi Code from /plugins (Installed tab, select cc-safety-net, press Enter)",failed:!1});if(uu.has(Ee)&&!fe.available.get(Ee))return Promise.resolve({message:`${cn(Ee)} not found; skipped`,failed:!1});if(ke!==null&&pu.has(Ee))return Promise.resolve({message:ke,failed:!0});return Pu("install",Ee,N,!0,fe.codexPluginListOutput).then((De)=>({message:De,failed:!1}),(De)=>({message:hr(De),failed:!0}))})),{loadingMessage:`Updating ${fe.targets.length} integration${fe.targets.length===1?"":"s"}…`,output:j}),Te=we===null?Re:[...Re,{message:we,failed:!0}];return Te.forEach((Ee)=>Ee.failed?console.error(Ee.message):j.write(`${Ee.message}
273
+ `)),await ie(),Te.some((Ee)=>Ee.failed)?1:0}function _s(_,N={}){return Promise.resolve().then(()=>lb(_)).then(()=>db(N)).catch((j)=>(console.error(hr(j)),1))}async function vr(_,N,j={}){try{let J=c(),Y=await Xt(!0,()=>Zv(J,_,N,j),()=>Zt({input:j.input??process.stdin,output:j.output??process.stdout}),{loadingMessage:_==="install"?"Checking available integrations…":"Checking installed integrations…",output:j.output??process.stdout});if(!Y)return(j.output??process.stdout).write(`Cancelled: nothing was ${_}ed.
274
+ `),0;if(Y==="update")return(j.runUpdate??(()=>_s([],{fetchVersion:j.fetchVersion,input:j.input,output:j.output,showBanner:!1})))();let re=j.output??process.stdout;return await jd(Y,async(ie)=>{if(ie==="kimi-code"&&_==="install"){let fe=await ab(j,J);if(fe===null){re.write(`Cancelled: Kimi Code integration was not installed.
275
+ `);return}if(fe==="plugin"){re.write(`${sb(J)}
276
+ `);return}}let de=await Hr(Pu(_,ie,J),{loadingMessage:`${_==="install"?"Installing":"Uninstalling"} ${cn(ie)} integration…`,output:re});re.write(`${de}
277
+ `)}),0}catch(J){return console.error(hr(J)),1}}function hr(_){let N=_ instanceof Error?_.message:String(_),j=typeof _==="object"&&_!==null&&"code"in _?_.code:null;if(j==="EACCES"||j==="EPERM")return`${N}
278
+ Check file permissions for the target config file and parent directory.`;if(j==="ENOENT")return`${N}
279
+ Check that the target config path and parent directory exist.`;if(j==="ENOTDIR")return`${N}
280
+ Check that every parent path component is a directory.`;return N}import{mkdirSync as yb}from"node:fs";import{dirname as hb}from"node:path";import{createInterface as vb}from"node:readline";import{existsSync as Eu,readFileSync as ub}from"node:fs";function It(_,N){let j=pt(_,N);return{policy:j.policy,errors:ce(lt(j.issues,dt,(J)=>J.kind==="custom")," "," ")}}function br(_,N){return It(_,N).errors}function Ru(_,N){return{"safety.level":_.safety.level,...Ts("safety.overrides",_.safety.overrides),"workflow.worktree_mode":String(_.workflow.worktree_mode),"destructive_command_protection.enabled":String(_.destructive_command_protection.enabled),...Ts("destructive_command_protection.overrides",_.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":As(_.destructive_command_protection.allow_paths),"secret_protection.enabled":String(_.secret_protection.enabled),...Ts("secret_protection.overrides",_.secret_protection.overrides),"secret_protection.deny_paths":As(_.secret_protection.deny_paths),"secret_protection.allow_paths":As(_.secret_protection.allow_paths),...N?{"audit.retention_days":String(_.audit.retention_days)}:{}}}function Ro(_,N,j){let J=Ru(_,j),Y=Ru(N,j);return[...new Set([...Object.keys(J),...Object.keys(Y)])].flatMap((re)=>J[re]===Y[re]?[]:[{field:re,before:J[re],after:Y[re]}])}function wr(_,N){let j=u(_,N);if(!Eu(j))return{baseline:k(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,_.home),diagnostics:[]};let J=Ot(j),Y=It(J.value,_.home);return{baseline:Y.policy,diagnostics:J.errors.length>0?J.errors:Y.errors}}function Ot(_){if(!Eu(_))return{errors:[`${_}: file not found`]};try{return{value:JSON.parse(ub(_,"utf-8")),errors:[]}}catch(N){let j=N instanceof Error?N.message:String(N);return{errors:[`${_}: ${N instanceof SyntaxError?`Invalid JSON: ${j}`:j}`]}}}function Eo(_,N){let j=pb(_)?_:{};return{version:N.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((J)=>j[J]!==void 0).map((J)=>[J,j[J]]))}}function Ts(_,N){return Object.fromEntries(Object.entries(N).flatMap(([j,J])=>J===void 0?[]:[[`${_}.${j}`,String(J)]]))}function As(_){return _.length===0?"(none)":_.join(", ")}function pb(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}import{chmodSync as fb,existsSync as _u,mkdirSync as mb,readFileSync as Tu}from"node:fs";import{dirname as gb}from"node:path";function Au(_,N={}){let j=u(_,N);if(!_u(j))return{path:j,exists:!1,raw:"",policy:F(),errors:[]};let J=Tu(j,"utf-8");if(!J.trim())return{path:j,exists:!0,raw:J,policy:F(),errors:["Config file is empty"]};try{let Y=It(JSON.parse(J),_.home);return{path:j,exists:!0,raw:J,policy:Y.policy,errors:Y.errors}}catch(Y){return{path:j,exists:!0,raw:J,policy:F(),errors:[`Invalid JSON: ${Y instanceof Error?Y.message:String(Y)}`]}}}function Fn(_,N,j={}){let J=u(_,j),Y=It(N,_.home);if(Y.errors.length>0)return{path:J,policy:F(),errors:Y.errors};let re=Y.policy;return mb(gb(J),{recursive:!0,mode:448}),g(se(J),`${JSON.stringify(re,null,2)}
281
+ `,384),fb(J,384),{path:J,policy:re,errors:[]}}function Iu(_,N){let j=It(N,_.home);if(j.errors.length>0)return{errors:j.errors};return{preview:Ge(j.policy,_.env),errors:[]}}function Ou(_,N={}){let j=u(_,N);if(!_u(j))return Fn(_,te,N);let J=Tu(j,"utf-8");if(!J.trim())return Fn(_,te,N);try{return Fn(_,k(JSON.parse(J),_.home),N)}catch{return Fn(_,te,N)}}var $u=new Set(["check","apply"]),Du="(unset)";async function Nu(_,N,j={}){let J=mn({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},N),Y=J.positionals[0],re=[...J.errors,...Y&&!$u.has(Y)?[`Unknown policy subcommand: ${Y}`]:[],...Y&&$u.has(Y)&&!J.positionals[1]?[`policy ${Y} requires a file`]:[],...J.positionals.slice(2).map((He)=>`Unexpected policy argument: ${He}`)];if(re.length>0){for(let He of re)console.error(He);return 1}let ie=J.positionals[1];if(!Y||!ie)return Kt(Er,console.error),1;let de=j.cwd??process.cwd(),fe=J.flags.global?u(_):h(de);if(!J.flags.global&&A(_,{cwd:de}))return console.error(`${fe} is the user policy, not a project policy; use --global for the user scope, or run from a project directory`),1;let we=Ot(ie),ke=[...we.errors,...br(we.value,_.home).map((He)=>`${ie}: ${He}`),...!J.flags.global&&kb(we.value)&&we.value.audit!==void 0?[`${ie}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(ke.length>0){for(let He of ke)console.error(He);return 1}let Re=k(we.value,_.home);if(console.log(`Scope: ${J.flags.global?"user":"project"} (${fe})`),console.log(`Proposal: ${ie}`),J.flags.global)Lu(k(Ot(fe).value,_.home),Re,!0);if(!J.flags.global){let He=wr(_).baseline;console.log("Effective policy (user + project merged):"),Lu(ee(He,ue(Ot(fe).value,_.home).policy).policy,ee(He,ue(we.value,_.home).policy).policy,!1)}if(Y==="check")return 0;let Te=j.input??process.stdin,Ee=j.output??process.stdout;if(!Te.isTTY||!Ee.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${ie}${J.flags.global?" --global":""}`),1;if(!await bb(`Apply this policy to ${fe}? [y/N] `,Te,Ee))return console.log("Cancelled; nothing was written."),0;return wb(_,fe,we.value,Re,J.flags.global),console.log(`Policy applied: ${fe}`),0}function bb(_,N,j){let J=vb({input:N,output:j,terminal:!1});return new Promise((Y)=>{J.once("close",()=>Y(!1)),J.question(_,(re)=>{Y(/^y(es)?$/i.test(re.trim())),J.close()})})}function wb(_,N,j,J,Y){if(Y){Fn(_,J);return}yb(hb(N),{recursive:!0}),bn(N,Eo(j,J))}function Lu(_,N,j){let J=Ro(_,N,j);if(J.length===0){console.log("No changes.");return}console.log(`Changes (${J.length}):`);for(let Y of J)console.log(` ${Y.field}: ${Y.before??Du} -> ${Y.after??Du}`)}function kb(_){return!!_&&typeof _==="object"&&!Array.isArray(_)}import{join as jw}from"node:path";var ju="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- `caffeinate`, `exec`, `nice`, `nohup`, `setsid`, `stdbuf`, `time`, and `timeout` are built-in transparent wrappers and need no configuration. Configure only other wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n- `command_tools`: Optional array of shell tools that a plugin adds to an agent and that CC Safety Net does not know. Each entry is a tool name such as `\"ops_bash\"`, or `{ \"name\": \"ops_run_background\", \"cwd\": \"cwd\" }` when the tool takes its working directory in a named argument (otherwise `workdir`, `cwd`, or `working_directory` is read). A call to a declared tool with a non-empty string `command` is analyzed like a built-in shell command. User and project lists merge; the user entry wins a name declared in both.\n- Built-in shell and file tools are already analyzed and cannot be declared; `rule verify` reports one declared by hand.\n- Use `cc-safety-net rule tool add ops_bash ops_run_background` to declare tools in the user config, or add `--project` for the project config.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function _o(_,N){if(!_.ok){Bu(_);return}Mu(_,N)}function Fu(_,N,j){if(_.ok)console.log(j);if(!_.add){_o(_,`Added rulebook source: ${N}`);return}if(!_.ok){Bu(_);return}if(_.add.added.length>0)console.log(`Added ${_.add.added.length} ${_.add.added.length===1?"rulebook":"rulebooks"} from ${_.add.source} at ${_.add.ref}:`),_.add.added.forEach((J)=>{console.log(` - ${J}`)});if(_.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${_.add.source} at ${_.add.ref}: ${_.add.alreadyConfigured.join(", ")}`);if(_.add.commits.length>0)console.log(`Vendored at ${_.add.commits.map((J)=>J.slice(0,7)).join(", ")}.`);Mu(_,"Rule config updated.")}function Mu(_,N){for(let j of _.changes??[])console.log(j);console.log(N),console.log(""),Cb(_.entries)}function Cb(_){if(_.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${_.length}):`);for(let N of _)console.log(` - ${N.name} ${N.version} (${xb(N.ruleCount)})`),console.log(` Source: ${N.spec}`)}function xb(_){return`${_} ${_===1?"rule":"rules"}`}function Uu(_){Wn("Active sources",_.rulebooks,(N)=>[`[${N.source}] ${N.name} ${N.version}`,` Source: ${N.spec}`]),Wn("Active rules",_.rules,(N)=>[`[${Pb(_,N.name)}] ${N.name}`,...Sb(N),` Reason: ${N.reason}`]),Wn("Disabled rules",Hu(_,"off"),(N)=>[N.key]),Wn("Reason overrides",Hu(_,"reason"),(N)=>[N.key,` Reason: ${N.value.reason}`]),Wn("Transparent wrappers",_.transparent_wrappers,(N)=>[N]),Wn("Issues",_.errors,(N)=>[N]),Wn("Warnings",_.warnings,(N)=>[N])}function Gu(_){Wn("Command tools",_,(N)=>typeof N.tool==="string"?[`[${N.scope}] ${N.tool}`]:[`[${N.scope}] ${N.tool.name}`,...N.tool.cwd===void 0?[]:[` Cwd argument: ${N.tool.cwd}`]])}function Wn(_,N,j){if(N.length===0){console.log(`${_}: (none)`);return}console.log(`${_} (${N.length}):`);for(let J of N){let[Y,...re]=j(J);console.log(` - ${Y}`);for(let ie of re)console.log(` ${ie}`)}}function Sb(_){if(!_.match)return[` Command: ${_.subcommand?`${_.command} ${_.subcommand}`:_.command}`,` Block args: ${_.block_args.join(", ")}`];return[` Command: ${[_.command,..._.match.command_path].join(" ")}`,..._.match.any_args?[` Any args: ${_.match.any_args.join(", ")}`]:[],..._.match.exclude_args?[` Exclude args: ${_.match.exclude_args.join(", ")}`]:[]]}function Pb(_,N){return _.rulebooks.find((j)=>j.rules.includes(N))?.source??"project"}function Hu(_,N){return Object.entries({..._.userConfig?.overrides,..._.projectConfig?.overrides}).filter((j)=>{if(N==="off")return j[1]==="off";return!!j[1]&&typeof j[1]==="object"}).map(([j,J])=>({key:j,value:J}))}function Bu(_){for(let N of _.errors)console.error(N)}import{dirname as pp,join as No}from"node:path";import{join as Ds,resolve as jb}from"node:path";function kr(_){let N=d(_);if(N.errors.length>0)return{ok:!1,result:{ok:!1,errors:N.errors,entries:[]}};return{ok:!0,config:N.config??Et}}function qu(_){bn(_,{version:1,rules:[],overrides:{},transparent_wrappers:[]})}function Vu(_){bn(_,{rulebook_version:1,name:"example-rules",version:"1.0.0",description:"Project-specific CC Safety Net rules.",author:"project",allowed_commands:["docker"],rules:[{name:"block-docker-system-prune",command:"docker",subcommand:"system",block_args:["prune"],reason:"Use targeted cleanup instead."}],tests:[{command:"docker system prune",expect:"blocked",rule:"block-docker-system-prune"}]})}import{dirname as Oo}from"node:path";var Rb="custom.";function To(_){if(_.rulebook_version!==2)return[];let N=_.rules.map((j)=>({name:j.name,command:j.command,block_args:[],match:j.match,reason:j.reason,intent:j.intent}));return(_.tests??[]).flatMap((j,J)=>{let Y=Is(y(j.command));if(Y.length===0)return[`tests[${J}]: could not parse fixture command: ${j.command}`];let re=Y.reduce((ie,de)=>ie??D(de,N)?.id.slice(Rb.length),void 0);if(j.expect==="blocked"){if(re===j.rule)return[];let ie=re?`"${re}" matched first`:"no rule matched";return[`tests[${J}]: expected "${j.rule}" to block "${j.command}" but ${ie}`]}return re?[`tests[${J}]: expected "${j.command}" to be allowed but "${re}" matched`]:[]})}function Is(_){return _.nodes.flatMap((N)=>{if(N.kind==="group"||N.kind==="function")return Is(N.body);if(N.kind!=="command")return[];let j=Se(ne(N.dialect,N.words)).words.map(t);return[...j.length>0?[j]:[],...N.nested.flatMap((J)=>Is(J))]})}var Ao=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function Io(_={}){return{requests:0,responseBytes:0,maxRequests:_.maxRequests??Ao.maxRequests,maxResponseBytes:_.maxResponseBytes??Ao.maxResponseBytes}}function Mn(_){return{controller:new AbortController,budget:Io(),resolveUrl:_}}function Ku(_){return _ instanceof Error&&_.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Ju(_){if(_.requests>=_.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");_.requests++}function Wu(_,N){if(N>_.maxResponseBytes-_.responseBytes)throw _.responseBytes+=N,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");_.responseBytes+=N}var Zu=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function zu(_,N,j=w(Oo(Oo(N)),"rules policy"),J=Mn()){if(C(_))return Ab(_,J);return Tb(_,N,j)}async function Xu(_,N,j,J,Y,re){if(!C(_))return zu(_,N,j,J);let ie=Y?null:Eb(_,N,j);if(ie)return ie;if(!Y&&!re)throw Error(`${_} is not vendored; run rule update ${_} to vendor it`);return zu(_,N,j,J)}function Eb(_,N,j=w(Oo(Oo(N)),"rules policy")){let J=L(_),Y=M(N,J.name),re=r(i(j,Y));if(re===null)return null;let ie=le(Os(re,`Invalid rulebook ${Y}.`));if(ie.name!==J.name)throw Error(`rulebook name "${ie.name}" in ${Y} must match "${J.name}"`);return{spec:_,rulebook:ie,content:re}}async function Qu(_,N={}){if(!Z(_))throw Error(`Invalid GitHub repository source: ${_}`);let[j,J]=_.split("/");if(!j||!J)throw Error(`Invalid GitHub repository source: ${_}`);if(N.ref!==void 0&&!ae(N.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${N.ref}`);let Y=N.operation??Mn(),re=N.ref??await _b(j,J,_,Y),ie=await np(j,J,re,_,Y),de=await $o(`https://api.github.com/repos/${j}/${J}/git/trees/${ie}?recursive=1`,"tree",Y),fe=de.response;if(!fe.ok)throw Error(`Failed to inspect ${_}: GitHub tree returned ${fe.status}`);let we=JSON.parse(de.content);if(!Array.isArray(we?.tree))throw Error(`Failed to inspect ${_}: unexpected GitHub tree response`);let ke=we.tree,Re=[...new Set(ke.flatMap((Te)=>{if(!Te||typeof Te!=="object")return[];let Ee=Te;if(Ee.type!=="blob"||typeof Ee.path!=="string")return[];let De=Ee.path.match(wt);return De?.[1]?[De[1]]:[]}))].sort();if(Re.length===0)throw Error(`No rulebooks found in ${_} under ${he}/`);return{source:_,owner:j,repo:J,ref:re,commit:ie,names:Re}}async function _b(_,N,j,J){let Y=await $o(`https://api.github.com/repos/${_}/${N}`,"metadata",J),re=Y.response;if(!re.ok)throw Error(`Failed to inspect ${j}: GitHub returned ${re.status}`);let de=JSON.parse(Y.content)?.default_branch;if(typeof de!=="string"||de==="")throw Error(`Failed to inspect ${j}: missing default branch`);if(!ae(de))throw Error(`GitHub returned an invalid default branch: ${de}`);return de}function Tb(_,N,j){Ct(_);let J=M(N,_),Y=r(i(j,J));if(Y===null)throw Error(`Rulebook source not found: ${_}`);let re=ep(Os(Y,"Invalid local rulebook source."));if(re.name!==_)throw Error(`rulebook name "${re.name}" must match local source "${_}"`);return{spec:_,rulebook:re,content:Y}}async function Ab(_,N){let j=L(_),J=await np(j.owner,j.repo,j.ref,_,N),Y=await $o(`https://raw.githubusercontent.com/${j.owner}/${j.repo}/${J}/${j.path}`,"raw",N),re=Y.response;if(!re.ok)throw Error(`Failed to fetch ${_}: GitHub raw returned ${re.status}`);let ie=Y.content,de=ep(Os(ie,"Invalid GitHub rulebook response."));if(de.name!==j.name)throw Error(`rulebook name "${de.name}" must match GitHub source "${j.name}"`);return{spec:_,rulebook:de,content:ie}}function ep(_){let N=le(_),j=To(N);if(j.length>0)throw Error(j.join("; "));return N}function Os(_,N){try{return JSON.parse(_)}catch{throw Error(N)}}async function np(_,N,j,J,Y){let re=await $o(`https://api.github.com/repos/${_}/${N}/commits/${encodeURIComponent(j)}`,"commit",Y),ie=re.response;if(!ie.ok)throw Error(`Failed to resolve ${J}: GitHub returned ${ie.status}`);let de=JSON.parse(re.content);if(typeof de?.sha!=="string"||de.sha==="")throw Error(`Failed to resolve commit for ${J}`);return de.sha}async function Ib(_,N,j={}){if(j.signal?.aborted)throw j.signal.reason;let J=j.budget??Io(),Y=new AbortController,re=()=>Y.abort(j.signal?.reason);j.signal?.addEventListener("abort",re,{once:!0});let ie=!1,de=setTimeout(()=>{if(Y.signal.aborted)return;ie=!0,Y.abort()},j.timeoutMs??Zu.timeoutMs);try{if(j.signal?.aborted)throw j.signal.reason;Ju(J);let fe=await fetch(_,{signal:Y.signal,redirect:"error"});if(!fe.ok)return tp(fe),{response:fe,content:""};return{response:fe,content:await Ob(fe,N,J,()=>Y.abort())}}catch(fe){if(ie)throw Error("GitHub request timed out",{cause:fe});if(j.signal?.aborted)throw j.signal.reason;throw fe}finally{clearTimeout(de),j.signal?.removeEventListener("abort",re)}}function $o(_,N,j){return Ib(j.resolveUrl?.(_)??_,N,{budget:j.budget,signal:j.controller.signal})}async function Ob(_,N,j=Io(),J){let Y=Zu[`${N}Bytes`],re=Number(_.headers.get("content-length"));if(Number.isFinite(re)&&re>Y)throw tp(_),Error(`GitHub ${N} response exceeds ${Y} bytes`);if(!_.body)return"";let ie=_.body.getReader(),de=[],fe=0;while(!0){let we=await ie.read();if(we.done)break;try{Wu(j,we.value.byteLength)}catch(ke){throw J?.(),Yu(ie),ke}if(fe+=we.value.byteLength,fe>Y)throw J?.(),Yu(ie),Error(`GitHub ${N} response exceeds ${Y} bytes`);de.push(Buffer.from(we.value))}return Buffer.concat(de,fe).toString("utf-8")}function tp(_){if(!_.body)return;rp(()=>_.body?.cancel())}function Yu(_){rp(()=>_.cancel())}function rp(_){try{Promise.resolve(_()).catch(()=>{})}catch{}}var $b=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function op(_,N){let j=ap(_.rules,N);if(j.length>0)return{ok:!0,specs:j};return sp(_.rules,N)}function ip(_,N){let j=ap(_,N);if(j.length>0)return{ok:!0,specs:j};let J=Lb(_,N);if(J.length>0)return{ok:!0,specs:J};let Y=Nb(_,N);if(!Y.ok)return Y;if(Y.specs.length>0)return{ok:!0,specs:Y.specs};return sp(_,N)}function sp(_,N){let j=_.filter((J)=>$s(J)?.name===N);if(j.length===1)return{ok:!0,specs:j};return Db(N,j)}function Db(_,N){return{ok:!1,result:{ok:!1,errors:N.length===0?[`No configured rulebook matches ${_}`]:[`Ambiguous rulebook match ${_}: ${N.join(", ")}`],entries:[]}}}function ap(_,N){return _.filter((j)=>j===N)}function Lb(_,N){let j=N.match($b),J=j?.[1],Y=j?.[2],re=j?.[3];if(!J||!Y||!re||!ae(re))return[];return lp(_,(ie)=>ie.owner===J&&ie.repo===Y&&ie.ref===re)}function Nb(_,N){if(!Z(N))return{ok:!0,specs:[]};let[j,J]=N.split("/"),Y=lp(_,(ie)=>ie.owner===j&&ie.repo===J);if(new Set(Y.map((ie)=>$s(ie)?.ref).filter((ie)=>!!ie)).size<2)return{ok:!0,specs:Y};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${N}. Use an explicit ref:`,` cc-safety-net rule remove ${N}#<ref>`],entries:[]}}}function $s(_){try{return L(_)}catch{return null}}function lp(_,N){return _.filter((j)=>{let J=$s(j);return J?N(J):!1})}async function Lo(_,N={}){let j=Ls(N);return Hb(_,j,await Do(_,j,Mn()))}function Hb(_,N,j){if(!j.ok)return j;let J=hn(_,N),Y=[...new Set(B(J.configPath,J.filesystemScope))];if(Y.length===0)return j;return{ok:!1,errors:Y,entries:j.entries}}async function Do(_,N,j,J={},Y=new Set,re=new Set){try{let ie=hn(_,N),de=kr(ie.configTarget);if(!de.ok)return de.result;let fe=de.config,we=N.only?op(fe,N.only):{ok:!0,specs:fe.rules};if(!we.ok)return we.result;let ke=new Set([...N.refresh?we.specs:[],...Y]),Re=(nn)=>Xu(nn,ie.configDir,ie.filesystemScope,j,ke.has(nn),!N.refresh||ke.has(nn)),Te=await zb(fe.rules,N.refresh?(nn)=>Re(nn).then((an)=>({ok:!0,item:an})).catch((an)=>{if(Ku(an))throw an;return{ok:!1,spec:nn,message:an instanceof Error?an.message:String(an)}}):async(nn)=>({ok:!0,item:await Re(nn)}),j),Ee=Te.filter((nn)=>!nn.ok),De=Te.filter((nn)=>nn.ok).map((nn)=>nn.item),He=De.flatMap((nn)=>Fb(nn,fe.rules)),Le=De.flatMap((nn)=>Mb(nn,re,ie)),Ye=new Set([...He,...Le].map((nn)=>nn.spec)),tn=[...Ee,...He,...Le],rn=[],sn=Gb(rn,()=>De.flatMap((nn)=>Ye.has(nn.spec)||tn.length>0&&re.has(nn.spec)?[]:Ub(nn,ie,J,rn)));return{ok:tn.length===0,errors:tn.map((nn)=>`Failed to update ${nn.spec}: ${nn.message}`),entries:De.map(qb),changes:sn}}catch(ie){return xr(ie)}}function Fb(_,N){if(!C(_.spec))return[];let j=Ue(_.spec),J=N.filter((Y)=>Y!==_.spec&&Ue(Y).toLowerCase()===j.toLowerCase());if(J.length===0)return[];return[{ok:!1,spec:_.spec,message:`rulebook name "${j}" is also claimed by ${J.join(", ")}; rename one of them`}]}function Mb(_,N,j){if(!N.has(_.spec)||!C(_.spec))return[];let J=M(j.configDir,_.rulebook.name),Y=r(i(j.filesystemScope,J));if(Y===null||Y===_.content)return[];return[{ok:!1,spec:_.spec,message:`${J} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Ub(_,N,j,J){if(!C(_.spec))return[];let Y=M(N.configDir,_.rulebook.name),re=i(N.filesystemScope,Y),ie=r(re);if(ie===_.content)return[];return J?.push({target:re,previous:ie}),g(re,_.content,void 0,j._testAfterPolicyRename),Bb(_,ie)}function Gb(_,N){try{return N()}catch(j){for(let J of[..._].reverse()){if(J.previous===null){H(J.target);continue}g(J.target,J.previous)}throw j}}function Bb(_,N){if(N===null)return[`Vendored ${_.spec} (${_.rulebook.version})`];let j=ve(N),J="problem"in j?null:j.rulebook,Y=new Map(J?.rules.map((ie)=>[ie.name,JSON.stringify(ie)])??[]),re=new Set(_.rulebook.rules.map((ie)=>ie.name));return[`Updated ${_.spec} (${J?.version??"unreadable"} -> ${_.rulebook.version})`,...[...re].filter((ie)=>!Y.has(ie)).map((ie)=>` + ${ie}`),...[...Y.keys()].filter((ie)=>!re.has(ie)).map((ie)=>` - ${ie}`),..._.rulebook.rules.filter((ie)=>{let de=Y.get(ie.name);return de!==void 0&&de!==JSON.stringify(ie)}).map((ie)=>` ~ ${ie.name}`)]}function qb(_){return{spec:_.spec,name:_.rulebook.name,version:_.rulebook.version,ruleCount:_.rulebook.rules.length}}async function cp(_,N,j={}){return Vb(_,N,Zb(j),Mn())}async function Vb(_,N,j,J,Y={}){let re=null,ie=!1;try{let de=hn(_,j),fe=r(de.configTarget);re={target:de.configTarget,content:fe};let we=kr(de.configTarget);if(!we.ok)return we.result;let ke=we.config,Re=Z(N);Kb(N,j,Re);let Te=Re?await Qu(N,{ref:j.ref,operation:J}):null,Ee=Te?Jb(Te,j.rulebooks):[],De=Te?Ee.map((rn)=>Wb(ke.rules,Te,rn)??`${N}#${Te.ref}/${rn}`):[N],He=De.filter((rn)=>!ke.rules.includes(rn)),Le=[...ke.rules,...He];if(Le.length>ye)return Yb();if(Le.length!==ke.rules.length)ie=!0,bn(de.configTarget,{...ke,rules:Le},void 0,Y._testAfterPolicyRename);let Ye=await Do(_,j,J,Y,new Set(He),new Set(He));if(!Ye.ok)Cr(de.configTarget,fe);if(!Ye.ok||!Te)return Ye;let tn=Ee.filter((rn,sn)=>He.includes(De[sn]??""));return{...Ye,add:{source:N,ref:Te.ref,selected:Ee,added:tn,alreadyConfigured:Ee.filter((rn)=>!tn.includes(rn)),commits:He.length>0?[Te.commit]:[]}}}catch(de){if(ie&&re)try{Cr(re.target,re.content)}catch(fe){return xr(fe)}return xr(de)}}function Kb(_,N,j){if(!j&&N.rulebooks!==void 0)throw Error("--only can only select rulebooks from an owner/repo source");if(!j&&N.ref)throw Error(`--ref can only select a ref for an owner/repo source: ${_}`);if(N.rulebooks?.length===0)throw Error("--only requires at least one rulebook name");let J=N.rulebooks?.filter((Y)=>!p.test(Y))??[];if(J.length>0)throw Error(`Invalid rulebook names: ${J.join(", ")}`)}function Jb(_,N){let j=N?[...new Set(N)]:_.names,J=j.filter((Y)=>!_.names.includes(Y));if(J.length>0)throw Error(`Rulebooks not found in ${_.source} at ${_.ref}: ${J.join(", ")}
282
+ Available rulebooks: ${_.names.join(", ")}`);return j}function Wb(_,N,j){let J=`${N.source}#${N.ref}/${j}`;if(_.includes(J))return J;let Y=`${N.source}#${N.commit}/${j}`;return _.find((re)=>re===Y)}async function zb(_,N,j=Mn()){if(_.length>ye)throw Error(be);let J=[],Y=0,re,ie=Array.from({length:Math.min(_.length,Ao.concurrency)},async()=>{while(!re){let de=Y;if(de>=_.length)return;Y++;try{J[de]=await N(_[de],de,j.controller.signal)}catch(fe){if(!re)re={value:fe},Y=_.length,j.controller.abort(fe);return}}});if(await Promise.all(ie),re)throw re.value;return J}function Yb(){return{ok:!1,errors:[be],entries:[]}}function Ls(_){return{cwd:_.cwd,userConfigDir:_.userConfigDir,userConfigPath:_.userConfigPath,projectConfigPath:_.projectConfigPath,global:_.global,only:_.only,refresh:_.refresh}}function Zb(_){return{...Ls(_),ref:_.ref,rulebooks:_.rulebooks}}function Xb(_){return{...Ls(_),deleteSource:_.deleteSource}}async function dp(_,N,j={}){try{return await Qb(_,N,Xb(j),{})}catch(J){return xr(J)}}async function Qb(_,N,j,J){let Y=hn(_,j),re=d(Y.configTarget);if(re.errors.length>0)return{ok:!1,errors:re.errors,entries:[]};if(!re.config)return{ok:!1,errors:[`No config found at ${Y.configPath}`],entries:[]};let ie=ip(re.config.rules,N);if(!ie.ok)return ie.result;let de=j.deleteSource?ew(Y.configDir,ie.specs,Y.filesystemScope):{ok:!0,dirs:[]};if(!de.ok)return de.result;let fe=r(Y.configTarget);if(fe===null)return xr(Error("Rules config is unavailable."));try{bn(Y.configTarget,{...re.config,rules:re.config.rules.filter((Re)=>!ie.specs.includes(Re))},void 0,J._testAfterPolicyRename)}catch(Re){throw Cr(Y.configTarget,fe),Re}let we=await Do(_,j,Mn(),J);if(!we.ok)return Cr(Y.configTarget,fe),we;let ke=nw(de.dirs,J,Y.filesystemScope);if(!ke.ok){Cr(Y.configTarget,fe);let Re=await Do(_,j,Mn(),J);if(!Re.ok)return{ok:!1,errors:[...ke.result.errors,...Re.errors],entries:Re.entries};return ke.result}return we}function ew(_,N,j){let J=N.flatMap((de)=>p.test(de)?[]:["--delete-source can only delete local rulebook sources"]),Y=N.map((de)=>Ds(_,de)),re=J.length>0?[]:Y.flatMap((de)=>up(de,j)),ie=[...J,...re];return ie.length>0?{ok:!1,result:{ok:!1,errors:ie,entries:[]}}:{ok:!0,dirs:Y}}function up(_,N){let j=jb(_),J=i(N,j),Y=me(J);if(!Y)return[`Local rulebook source directory not found: ${_}`];let re=Y.find((ie)=>ie.name==="rulebook.json");if(!re)return[`Local rulebook source directory is missing rulebook.json: ${_}`];if(re.kind!=="file")throw new o(N.label);if(r(i(N,Ds(j,"rulebook.json"))),Y.length>1)return[`Local rulebook source directory contains extra files: ${_}. delete manually if you really want to remove the directory.`];return[]}function nw(_,N,j){let J=_.flatMap((Y)=>{try{if(!me(i(j,Y)))return[];let re=up(Y,j);if(re.length>0)return re;return tw(Y,N,j),[]}catch(re){return[`Failed to delete local rulebook source ${Y}: ${re instanceof Error?re.message:String(re)}`]}});return J.length>0?{ok:!1,result:{ok:!1,errors:J,entries:[]}}:{ok:!0}}function tw(_,N,j){if(N._testDeleteLocalSourceDir){N._testDeleteLocalSourceDir(_);return}H(i(j,Ds(_,ge))),St(i(j,_))}function Cr(_,N){if(N===null){H(_);return}g(_,N)}function xr(_){return{ok:!1,errors:[_ instanceof Error?_.message:String(_)],entries:[]}}var rw=".safety-net.json",ow="~/.cc-safety-net/config.json";async function gp(_,N){let j=A(_,{cwd:N.cwd});if(j)console.log(`Skipped the project scope: ${I(N.cwd)} is the user rule config, not a project rule config`);return[j||await fp(_,{legacyPath:qa({cwd:N.cwd}),configPath:I(N.cwd),defaultRulebookName:"project-rules",migratedFrom:rw,cleanup:N.cleanup,syncOptions:{cwd:N.cwd}}),await fp(_,{legacyPath:Lt(_),configPath:W(_),defaultRulebookName:"user-rules",migratedFrom:ow,cleanup:N.cleanup,syncOptions:{cwd:N.cwd,global:!0}})].every((Y)=>Y)?0:1}async function fp(_,N){let j=hn(_,N.syncOptions),J=i(j.filesystemScope,N.legacyPath),Y=r(J);if(Y===null)return console.log(`No legacy config found at ${N.legacyPath}`),!0;let re=sw(Y);if(!re.ok){for(let Ee of re.errors)console.error(Ee);return!1}let ie=d(j.configTarget);if(ie.errors.length>0){for(let Ee of ie.errors)console.error(Ee);return!1}let de=ie.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},fe=aw(pp(N.configPath),de.rules,N.defaultRulebookName,N.migratedFrom,j.filesystemScope),we=No(pp(N.configPath),fe,"rulebook.json"),ke=i(j.filesystemScope,we),Re=[mp(j.configTarget),mp(ke)],Te=await iw(_,N,j.configTarget,ke,fe,re.config.rules,{...de,rules:de.rules.includes(fe)?de.rules:[...de.rules,fe]});if(!Te.ok){dw(Re);for(let Ee of Te.errors)console.error(Ee);return!1}if(!N.cleanup)return console.log(`Migrated legacy config at ${N.legacyPath}. Legacy file is no longer used.`),!0;if(!cw(j.configTarget,ke,fe,N.migratedFrom,re.config.rules))return console.error(`Migration cleanup verification failed for ${N.legacyPath}`),!1;return H(J),console.log(`Deleted legacy config at ${N.legacyPath}`),!0}async function iw(_,N,j,J,Y,re,ie){try{return bn(j,ie),bn(J,lw(Y,N.migratedFrom,re)),await Lo(_,N.syncOptions)}catch(de){return{ok:!1,errors:[de instanceof Error?de.message:String(de)]}}}function sw(_){try{let N=JSON.parse(_),j=Jo(N);if(j.errors.length>0)return{ok:!1,errors:j.errors};return{ok:!0,config:{version:1,rules:N.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function aw(_,N,j,J,Y){let re=N.find((ie)=>uw(i(Y,No(_,ie,"rulebook.json")))===J);if(re)return re;if(r(i(Y,No(_,j,"rulebook.json")))===null)return j;for(let ie=2;;ie++){let de=`${j}-${ie}`;if(r(i(Y,No(_,de,"rulebook.json")))===null)return de}}function lw(_,N,j){return{rulebook_version:1,name:_,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:N,allowed_commands:[...new Set(j.map((J)=>J.command))],rules:j,tests:j.map((J)=>({command:[J.command,J.subcommand,J.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:J.name}))}}function cw(_,N,j,J,Y){if(!d(_).config?.rules.includes(j))return!1;try{let ie=r(N);if(ie===null)return!1;let de=JSON.parse(ie);return de.migrated_from===J&&JSON.stringify(de.rules)===JSON.stringify(Y)}catch{return!1}}function mp(_){return{target:_,content:r(_)}}function dw(_){for(let N of _){if(N.content===null){H(N.target);continue}g(N.target,N.content)}}function uw(_){let N=r(_);if(N===null)return null;try{let j=JSON.parse(N);return typeof j.migrated_from==="string"?j.migrated_from:null}catch{return null}}import{mkdir as pw,readFile as fw,writeFile as mw}from"node:fs/promises";import{dirname as gw,join as yw}from"node:path";var hw=86400000,vw=604800000;async function hp(_,N=Date.now()){if(_.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let j=et(_);if(!j)return null;let J=yw(j,".cc-safety-net","update-check.json"),Y=await bw(J,N);if(!Y.lastCheck||N-Y.lastCheck>hw){let de=await Gn();if(Y.lastCheck=N,de.latestVersion)Y.latestVersion=de.latestVersion;if(!await yp(J,Y))return null;if(de.error)return null}let re=Y.latestVersion,ie=pn();if(!re||!Qo(re,ie))return null;if(Y.notifiedVersion===re&&Y.notifiedAt!==void 0&&N-Y.notifiedAt<vw)return null;if(Y.notifiedVersion=re,Y.notifiedAt=N,!await yp(J,Y))return null;return`UPDATE_AVAILABLE: cc-safety-net v${re} is available (running v${ie}). 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 bw(_,N){let j=await fw(_,"utf8").then((re)=>JSON.parse(re)).catch(()=>{return});if(!j||typeof j!=="object"||Array.isArray(j))return{};let J=j,Y=(re)=>typeof re==="number"&&Number.isFinite(re)&&re<=N?re:void 0;return{lastCheck:Y(J.lastCheck),latestVersion:typeof J.latestVersion==="string"?J.latestVersion:void 0,notifiedVersion:typeof J.notifiedVersion==="string"?J.notifiedVersion:void 0,notifiedAt:Y(J.notifiedAt)}}async function yp(_,N){return pw(gw(_),{recursive:!0,mode:448}).then(()=>mw(_,JSON.stringify(N),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as xw,resolve as js}from"node:path";var bp=new Map([["Bash","posix"],["PowerShell","powershell"],["Monitor","posix"]]);var wp=new Map([["Bash","auto"]]);var kp=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);var Cp=new Map([["Shell","auto"]]);var Sp=new Map([["exec","auto"]]),Pp="write_to_process";var Rp=new Map([["Execute","auto"]]);var Ep=new Map([["run_shell_command","auto"]]);var _p=new Map([["run_terminal_command","auto"],["run_terminal_cmd","auto"],["monitor","auto"],["bash","auto"],["Shell","auto"]]);var Tp=new Map([["terminal","posix"]]);var Ap=new Map([["Bash","posix"]]);var Ip="exec";var kw=[["antigravity-cli",[...el.keys(),nl]],["claude-code",[...bp.keys()]],["codex",[...wp.keys()]],["copilot-cli",[...kp.keys()]],["cursor",[...Cp.keys()]],["deepseek-harness",[...Qe.keys()]],["devin",[...Sp.keys(),Pp]],["droid",[...Rp.keys()]],["gemini-cli",[...Ep.keys()]],["grok-build",[..._p.keys()]],["hermes-agent",[...Tp.keys()]],["kimi-code",[...Ap.keys()]],["openclaw",[Ip]],["opencode",[Je,Ce]],["pi",[...Xe.keys()]]].flatMap(([_,N])=>N.map((j)=>({name:j,integration:cn(_)}))),Op="and is already analyzed. Built-in tools cannot be declared.";function jo(_){let N=_e(_),j=[...new Set(kw.filter((J)=>_e(J.name)===N).map((J)=>J.integration))].sort((J,Y)=>J.localeCompare(Y));if(j.length>0)return`"${_}" is a built-in shell tool of ${Cw(j)}, ${Op}`;if(x(_)!=="unknown")return`"${_}" is a built-in file tool, ${Op}`;return}function Cw(_){return _.length===1?_[0]??"":`${_.slice(0,-1).join(", ")} and ${_.at(-1)}`}var Dp="CC Safety Net Config",Sw="═".repeat(Dp.length),Pw="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Rw=new Set(["rule.json","rule.lock","cache"]);function Lp(_,N={}){try{return Ew(_,N)}catch(j){if(j instanceof o)return console.error(j.message),1;throw j}}function Ew(_,N){let j=N.cwd??process.cwd(),J=X(_,{cwd:j}),Y=Lt(_),re=Ir(j),ie=js(j,he),de=i(J.userScope,Y),fe=i(J.projectScope,re),we=!1,ke=!1,Re=[],Te=[],Ee=_w(i(J.projectScope,ie));if(Aw(),r(J.userConfigTarget)!==null){let De=Un(J.userConfigTarget);if(De.errors.push(...B(J.userConfigPath,J.userScope),...$p(J.userConfigTarget)),Re.push({scope:"User",path:J.userConfigPath,result:De,schema:"rules",target:J.userConfigTarget}),De.errors.length>0)we=!0}if(r(de)!==null)if(ke=!0,r(J.userConfigTarget)!==null)Te.push(Ho("user","cleanup"));else{let De=Wo(de);if(Re.push({scope:"User",path:Y,result:De,schema:"legacy",inactive:!0,target:de}),Te.push(Ho("user",De.errors.length>0?"fix-or-delete":"migrate")),De.errors.length>0)we=!0}if(r(J.projectConfigTarget)!==null){let De=Un(J.projectConfigTarget);if(De.errors.push(...B(J.projectConfigPath,J.projectScope),...$p(J.projectConfigTarget)),Re.push({scope:"Project",path:js(J.projectConfigPath),result:De,schema:"rules",target:J.projectConfigTarget}),De.errors.length>0)we=!0;if(r(fe)!==null)ke=!0,Te.push(Ho("project","cleanup"))}else if(r(fe)!==null){ke=!0,we=!0;let De=Wo(fe);Re.push({scope:"Project",path:js(re),result:De,schema:"legacy",inactive:!0,target:fe}),Te.push(Ho("project",De.errors.length>0?"fix-or-delete":"migrate"))}if(Ee?.result.errors.length)we=!0;if(Re.length===0&&!Ee)return console.log(`
283
+ No config files found. Using built-in rules only.`),0;for(let De of Re)if(De.inactive)Ow(De.scope,De.path,De.result);else if(De.result.errors.length>0)$w(De.scope,De.path,De.result.errors);else{if(De.schema==="rules"&&Nw(De.target))console.log(`
284
+ Added $schema to ${De.scope.toLowerCase()} config.`);Iw(De.scope,De.path,De.result,De.schema)}for(let De of Te)console.error(`
285
+ ${en.red(De)}`);if(Ee)if(Ee.result.errors.length>0)Lw(Ee.path,Ee.result.errors);else Dw(Ee.path,Ee.result);if(we)return console.error(`
286
+ Config validation failed.`),1;return console.log(ke?`
283
287
  Configs valid with warnings.`:`
284
- All configs valid.`),0}function xo(P,O){let D=`legacy ${P} config`;if(O==="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(O==="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 ${D}, then run \`npx -y cc-safety-net rule migrate\`.`}function mb(P){if(me(P)===null)return null;let O=gb(P);if(O.ruleNames.size===0&&O.errors.length===0)return null;return{path:P.path,result:O}}function gb(P){let O=[],D=new Set,j=(me(P)??[]).filter((J)=>!pb.has(J.name)).sort((J,Y)=>J.name.localeCompare(Y.name));if(j.length===0)return{errors:O,ruleNames:D};for(let J of j){if(!d.test(J.name)){O.push(`rulebook directory names must match ${d}: ${J.name}`);continue}if(J.kind!=="directory"){O.push(`${J.name} must be a rulebook directory`);continue}let Y=i(P.scope,cb(P.path,J.name,"rulebook.json")),re=r(Y);if(re===null){O.push(`${J.name}/rulebook.json is required`);continue}try{let ie;try{ie=JSON.parse(re)}catch{O.push(`${J.name}/rulebook.json: invalid JSON`);continue}let de=le(ie);if(de.name!==J.name){O.push(`rulebook name "${de.name}" must match folder "${J.name}"`);continue}let fe=mo(de);if(fe.length>0){O.push(...fe.map((we)=>`${J.name}/rulebook.json: ${we}`));continue}D.add(J.name)}catch(ie){O.push(ie instanceof Error?`${J.name}/rulebook.json: ${ie.message}`:`${J.name}/rulebook.json: ${String(ie)}`)}}return{errors:O,ruleNames:D}}function yb(){console.log(Fu),console.log(db)}function hb(P,O,D,j){if(console.log(`
285
- ✓ ${P} config: ${O}`),console.log(` Schema: ${j==="rules"?"rulebook sources":"legacy inline rules"}`),D.ruleNames.size>0){console.log(` ${j==="rules"?"Sources":"Rules"}:`);let J=1;for(let Y of D.ruleNames)console.log(` ${J}. ${Y}`),J++}else console.log(` ${j==="rules"?"Sources":"Rules"}: (none)`)}function vb(P,O,D){if(console.error(`
286
- ✗ Legacy ${P.toLowerCase()} config: ${O}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),D.errors.length>0){console.error(" Errors:");let j=1;for(let J of D.errors)for(let Y of J.split("; "))console.error(` ${j}. ${Y}`),j++;return}if(D.ruleNames.size>0){console.error(" Rules:");let j=1;for(let J of D.ruleNames)console.error(` ${j}. ${J}`),j++;return}console.error(" Rules: (none)")}function bb(P,O,D){Mu(`${P} config`,O,D)}function wb(P,O){console.log(`
287
- ✓ GitHub source rules: ${P}`),console.log(" Rulebooks:");let D=1;for(let j of O.ruleNames)console.log(` ${D}. ${j}`),D++}function kb(P,O){Mu("GitHub source rules",P,O)}function Mu(P,O,D){console.error(`
288
- ✗ ${P}: ${O}`),console.error(" Errors:");let j=1;for(let J of D)for(let Y of J.split("; "))console.error(` ${j}. ${Y}`),j++}function xb(P){try{let O=r(P);if(O===null)return!1;let D=JSON.parse(O);if(D.$schema)return!1;return g(P,JSON.stringify({$schema:ub,...D},null,2)),!0}catch(O){if(O instanceof o)throw O;return!1}}var Uu=new Set(["init","add","remove","update","sync","list","wrapper","migrate","doc","verify"]),Sb=new Set(["init","add","remove","update","sync","wrapper"]),Pb=new Set(["add","remove","list"]),Rb="cc-safety-net/rulebooks";async function Gu(P,O){try{return await Eb(P,O)}catch(D){if(D instanceof o)return console.error(D.message),1;throw D}}async function Eb(P,O){let D=Ab(O),j=D.help?_b(D.positionals):null;if(j)return Lt(j),0;if(D.errors.length>0){for(let fe of D.errors)console.error(fe);return 1}let J=D.positionals[0];if(!J)return Lt(xt,console.error),1;let Y=D.positionals[1],re={global:D.global},ie=process.cwd();if(!D.global&&Sb.has(J)&&!(J==="wrapper"&&Y==="list")&&L(P,{cwd:ie}))return console.error(`${_(ie)} is the user rule config, not a project rule config; use --global for the user scope, or run from a project directory`),1;if(J==="init"){let fe=kn(P,re);Ob(fe.configTarget);let we=Cb(fe.configDir,"example-rules","rulebook.json"),Ce=i(fe.filesystemScope,we);if(D.example&&r(Ce)===null)uu(Ce);let Se=B(fe.configPath,fe.filesystemScope);for(let Ie of Se)console.error(Ie);if(Se.length>0)return 1;return console.log("Rule config initialized."),0}if(J==="add"){let fe=qu(D);if(!fe)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let we=kn(P,re),Ce=await Au(P,fe,{...re,ref:D.ref,rulebooks:D.only.length>0?D.only:void 0});return su(Ce,fe,`Scope: ${D.global?"user":"project"} (${we.configDir})`),Ce.ok?0:1}if(J==="remove"){if(!Y)return console.error("rule remove requires a source"),1;let fe=await Tu(P,Y,{...re,deleteSource:D.deleteSource});return fo(fe,`Removed rulebook source: ${Y}`),fe.ok?0:1}if(J==="update"){let fe=await wo(P,{...re,only:Y,refresh:!0});return fo(fe,"Rule config updated."),fe.ok?0:1}if(J==="sync")return Ca(P,{global:D.global});if(J==="list"){let fe=Q(P,{cwd:ie});return lu(fe),fe.errors.length>0?1:0}if(J==="wrapper")return Db(P,D);if(J==="migrate")return Lu(P,{cleanup:D.cleanup,cwd:ie});if(J==="doc"){console.log(ou);let fe=await ju(P);if(fe)console.error(fe);return 0}if(J==="verify")return Hu(P);return 1}function _b(P){if(P.length===0)return xt;let O=xt.subcommands.filter((j)=>j.usage.split(" ")[0]===P[0]);if(O.length===0)return null;if(P.length===1&&O.length>1)return{name:`rule ${P[0]}`,description:`Subcommands of rule ${P[0]}`,usage:`rule ${P[0]} <subcommand>`,subcommands:O,options:[]};let D=P.length===1?O[0]:O.find((j)=>j.usage.split(" ")[1]===P[1]);if(!D)return null;return{name:`rule ${P[0]}`,description:D.description,usage:`rule ${D.usage}`,options:P[0]==="add"?_o:[],examples:P[0]==="add"?Ao:void 0}}function Ab(P){let O=yn({label:"rule",booleans:{global:["-g","--global"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"]},lists:{only:["--only"]},positionals:"list"},P),D={...O.flags,ref:O.values.ref,only:O.lists.only??[],help:O.help,positionals:O.positionals,errors:O.errors};return Tb(D),D}function Tb(P){let[O]=P.positionals;if(O&&!Uu.has(O))P.errors.push(`Unknown rule subcommand: ${O}`);if(P.deleteSource&&O!=="remove")if(O&&Uu.has(O))P.errors.push(`Unknown option for rule ${O}: --delete-source`);else P.errors.push("--delete-source is only valid with 'rule remove'");if(P.cleanup&&O!=="migrate")P.errors.push(pr(O,"--cleanup"));if(P.example&&O!=="init")P.errors.push(pr(O,"--example"));if(P.ref&&O!=="add")P.errors.push(pr(O,"--ref"));if(P.only.length>0&&O!=="add")P.errors.push(pr(O,"--only"));if(O==="add")Ib(P);if(O==="migrate"){if(P.global)P.errors.push(pr(O,"--global"));if(P.positionals.length>1)P.errors.push(`Unexpected rule migrate argument: ${P.positionals[1]}`)}else if(O==="wrapper")$b(P);else if(P.positionals.length>2)P.errors.push(`Unexpected rule argument: ${P.positionals[2]}`);if(O==="list"&&P.global)P.errors.push("Unknown option for rule list: --global")}function qu(P){if(P.positionals[1])return P.positionals[1];if(P.ref||P.only.length>0)return Rb;return}function Ib(P){let O=qu(P);if(!O)return;if((P.ref||P.only.length>0)&&!Z(O)){if(P.ref)P.errors.push(`--ref can only select a ref for an owner/repo source: ${O}`);if(P.only.length>0)P.errors.push("--only can only select rulebooks from an owner/repo source");return}if(P.ref&&!ae(P.ref))P.errors.push(`--ref must use valid path segments: ${P.ref}`);let D=P.only.filter((j)=>!d.test(j));if(D.length>0)P.errors.push(`Invalid rulebook names: ${D.join(", ")}`)}function pr(P,O){return P?`Unknown option for rule ${P}: ${O}`:`Unknown option for rule: ${O}`}function $b(P){let O=P.positionals[1],D=P.positionals[2];if(!O){P.errors.push("rule wrapper requires add, remove, or list");return}if(!Pb.has(O)){P.errors.push(`Unknown rule wrapper action: ${O}`);return}if(O==="list"){if(D)P.errors.push(`Unexpected rule wrapper argument: ${D}`);return}if(!D){P.errors.push(`rule wrapper ${O} requires a command`);return}if(P.positionals.length>3)P.errors.push(`Unexpected rule wrapper argument: ${P.positionals[3]}`)}function Ob(P){if(r(P)===null){du(P);return}let O=m(P);if(!O.config)return;wn(P,{version:1,rules:O.config.rules,overrides:O.config.overrides??{},transparent_wrappers:O.config.transparent_wrappers??[]})}async function Db(P,O){let D=O.positionals[1],j=O.positionals[2],J=kn(P,{global:O.global}).configTarget;if(D==="list"){let de=m(J);if(de.errors.length>0){for(let fe of de.errors)console.error(fe);return 1}return Lb(de.config?.transparent_wrappers??[]),0}if(!j||!C.test(j))return console.error("transparent wrapper must match command pattern"),1;if(Ae(j))return console.error(`reserved command "${j}" cannot be a wrapper`),1;let Y=m(J);if(Y.errors.length>0){for(let de of Y.errors)console.error(de);return 1}let re=Y.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},ie=D==="add"?[...new Set([...re.transparent_wrappers??[],j])]:(re.transparent_wrappers??[]).filter((de)=>de!==j);return wn(J,{version:1,rules:re.rules,overrides:re.overrides??{},transparent_wrappers:ie}),console.log(D==="add"?`Added transparent wrapper: ${j}`:`Removed transparent wrapper: ${j}`),0}function Lb(P){if(P.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${P.length}):`);for(let O of P)console.log(` - ${O}`)}import{sep as Ub}from"node:path";import{existsSync as Nb,readFileSync as jb}from"node:fs";import{join as Fb}from"node:path";async function Hb(P){if(P.isTTY)return null;return(await Ke(P).catch(()=>null))?.trim()||null}function Mb(P){let O=P.env.get("CLAUDE_SETTINGS_PATH");if(O)return O;return Fb(Ir(P),"settings.json")}function ms(P){let O=Mb(P);if(!Nb(O))return!1;try{let D=jb(O,"utf-8"),j=JSON.parse(D);if(!j.enabledPlugins)return!1;let J="cc-safety-net@cc-marketplace";if(!(J in j.enabledPlugins))return!1;return j.enabledPlugins[J]===!0}catch(D){if(v(n.debug,P.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${O}: ${D instanceof Error?D.message:String(D)}`);return!1}}async function gs(P,O=process.stdin){let D=ms(P),j;if(!D)j="\uD83D\uDEE1️ CC Safety Net ❌";else{let Y=k(P,{cwd:process.cwd()}),re=Y.policy,ie=T(re,P.env),de=Object.values(V(re,ie.capabilities)).some((Ce)=>Ce.changesInherited),fe={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[de?"custom":ie.effectiveLevel],we=Y.policyScopes&&!Y.policyScopes.weakeningsIgnored&&Y.policyScopes.weakenings.length>0?"\uD83D\uDD3B":"";j=`\uD83D\uDEE1️ CC Safety Net ${fe}${ie.worktreeMode?"\uD83C\uDF33":""}${we}${Y.state==="degraded"?"⚠️":""}`}let J=await Hb(O);if(J&&!J.startsWith("{"))console.log(`${J} | ${j}`);else console.log(j)}function Bu(P){let O=k(P,{cwd:process.cwd()}),D=O.policy,j=T(D,P.env),J=!!process.env.NO_COLOR||!process.stdout.isTTY,Y=Math.min(process.stdout.columns||80,100),re=J?"ok":"✔",ie=J?"OFF":"✘",de=(qe,Me)=>{let en=` ${qe.padEnd(13)}${Me}`;return(en.length>Y?`${en.slice(0,Y-1)}…`:en).replaceAll(ie,nn.red(ie))},fe=Object.values(V(D,j.capabilities)).some((qe)=>qe.changesInherited),we=(qe)=>qe===P.home||qe.startsWith(`${P.home}${Ub}`)?`~${qe.slice(P.home.length)}`:qe,Ce={ready:nn.green,degraded:nn.yellow}[O.state],Se=O.policyScopes?.weakenings??[],Ie=[...ms(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."],...O.diagnostics],Ee=J?"-":"·";console.log([`${J?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Ce(O.state)}`,"",de("Protection",`destructive ${D.destructiveCommandProtectionEnabled?re:ie} secrets ${D.secretProtection.enabled?re:ie}`),de("Level",fe?`${j.effectiveLevel} (customised)`:j.effectiveLevel),de("Rules",D.rules.length===0?"none active":`${D.rules.length} active`),de("Policy",we(l(P))),...O.policyScopes?[de("Project",we(h(process.cwd())))]:[],...j.worktreeMode?[de("Worktree","relaxations active")]:[],"",...Se.length===0?[]:[O.policyScopes?.weakeningsIgnored?" Project policy (ignored)":" Project policy",...Se.flatMap((qe)=>er(qe," ",Y-6).map((Me,en)=>en===0?` ${Me}`:Me)),""],...Ie.length===0?[" Everything configured is active."]:[" Not active",...Ie.flatMap((qe)=>er(qe," ",Y-6).map((Me,en)=>en===0?` ${Ee} ${Me}`:Me)),""," Full report: cc-safety-net doctor"]].join(`
289
- `))}import{spawn as np}from"node:child_process";import{randomBytes as Zb}from"node:crypto";import{existsSync as Xb}from"node:fs";import{createServer as Qb}from"node:http";import{Writable as ew}from"node:stream";var Co=500;function Gb(P){let O=P.filter((J)=>J.decision!=="allow"),D=P.filter((J)=>J.decision==="allow"),j=Math.min(O.length,Math.max(Co-D.length,Math.ceil(Co/2)));return[...O.slice(0,j),...D.slice(0,Co-j)]}function Vu(P,O,D=U(P)){if(D)K(P,D);let j=(Me)=>new Date(Me.getFullYear(),Me.getMonth(),Me.getDate()).getTime(),J=j(new Date),Y=new Date(J);Y.setDate(Y.getDate()-(O-1));let re=Y.getTime(),ie=[],de={count:0};for(let Me of D?Kn(D,de):[])for(let en of kt(Me,de)){let on=new Date(en.ts).getTime();if(!Number.isFinite(on))continue;if(on>=re)ie.push(en)}ie.sort((Me,en)=>new Date(en.ts).getTime()-new Date(Me.ts).getTime());let fe=Array.from({length:O},()=>0),we=Array.from({length:O},()=>0),Ce={},Se={},Ie={},Ee=0,qe=0;for(let Me of ie){let en=Me.agent||"unknown";Ce[en]=(Ce[en]??0)+1;let on=Math.round((J-j(new Date(Me.ts)))/86400000),sn=O-1-on,an=on>=0&&on<O;if(an)we[sn]=(we[sn]??0)+1;if(Me.decision!=="allow"){if(Ee++,Me.ruleId)Se[Me.ruleId]=(Se[Me.ruleId]??0)+1;let rn=Ro(Me.segment||Me.command);if(rn)Ie[rn]=(Ie[rn]??0)+1;if(Me.failureStage)qe++;if(an)fe[sn]=(fe[sn]??0)+1}}return{days:O,logsDir:D,homeDir:P.home,totalInWindow:ie.length,truncated:ie.length>Co,unreadable:de.count,counts:{blocked:Ee,allowed:ie.length-Ee,agents:Ce,blockedByDay:fe,analyzedByDay:we,rules:Se,commands:Ie,errors:qe},entries:Gb(ie).sort((Me,en)=>new Date(en.ts).getTime()-new Date(Me.ts).getTime())}}import{spawn as qb}from"node:child_process";import{existsSync as Bb,statSync as Ju}from"node:fs";import{delimiter as Vb,join as Jb}from"node:path";var Kb=120000,So="Choose the project folder",Wb=`try
290
- return POSIX path of (choose folder with prompt "${So}")
288
+ All configs valid.`),0}function $p(_){return(d(_).config?.command_tools??[]).flatMap((N)=>jo(typeof N==="string"?N:N.name)??[])}function Ho(_,N){let j=`legacy ${_} config`;if(N==="cleanup")return`Warning: Legacy ${_} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(N==="migrate")return`Warning: Legacy ${_} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${_} config is no longer supported. Fix or delete the ${j}, then run \`npx -y cc-safety-net rule migrate\`.`}function _w(_){if(me(_)===null)return null;let N=Tw(_);if(N.ruleNames.size===0&&N.errors.length===0)return null;return{path:_.path,result:N}}function Tw(_){let N=[],j=new Set,J=(me(_)??[]).filter((Y)=>!Rw.has(Y.name)).sort((Y,re)=>Y.name.localeCompare(re.name));if(J.length===0)return{errors:N,ruleNames:j};for(let Y of J){if(!p.test(Y.name)){N.push(`rulebook directory names must match ${p}: ${Y.name}`);continue}if(Y.kind!=="directory"){N.push(`${Y.name} must be a rulebook directory`);continue}let re=i(_.scope,xw(_.path,Y.name,"rulebook.json")),ie=r(re);if(ie===null){N.push(`${Y.name}/rulebook.json is required`);continue}try{let de;try{de=JSON.parse(ie)}catch{N.push(`${Y.name}/rulebook.json: invalid JSON`);continue}let fe=le(de);if(fe.name!==Y.name){N.push(`rulebook name "${fe.name}" must match folder "${Y.name}"`);continue}let we=To(fe);if(we.length>0){N.push(...we.map((ke)=>`${Y.name}/rulebook.json: ${ke}`));continue}j.add(Y.name)}catch(de){N.push(de instanceof Error?`${Y.name}/rulebook.json: ${de.message}`:`${Y.name}/rulebook.json: ${String(de)}`)}}return{errors:N,ruleNames:j}}function Aw(){console.log(Dp),console.log(Sw)}function Iw(_,N,j,J){if(console.log(`
289
+ ✓ ${_} config: ${N}`),console.log(` Schema: ${J==="rules"?"rulebook sources":"legacy inline rules"}`),j.ruleNames.size>0){console.log(` ${J==="rules"?"Sources":"Rules"}:`);let Y=1;for(let re of j.ruleNames)console.log(` ${Y}. ${re}`),Y++}else console.log(` ${J==="rules"?"Sources":"Rules"}: (none)`)}function Ow(_,N,j){if(console.error(`
290
+ ✗ Legacy ${_.toLowerCase()} config: ${N}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),j.errors.length>0){console.error(" Errors:");let J=1;for(let Y of j.errors)for(let re of Y.split("; "))console.error(` ${J}. ${re}`),J++;return}if(j.ruleNames.size>0){console.error(" Rules:");let J=1;for(let Y of j.ruleNames)console.error(` ${J}. ${Y}`),J++;return}console.error(" Rules: (none)")}function $w(_,N,j){Np(`${_} config`,N,j)}function Dw(_,N){console.log(`
291
+ ✓ GitHub source rules: ${_}`),console.log(" Rulebooks:");let j=1;for(let J of N.ruleNames)console.log(` ${j}. ${J}`),j++}function Lw(_,N){Np("GitHub source rules",_,N)}function Np(_,N,j){console.error(`
292
+ ✗ ${_}: ${N}`),console.error(" Errors:");let J=1;for(let Y of j)for(let re of Y.split("; "))console.error(` ${J}. ${re}`),J++}function Nw(_){try{let N=r(_);if(N===null)return!1;let j=JSON.parse(N);if(j.$schema)return!1;return g(_,JSON.stringify({$schema:Pw,...j},null,2)),!0}catch(N){if(N instanceof o)throw N;return!1}}var jp=new Set(["init","add","remove","update","sync","list","wrapper","tool","migrate","doc","verify"]),Hw=new Set(["init","add","remove","update","sync","wrapper"]),Fp=new Set(["add","remove","list"]),Fw="cc-safety-net/rulebooks";async function Mp(_,N){try{return await Mw(_,N)}catch(j){if(j instanceof o)return console.error(j.message),1;throw j}}async function Mw(_,N){let j=Gw(N),J=j.help?Uw(j.positionals):null;if(J)return Kt(J),0;if(j.errors.length>0){for(let we of j.errors)console.error(we);return 1}let Y=j.positionals[0];if(!Y)return Kt(Dt,console.error),1;let re=j.positionals[1],ie={global:j.global},de=process.cwd();if((Y==="tool"?j.project:!j.global&&Hw.has(Y)&&!(Y==="wrapper"&&re==="list"))&&A(_,{cwd:de}))return console.error(`${I(de)} is the user rule config, not a project rule config; ${Y==="tool"?"drop --project":"use --global"} for the user scope, or run from a project directory`),1;if(Y==="init"){let we=hn(_,ie);Vw(we.configTarget);let ke=jw(we.configDir,"example-rules","rulebook.json"),Re=i(we.filesystemScope,ke);if(j.example&&r(Re)===null)Vu(Re);let Te=B(we.configPath,we.filesystemScope);for(let Ee of Te)console.error(Ee);if(Te.length>0)return 1;return console.log("Rule config initialized."),0}if(Y==="add"){let we=Up(j);if(!we)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let ke=hn(_,ie),Re=await cp(_,we,{...ie,ref:j.ref,rulebooks:j.only.length>0?j.only:void 0});return Fu(Re,we,`Scope: ${j.global?"user":"project"} (${ke.configDir})`),Re.ok?0:1}if(Y==="remove"){if(!re)return console.error("rule remove requires a source"),1;let we=await dp(_,re,{...ie,deleteSource:j.deleteSource});return _o(we,`Removed rulebook source: ${re}`),we.ok?0:1}if(Y==="update"){let we=await Lo(_,{...ie,only:re,refresh:!0});return _o(we,"Rule config updated."),we.ok?0:1}if(Y==="sync")return Ja(_,{global:j.global});if(Y==="list"){let we=Q(_,{cwd:de});return Uu(we),we.errors.length>0?1:0}if(Y==="wrapper")return Kw(_,j);if(Y==="tool")return Ww(_,j,de);if(Y==="migrate")return gp(_,{cleanup:j.cleanup,cwd:de});if(Y==="doc"){console.log(ju);let we=await hp(_);if(we)console.error(we);return 0}if(Y==="verify")return Lp(_);return 1}function Uw(_){if(_.length===0)return Dt;let N=Dt.subcommands.filter((J)=>J.usage.split(" ")[0]===_[0]);if(N.length===0)return null;if(_.length===1&&N.length>1)return{name:`rule ${_[0]}`,description:`Subcommands of rule ${_[0]}`,usage:`rule ${_[0]} <subcommand>`,subcommands:N,options:[]};let j=_.length===1?N[0]:N.find((J)=>J.usage.split(" ")[1]===_[1]);if(!j)return null;return{name:`rule ${_[0]}`,description:j.description,usage:`rule ${j.usage}`,options:_[0]==="add"?qo:[],examples:_[0]==="add"?Vo:void 0}}function Gw(_){let N=mn({label:"rule",booleans:{global:["-g","--global"],project:["--project"],cleanup:["--cleanup"],deleteSource:["--delete-source"],example:["--example"]},values:{ref:["--ref"],cwdArg:["--cwd-arg"]},lists:{only:["--only"]},positionals:"list"},_),j={...N.flags,ref:N.values.ref,cwdArg:N.values.cwdArg,only:N.lists.only??[],help:N.help,positionals:N.positionals,errors:N.errors};return Bw(j),j}function Bw(_){let[N]=_.positionals;if(N&&!jp.has(N))_.errors.push(`Unknown rule subcommand: ${N}`);if(_.deleteSource&&N!=="remove")if(N&&jp.has(N))_.errors.push(`Unknown option for rule ${N}: --delete-source`);else _.errors.push("--delete-source is only valid with 'rule remove'");if(_.cleanup&&N!=="migrate")_.errors.push(zn(N,"--cleanup"));if(_.example&&N!=="init")_.errors.push(zn(N,"--example"));if(_.ref&&N!=="add")_.errors.push(zn(N,"--ref"));if(_.only.length>0&&N!=="add")_.errors.push(zn(N,"--only"));let j=N==="tool"?_.positionals[1]:void 0,J=j&&Fp.has(j)?`tool ${j}`:N;if(_.project&&j!=="add"&&j!=="remove")_.errors.push(zn(J,"--project"));if(_.cwdArg!==void 0&&j!=="add")_.errors.push(zn(J,"--cwd-arg"));if(N==="tool"&&_.global)_.errors.push(zn(N,"--global"));if(N==="add")qw(_);if(N==="migrate"){if(_.global)_.errors.push(zn(N,"--global"));if(_.positionals.length>1)_.errors.push(`Unexpected rule migrate argument: ${_.positionals[1]}`)}else if(N==="wrapper")Hp(_,"a command");else if(N==="tool")Hp(_,"a tool name");else if(_.positionals.length>2)_.errors.push(`Unexpected rule argument: ${_.positionals[2]}`);if(N==="list"&&_.global)_.errors.push("Unknown option for rule list: --global")}function Up(_){if(_.positionals[1])return _.positionals[1];if(_.ref||_.only.length>0)return Fw;return}function qw(_){let N=Up(_);if(!N)return;if((_.ref||_.only.length>0)&&!Z(N)){if(_.ref)_.errors.push(`--ref can only select a ref for an owner/repo source: ${N}`);if(_.only.length>0)_.errors.push("--only can only select rulebooks from an owner/repo source");return}if(_.ref&&!ae(_.ref))_.errors.push(`--ref must use valid path segments: ${_.ref}`);let j=_.only.filter((J)=>!p.test(J));if(j.length>0)_.errors.push(`Invalid rulebook names: ${j.join(", ")}`)}function zn(_,N){return _?`Unknown option for rule ${_}: ${N}`:`Unknown option for rule: ${N}`}function Hp(_,N){let j=_.positionals[0],J=_.positionals[1],Y=_.positionals[2];if(!J){_.errors.push(`rule ${j} requires add, remove, or list`);return}if(!Fp.has(J)){_.errors.push(`Unknown rule ${j} action: ${J}`);return}if(J==="list"){if(Y)_.errors.push(`Unexpected rule ${j} argument: ${Y}`);return}if(!Y){_.errors.push(`rule ${j} ${J} requires ${N}`);return}if(j!=="tool"&&_.positionals.length>3)_.errors.push(`Unexpected rule ${j} argument: ${_.positionals[3]}`)}function Vw(_){if(r(_)===null){qu(_);return}let N=d(_);if(!N.config)return;bn(_,N.config)}async function Kw(_,N){let j=N.positionals[1],J=N.positionals[2],Y=hn(_,{global:N.global}).configTarget;if(j==="list"){let fe=d(Y);if(fe.errors.length>0){for(let we of fe.errors)console.error(we);return 1}return Jw(fe.config?.transparent_wrappers??[]),0}if(!J||!E.test(J))return console.error("transparent wrapper must match command pattern"),1;if(Me(J))return console.error(`reserved command "${J}" cannot be a wrapper`),1;let re=d(Y);if(re.errors.length>0){for(let fe of re.errors)console.error(fe);return 1}let ie=re.config??{version:1,rules:[],overrides:{},transparent_wrappers:[]},de=j==="add"?[...new Set([...ie.transparent_wrappers??[],J])]:(ie.transparent_wrappers??[]).filter((fe)=>fe!==J);return bn(Y,{...ie,transparent_wrappers:de}),console.log(j==="add"?`Added transparent wrapper: ${J}`:`Removed transparent wrapper: ${J}`),0}function Jw(_){if(_.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${_.length}):`);for(let N of _)console.log(` - ${N}`)}function Ww(_,N,j){let J=N.positionals[1],Y=[...new Set(N.positionals.slice(2))];if(J==="list")return zw(_,j);let re=[...Y.flatMap((we)=>{if(!$e.test(we))return[`"${we}" is not a tool name: ${xe}.`];let ke=J==="add"?jo(we):void 0;return ke?[ke]:[]}),...N.cwdArg!==void 0&&!$e.test(N.cwdArg)?[`"${N.cwdArg}" is not an argument name: ${xe}.`]:[]];if(re.length>0){for(let we of re)console.error(en.red(`Error: ${we}`));return 1}let ie=hn(_,{global:!N.project}),de=kr(ie.configTarget);if(!de.ok){for(let we of de.result.errors)console.error(we);return 1}let fe=Y.reduce((we,ke)=>{let Re=N.cwdArg===void 0?ke:{name:ke,cwd:N.cwdArg},Te=(Ee)=>(typeof Ee==="string"?Ee:Ee.name)===ke;if(J==="remove")return we.filter((Ee)=>!Te(Ee));return we.some(Te)?we.map((Ee)=>Te(Ee)?Re:Ee):[...we,Re]},de.config.command_tools??[]);bn(ie.configTarget,{...de.config,command_tools:fe});for(let we of Y)console.log(J==="add"?`Added command tool: ${we}${N.cwdArg===void 0?"":` (cwd argument: ${N.cwdArg})`}`:`Removed command tool: ${we}`);return console.log(`Scope: ${N.project?"project":"user"} (${ie.configPath})`),0}function zw(_,N){let j=(A(_,{cwd:N})?["user"]:["user","project"]).map((Y)=>{let re=hn(_,{global:Y==="user"});return{scope:Y,path:re.configPath,...d(re.configTarget)}}),J=j.flatMap((Y)=>Y.errors.map((re)=>`${Y.path}: ${re}`));if(J.length>0){for(let Y of J)console.error(Y);return 1}return Gu(j.flatMap((Y)=>(Y.config?.command_tools??[]).map((re)=>({scope:Y.scope,tool:re})))),0}import{sep as nk}from"node:path";import{existsSync as Yw,readFileSync as Zw}from"node:fs";import{join as Xw}from"node:path";async function Qw(_){if(_.isTTY)return null;return(await it(_).catch(()=>null))?.trim()||null}function ek(_){let N=_.env.get("CLAUDE_SETTINGS_PATH");if(N)return N;return Xw(Vr(_),"settings.json")}function Hs(_){let N=ek(_);if(!Yw(N))return!1;try{let j=Zw(N,"utf-8"),J=JSON.parse(j);if(!J.enabledPlugins)return!1;let Y="cc-safety-net@cc-marketplace";if(!(Y in J.enabledPlugins))return!1;return J.enabledPlugins[Y]===!0}catch(j){if(S(n.debug,_.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${N}: ${j instanceof Error?j.message:String(j)}`);return!1}}async function Fs(_,N=process.stdin){let j=Hs(_),J;if(!j)J="\uD83D\uDEE1️ CC Safety Net ❌";else{let re=R(_,{cwd:process.cwd()}),ie=re.policy,de=P(ie,_.env),fe=Object.values(V(ie,de.capabilities)).some((Re)=>Re.changesInherited),we={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[fe?"custom":de.effectiveLevel],ke=re.policyScopes&&!re.policyScopes.weakeningsIgnored&&re.policyScopes.weakenings.length>0?"\uD83D\uDD3B":"";J=`\uD83D\uDEE1️ CC Safety Net ${we}${de.worktreeMode?"\uD83C\uDF33":""}${ke}${re.state==="degraded"?"⚠️":""}`}let Y=await Qw(N);if(Y&&!Y.startsWith("{"))console.log(`${Y} | ${J}`);else console.log(J)}function Gp(_){let N=R(_,{cwd:process.cwd()}),j=N.policy,J=P(j,_.env),Y=!!process.env.NO_COLOR||!process.stdout.isTTY,re=Math.min(process.stdout.columns||80,100),ie=Y?"ok":"✔",de=Y?"OFF":"✘",fe=(He,Le)=>{let Ye=` ${He.padEnd(13)}${Le}`;return(Ye.length>re?`${Ye.slice(0,re-1)}…`:Ye).replaceAll(de,en.red(de))},we=Object.values(V(j,J.capabilities)).some((He)=>He.changesInherited),ke=(He)=>He===_.home||He.startsWith(`${_.home}${nk}`)?`~${He.slice(_.home.length)}`:He,Re={ready:en.green,degraded:en.yellow}[N.state],Te=N.policyScopes?.weakenings??[],Ee=[...Hs(_)?[]:["plugin cc-safety-net@cc-marketplace is disabled in Claude Code; nothing is enforced in Claude Code until it is re-enabled. Other integrations are not affected."],...N.diagnostics],De=Y?"-":"·";console.log([`${Y?"":"\uD83D\uDEE1️ "}CC Safety Net — ${Re(N.state)}`,"",fe("Protection",`destructive ${j.destructiveCommandProtectionEnabled?ie:de} secrets ${j.secretProtection.enabled?ie:de}`),fe("Level",we?`${J.effectiveLevel} (customised)`:J.effectiveLevel),fe("Rules",j.rules.length===0?"none active":`${j.rules.length} active`),fe("Policy",ke(u(_))),...N.policyScopes?[fe("Project",ke(h(process.cwd())))]:[],...J.worktreeMode?[fe("Worktree","relaxations active")]:[],"",...Te.length===0?[]:[N.policyScopes?.weakeningsIgnored?" Project policy (ignored)":" Project policy",...Te.flatMap((He)=>ur(He," ",re-6).map((Le,Ye)=>Ye===0?` ${Le}`:Le)),""],...Ee.length===0?[" Everything configured is active."]:[" Not active",...Ee.flatMap((He)=>ur(He," ",re-6).map((Le,Ye)=>Ye===0?` ${De} ${Le}`:Le)),""," Full report: cc-safety-net doctor"]].join(`
293
+ `))}import{spawn as Qp}from"node:child_process";import{randomBytes as uk}from"node:crypto";import{existsSync as pk}from"node:fs";import{createServer as fk}from"node:http";import{Writable as mk}from"node:stream";var Fo=500;function tk(_){let N=_.filter((Y)=>Y.decision!=="allow"),j=_.filter((Y)=>Y.decision==="allow"),J=Math.min(N.length,Math.max(Fo-j.length,Math.ceil(Fo/2)));return[...N.slice(0,J),...j.slice(0,Fo-J)]}function Bp(_,N,j=U(_)){if(j)K(_,j);let J=(Le)=>new Date(Le.getFullYear(),Le.getMonth(),Le.getDate()).getTime(),Y=J(new Date),re=new Date(Y);re.setDate(re.getDate()-(N-1));let ie=re.getTime(),de=[],fe={count:0};for(let Le of j?Yn(j,fe):[])for(let Ye of $t(Le,fe)){let tn=new Date(Ye.ts).getTime();if(!Number.isFinite(tn))continue;if(tn>=ie)de.push(Ye)}de.sort((Le,Ye)=>new Date(Ye.ts).getTime()-new Date(Le.ts).getTime());let we=Array.from({length:N},()=>0),ke=Array.from({length:N},()=>0),Re={},Te={},Ee={},De=0,He=0;for(let Le of de){let Ye=Le.agent||"unknown";Re[Ye]=(Re[Ye]??0)+1;let tn=Math.round((Y-J(new Date(Le.ts)))/86400000),rn=N-1-tn,sn=tn>=0&&tn<N;if(sn)ke[rn]=(ke[rn]??0)+1;if(Le.decision!=="allow"){if(De++,Le.ruleId)Te[Le.ruleId]=(Te[Le.ruleId]??0)+1;let nn=Go(Le.segment||Le.command);if(nn)Ee[nn]=(Ee[nn]??0)+1;if(Le.failureStage)He++;if(sn)we[rn]=(we[rn]??0)+1}}return{days:N,logsDir:j,homeDir:_.home,totalInWindow:de.length,truncated:de.length>Fo,unreadable:fe.count,counts:{blocked:De,allowed:de.length-De,agents:Re,blockedByDay:we,analyzedByDay:ke,rules:Te,commands:Ee,errors:He},entries:tk(de).sort((Le,Ye)=>new Date(Ye.ts).getTime()-new Date(Le.ts).getTime())}}import{spawn as rk}from"node:child_process";import{existsSync as ok,statSync as qp}from"node:fs";import{delimiter as ik,join as sk}from"node:path";var ak=120000,Mo="Choose the project folder",lk=`try
294
+ return POSIX path of (choose folder with prompt "${Mo}")
291
295
  on error number -128
292
296
  return ""
293
- end try`,zb=`Add-Type -AssemblyName System.Windows.Forms
297
+ end try`,ck=`Add-Type -AssemblyName System.Windows.Forms
294
298
  $dialog = New-Object System.Windows.Forms.FolderBrowserDialog
295
- $dialog.Description = '${So}'
296
- if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Ku=[{binary:"zenity",args:["--file-selection","--directory",`--title=${So}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",So]}],Wu=(P,O)=>(O.PATH??"").split(Vb).some((D)=>{if(D.length===0)return!1;try{let j=Ju(Jb(D,P));return j.isFile()&&(j.mode&73)!==0}catch{return!1}});function ys(P,O){if(P==="darwin"||P==="win32")return!0;if(P!=="linux")return!1;if(!O.DISPLAY&&!O.WAYLAND_DISPLAY)return!1;return Ku.some((D)=>Wu(D.binary,O))}function Yb(P,O){if(P==="darwin")return{cmd:"osascript",args:["-e",Wb]};if(P==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",zb]};let D=Ku.find((j)=>Wu(j.binary,O));return D?{cmd:D.binary,args:D.args}:null}function hs(P=process.platform,O=process.env){let D=Yb(P,O);if(!D)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((j)=>{let J=qb(D.cmd,D.args,{env:O,stdio:["ignore","pipe","pipe"]}),Y="",re=!1,ie=(fe)=>{if(re)return;re=!0,clearTimeout(de),j(fe)},de=setTimeout(()=>{J.kill(),ie({error:"The folder dialog timed out"})},Kb);J.stdout.on("data",(fe)=>{Y+=fe.toString()}),J.on("error",()=>ie({error:`Could not open the folder dialog (${D.cmd})`})),J.on("close",()=>{let fe=Y.trim().replace(/\/+$/,"");if(!fe)return ie({cancelled:!0});if(!Bb(fe)||!Ju(fe).isDirectory())return ie({error:"That selection is not a folder on disk"});ie({path:fe})})})}var zu=`<!doctype html>
299
+ $dialog.Description = '${Mo}'
300
+ if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Vp=[{binary:"zenity",args:["--file-selection","--directory",`--title=${Mo}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",Mo]}],Kp=(_,N)=>(N.PATH??"").split(ik).some((j)=>{if(j.length===0)return!1;try{let J=qp(sk(j,_));return J.isFile()&&(J.mode&73)!==0}catch{return!1}});function Ms(_,N){if(_==="darwin"||_==="win32")return!0;if(_!=="linux")return!1;if(!N.DISPLAY&&!N.WAYLAND_DISPLAY)return!1;return Vp.some((j)=>Kp(j.binary,N))}function dk(_,N){if(_==="darwin")return{cmd:"osascript",args:["-e",lk]};if(_==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",ck]};let j=Vp.find((J)=>Kp(J.binary,N));return j?{cmd:j.binary,args:j.args}:null}function Us(_=process.platform,N=process.env){let j=dk(_,N);if(!j)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((J)=>{let Y=rk(j.cmd,j.args,{env:N,stdio:["ignore","pipe","pipe"]}),re="",ie=!1,de=(we)=>{if(ie)return;ie=!0,clearTimeout(fe),J(we)},fe=setTimeout(()=>{Y.kill(),de({error:"The folder dialog timed out"})},ak);Y.stdout.on("data",(we)=>{re+=we.toString()}),Y.on("error",()=>de({error:`Could not open the folder dialog (${j.cmd})`})),Y.on("close",()=>{let we=re.trim().replace(/\/+$/,"");if(!we)return de({cancelled:!0});if(!ok(we)||!qp(we).isDirectory())return de({error:"That selection is not a folder on disk"});de({path:we})})})}var Jp=`<!doctype html>
297
301
  <html lang="en">
298
302
  <head>
299
303
  <meta charset="utf-8">
@@ -5755,6 +5759,6 @@ loadPolicy().then((loaded) => {
5755
5759
  </script>
5756
5760
  </body>
5757
5761
  </html>
5758
- `;var Yu='<script id="ccsn-data" type="application/json">';function Zu(P,O=zu){return O.replace(Yu,()=>Yu+JSON.stringify({token:P}).replaceAll("<","\\u003c"))}var bs="kenryu42/cc-safety-net",nw=`https://github.com/${bs}`,tp=1e4,tw=7,rw="The project draft directory changed; reload the draft before applying.",ow="audit settings are user scope only; remove the audit section from a project proposal";async function rp(P,O={}){let D=yn({label:"gui",booleans:{noOpen:["--no-open"]}},P),j=O.log??console.log,J=O.error??console.error;if(D.errors.length>0){for(let re of D.errors)J(re);return J("Usage: cc-safety-net gui [--no-open]"),1}let Y=await iw(c,O);if(j(`CC Safety Net policy GUI: ${Y.url}`),!D.flags.noOpen)try{await(O.openBrowser??yw)(Y.url)}catch(re){J(`Failed to open browser: ${re instanceof Error?re.message:String(re)}`),J(`Open this URL manually: ${Y.url}`)}if(O.keepAlive===!1)return await Y.close(),0;return await gw(Y),0}async function iw(P,O={}){let D=Zb(24).toString("base64url"),j={dir:null,revision:0},J=Qb((ie,de)=>{sw(P,ie,de,D,O,j)});await new Promise((ie,de)=>{J.once("error",de),J.listen(0,"127.0.0.1",()=>{J.off("error",de),ie()})});let re=`http://127.0.0.1:${J.address().port}`;return{origin:re,token:D,url:`${re}/?token=${encodeURIComponent(D)}`,close:()=>mw(J)}}async function sw(P,O,D,j,J,Y){let re=P(),ie=new URL(O.url??"/","http://127.0.0.1");if(O.method==="GET"&&ie.pathname==="/favicon.ico"){D.writeHead(204,{"cache-control":"no-store"}),D.end();return}if(!uw(O,ie,j)){ln(D,403,{error:"Forbidden"});return}if(O.method==="GET"&&ie.pathname==="/"){await Promise.resolve(J.buildDocument?.()).then((de)=>fw(D,Zu(j,de)),(de)=>ln(D,500,{error:de instanceof Error?de.message:String(de)}));return}if(O.method==="GET"&&ie.pathname==="/api/policy"){let de=Zd(re,J),fe=k(re,vs(J));ln(D,200,{...de,configState:je(fe),...fe.policyScopes?{projectPolicy:{path:h(J.cwd??process.cwd()),weakenings:fe.policyScopes.weakeningsIgnored?[]:fe.policyScopes.weakenings}}:{},destructiveCommandRules:z,secretPatterns:Qe,version:pn(),preview:de.errors.length>0?null:Le(de.policy,re.env)});return}if(O.method==="POST"&&ie.pathname==="/api/policy/preview"){let de=await fr(O);if(!de.ok){ln(D,de.status,{errors:[de.error]});return}let fe=Xd(re,de.value);ln(D,fe.errors.length>0?400:200,fe);return}if(O.method==="POST"&&ie.pathname==="/api/policy/explain"){let de=await fr(O);if(!de.ok){ln(D,de.status,{errors:[de.error]});return}let fe=de.value;if(fe===null||typeof fe.command!=="string"){ln(D,400,{errors:["command must be a string"]});return}let we=lr(fe.policy,re.home);if(we.length>0){ln(D,400,{errors:we});return}ln(D,200,cw(re,fe.command,fe.policy,J));return}if(O.method==="POST"&&ie.pathname==="/api/policy"){let de=await fr(O);if(!de.ok){ln(D,de.status,{errors:[de.error]});return}let fe=Hn(re,de.value,J);ln(D,fe.errors.length>0?400:200,fe);return}if(O.method==="POST"&&ie.pathname==="/api/reset"){ln(D,200,Hn(re,te,J));return}if(O.method==="POST"&&ie.pathname==="/api/repair"){ln(D,200,Qd(re,J));return}if(O.method==="POST"&&ie.pathname==="/api/policy/project/choose-directory"){let de=await(J.chooseDirectory??hs)();if("path"in de)Y.dir=de.path,Y.revision+=1;ln(D,200,{cancelled:"cancelled"in de,..."error"in de?{error:de.error}:{}});return}if(O.method==="GET"&&ie.pathname==="/api/policy/project"){let de=op(Y,J),fe=ip(re,de,J),we=fe?{projection:{},diagnostics:[fe]}:Xu(de,re.home),Ce=cr(re,J);ln(D,200,{path:h(de),revision:Y.revision,baseline:Ce.baseline,userPolicyDiagnostics:Ce.diagnostics,projection:we.projection,projectionDiagnostics:we.diagnostics,canPickDirectory:ys(process.platform,process.env)});return}if(O.method==="POST"&&ie.pathname==="/api/policy/project/diff"){let de=await Qu(re,O,D,Y,J);if(!de)return;let fe=Xu(de.dir,re.home),we=cr(re,J).baseline,Ce=ee(we,ue(de.proposal,re.home).policy);ln(D,200,{rows:uo(ee(we,fe.projection).policy,Ce.policy,!1),weakenings:Ce.weakenings,existingFileDiagnostics:fe.diagnostics});return}if(O.method==="POST"&&ie.pathname==="/api/policy/project/apply"){let de=await Qu(re,O,D,Y,J);if(!de)return;let fe=lw(de.dir,de.proposal,re.home);ln(D,fe.errors.length>0?500:200,fe);return}if(O.method==="GET"&&ie.pathname==="/api/activity"){let de=oe(re,J),fe=dw(ie.searchParams.get("days"),de);if(fe===null){ln(D,400,{error:`days must be an integer between 1 and ${de}`});return}ln(D,200,Vu(re,fe,J.activityLogsDir));return}if(O.method==="POST"&&ie.pathname==="/api/rules/choose-directory"){ln(D,200,await hs());return}if(O.method==="GET"&&ie.pathname==="/api/rules"){let de=Q(re,vs(J)),fe=new Map(de.rules.map((we)=>[we.name,we]));ln(D,200,{projectPath:J.cwd??process.cwd(),canPickDirectory:ys(process.platform,process.env),rulebooks:de.rulebooks.map((we)=>({source:we.source,spec:we.spec,name:we.name,version:we.version,rules:we.rules.flatMap((Ce)=>{let Se=fe.get(Ce);if(!Se)return[];return[{name:Se.name,command:Se.command,subcommand:Se.subcommand,block_args:Se.block_args,reason:Se.reason}]})})),errors:de.errors,warnings:de.warnings});return}if(O.method==="GET"&&ie.pathname==="/api/star/context"){ln(D,200,await(J.fetchStarContext??(()=>xw(re,{logsDir:J.activityLogsDir})))());return}if(O.method==="POST"&&ie.pathname==="/api/star"){let de=await(J.starRepo??hw)();ln(D,200,de.ok?{ok:!0}:{ok:!1,fallbackUrl:nw});return}if(O.method==="GET"&&ie.pathname==="/api/integrations"){ln(D,200,await(J.fetchIntegrations??(()=>vw(re)))());return}if(O.method==="GET"&&ie.pathname==="/api/health"){ln(D,200,await(J.fetchHealth??ww)());return}if(O.method==="POST"&&(ie.pathname==="/api/install"||ie.pathname==="/api/uninstall")){let de=await fr(O);if(!de.ok){ln(D,de.status,{errors:[de.error]});return}let fe=de.value?.target;if(typeof fe!=="string"||!$n.some((Ce)=>Ce.target===fe)){ln(D,400,{error:"unknown target"});return}let we=ie.pathname==="/api/install"?"install":"uninstall";ln(D,200,await(J.runIntegration??kw)(we,fe));return}ln(D,404,{error:"Not found"})}function vs(P){return{...P,cwd:P.cwd??process.cwd()}}function op(P,O){return P.dir??O.cwd??process.cwd()}function ip(P,O,D){if(!L(P,{...D,cwd:O}))return null;return`${h(O)} is the user policy, not a project policy; choose a project directory, or run the GUI from one`}function Xu(P,O){let D=h(P),j=Xb(D)?bt(D):{value:void 0,errors:[]},J=ue(j.value,O);return{projection:J.policy,diagnostics:[...j.errors,...J.diagnostics]}}async function Qu(P,O,D,j,J){let Y=op(j,J),re=j.revision,ie=await fr(O);if(!ie.ok)return ln(D,ie.status,{errors:[ie.error]}),null;let de=ie.value;if(typeof de?.revision!=="number")return ln(D,400,{errors:["revision must be a number"]}),null;if(de.revision!==re)return ln(D,409,{errors:[rw]}),null;let fe=ip(P,Y,J);if(fe)return ln(D,400,{errors:[fe]}),null;let we=aw(de.proposal,P.home);if(we.length>0)return ln(D,400,{errors:we}),null;return{dir:Y,proposal:de.proposal}}function aw(P,O){let D=lr(P,O);if(D.length>0)return D;return P?.audit===void 0?[]:[ow]}function lw(P,O,D){let j=h(P),J=po(O,E(O,D));try{return g(i(S(P,"project policy"),j),`${JSON.stringify(J,null,2)}
5759
- `),{path:j,errors:[]}}catch(Y){return{path:j,errors:[Y instanceof Error?Y.message:String(Y)]}}}function cw(P,O,D,j){let J=E(D,P.home),Y=k(P,vs(j)),re=_e({rules:Y.policy.rules,transparentWrappers:Y.policy.transparentWrappers,safety:$e(J.safety),worktreeMode:J.workflow.worktree_mode,destructiveCommandProtectionEnabled:J.destructive_command_protection.enabled,destructiveCommandRuleOverrides:J.destructive_command_protection.overrides,destructiveCommandAllowPaths:J.destructive_command_protection.allow_paths,secretProtection:{enabled:J.secret_protection.enabled,disabledRules:Fe(J.secret_protection.overrides),denyPaths:J.secret_protection.deny_paths,allowPaths:J.secret_protection.allow_paths}});return nr(O,{policySnapshot:re,cwd:j.cwd,userConfigDir:j.userConfigDir},P)}function dw(P,O){if(P===null)return Math.min(tw,O);let D=Number(P);if(!Number.isInteger(D)||D<1||D>O)return null;return D}function uw(P,O,D){if(O.searchParams.get("token")!==D)return!1;if(P.method!=="POST")return!0;return P.headers["x-cc-safety-net-token"]===D}var pw=1048576;async function fr(P){let O=[],D=0;for await(let j of P){let J=j;if(D+=J.byteLength,D>pw)return{ok:!1,status:413,error:"Request body is too large"};O.push(J)}try{return{ok:!0,value:JSON.parse(Buffer.concat(O).toString("utf-8")||"{}")}}catch(j){return{ok:!1,status:400,error:`Invalid JSON: ${j instanceof Error?j.message:String(j)}`}}}function fw(P,O){P.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),P.end(O)}function ln(P,O,D){P.writeHead(O,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),P.end(JSON.stringify(D))}function mw(P){return new Promise((O,D)=>{P.close((j)=>j?D(j):O())})}function gw(P){return new Promise((O)=>{let D=()=>{process.off("SIGINT",j),process.off("SIGTERM",j)},j=()=>{D(),P.close().then(O)};process.once("SIGINT",j),process.once("SIGTERM",j)})}function yw(P){let O=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",D=process.platform==="win32"?["/c","start","",P]:[P];return new Promise((j,J)=>{let Y=np(O,D,{detached:!0,stdio:"ignore"}),re=(de)=>{Y.off("spawn",ie),J(de)},ie=()=>{Y.off("error",re),Y.unref(),j()};Y.once("error",re),Y.once("spawn",ie)})}async function hw(P="gh",O=tp){return{ok:await Cw(P,["api","-X","PUT",`/user/starred/${bs}`],O)===0}}async function vw(P,O={}){let D=await Sr((J)=>Ot({environment:P,cwd:process.cwd(),openCodeVersion:J}).status!=="n/a",O.fetcher),j=bw(P,D);return{targets:En.map((J)=>{let Y=j.find((re)=>re.platform===J.id);return{target:J.id,label:mn(J.id),version:D.versions[J.id]??null,status:Y?.configured?"active":Y?.detected?"disabled":Y?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:D.version,nodeVersion:D.nodeVersion,platform:D.platform}}}function bw(P,O){return Dt(P,process.cwd(),{ampPluginListOutput:O.ampPluginListOutput,codexPluginListOutput:O.codexPluginListOutput,copilotCliVersion:O.versions["copilot-cli"],openCodeVersion:O.versions.opencode,openCodePluginListOutput:O.openCodePluginListOutput})}async function ww(P={}){let O=await(P.checkUpdates??Gn)();return{update:{latestVersion:O.latestVersion??null,updateAvailable:O.updateAvailable}}}var ep=Promise.resolve();function kw(P,O,D={}){let j=async()=>{let Y=[],{log:re,error:ie}=console;console.log=(...de)=>Y.push(de.map(String).join(" ")),console.error=console.log;try{return{ok:await ar(P,[],{selectTargets:async()=>[O],output:new ew({write(fe,we,Ce){Y.push(String(fe).replace(/\n$/,"")),Ce()}}),...D})===0,output:Y.join(`
5760
- `)}}finally{console.log=re,console.error=ie}},J=ep.then(j);return ep=J.then(()=>{return},()=>{return}),J}async function xw(P,O={}){let[D,j]=await Promise.all([Sw(O.fetchRepo),Promise.resolve(br(P,oe(P),O.logsDir).totalBlocked)]);return{starCount:D,blockedTotal:j}}function Cw(P,O,D){return new Promise((j)=>{let J=np(P,O,{stdio:"ignore",windowsHide:!0}),Y=!1,re=setTimeout(()=>{J.kill(),ie(null)},D),ie=(de)=>{if(Y)return;Y=!0,clearTimeout(re),j(de)};J.once("error",()=>ie(null)),J.once("close",ie)})}async function Sw(P=fetch){try{let O=await P(`https://api.github.com/repos/${bs}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(tp)});if(!O.ok)return null;let D=await O.json();return typeof D.stargazers_count==="number"?D.stargazers_count:null}catch{return null}}function Pw(P){if(P[0]!=="help")return!1;let O=P[1];if(!O)qi(),process.exit(0);if(tr(O))process.exit(0);console.error(`Unknown command: ${O}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var Rw={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),tr("hook",console.error),process.exit(1)},install:async(P)=>{process.exit(await ar("install",P))},update:async(P)=>{process.exit(await os(P))},uninstall:async(P)=>{process.exit(await ar("uninstall",P))},rule:async(P)=>{process.exit(await Gu(c(),P))},policy:async(P)=>{process.exit(await ru(c(),P))},status:async(P)=>{if(Dn(yn({label:"status"},P).errors))process.exit(1);Bu(c())},statusline:async(P)=>{let O=yn({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},P);if(O.errors.length===0&&O.flags.claudeCode){await gs(c());return}if(Dn(O.errors),!O.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");tr("statusline",console.error),process.exit(1)},doctor:async(P)=>{let O=Li(P);if(!O)process.exit(1);let D=await bc(c(),{json:O.json,skipUpdateCheck:O.skipUpdateCheck});process.exit(D)},logs:async(P)=>{process.exit(await Es(c(),P))},gui:async(P)=>{process.exit(await rp(P))},explain:async(P)=>{process.exit(await Tc(c(),P))}};async function Ew(P){let O=yn({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},P);if(Pw(P))return;let D=P[0],j=D?vr(D):void 0;if(O.help&&j&&j.name!=="rule")tr(j.name),process.exit(0);if(!D||O.help&&!j)qi(),process.exit(0);if(O.flags.version)Oc(),process.exit(0);if(j){await Rw[j.name](P.slice(1));return}if(D==="--statusline"){await gs(c());return}console.error(D.startsWith("-")?`Unknown option: ${D}`:`Unknown command: ${D}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Ew as runCli};
5762
+ `;var Wp='<script id="ccsn-data" type="application/json">';function zp(_,N=Jp){return N.replace(Wp,()=>Wp+JSON.stringify({token:_}).replaceAll("<","\\u003c"))}var Bs="kenryu42/cc-safety-net",gk=`https://github.com/${Bs}`,ef=1e4,yk=7,hk="The project draft directory changed; reload the draft before applying.",vk="audit settings are user scope only; remove the audit section from a project proposal";async function nf(_,N={}){let j=mn({label:"gui",booleans:{noOpen:["--no-open"]}},_),J=N.log??console.log,Y=N.error??console.error;if(j.errors.length>0){for(let ie of j.errors)Y(ie);return Y("Usage: cc-safety-net gui [--no-open]"),1}let re=await bk(c,N);if(J(`CC Safety Net policy GUI: ${re.url}`),!j.flags.noOpen)try{await(N.openBrowser??Ak)(re.url)}catch(ie){Y(`Failed to open browser: ${ie instanceof Error?ie.message:String(ie)}`),Y(`Open this URL manually: ${re.url}`)}if(N.keepAlive===!1)return await re.close(),0;return await Tk(re),0}async function bk(_,N={}){let j=uk(24).toString("base64url"),J={dir:null,revision:0},Y=fk((de,fe)=>{wk(_,de,fe,j,N,J)});await new Promise((de,fe)=>{Y.once("error",fe),Y.listen(0,"127.0.0.1",()=>{Y.off("error",fe),de()})});let ie=`http://127.0.0.1:${Y.address().port}`;return{origin:ie,token:j,url:`${ie}/?token=${encodeURIComponent(j)}`,close:()=>_k(Y)}}async function wk(_,N,j,J,Y,re){let ie=_(),de=new URL(N.url??"/","http://127.0.0.1");if(N.method==="GET"&&de.pathname==="/favicon.ico"){j.writeHead(204,{"cache-control":"no-store"}),j.end();return}if(!Pk(N,de,J)){on(j,403,{error:"Forbidden"});return}if(N.method==="GET"&&de.pathname==="/"){await Promise.resolve(Y.buildDocument?.()).then((fe)=>Ek(j,zp(J,fe)),(fe)=>on(j,500,{error:fe instanceof Error?fe.message:String(fe)}));return}if(N.method==="GET"&&de.pathname==="/api/policy"){let fe=Au(ie,Y),we=R(ie,Gs(Y));on(j,200,{...fe,configState:ze(we),...we.policyScopes?{projectPolicy:{path:h(Y.cwd??process.cwd()),weakenings:we.policyScopes.weakeningsIgnored?[]:we.policyScopes.weakenings}}:{},destructiveCommandRules:z,secretPatterns:ut,version:pn(),preview:fe.errors.length>0?null:Ge(fe.policy,ie.env)});return}if(N.method==="POST"&&de.pathname==="/api/policy/preview"){let fe=await Sr(N);if(!fe.ok){on(j,fe.status,{errors:[fe.error]});return}let we=Iu(ie,fe.value);on(j,we.errors.length>0?400:200,we);return}if(N.method==="POST"&&de.pathname==="/api/policy/explain"){let fe=await Sr(N);if(!fe.ok){on(j,fe.status,{errors:[fe.error]});return}let we=fe.value;if(we===null||typeof we.command!=="string"){on(j,400,{errors:["command must be a string"]});return}let ke=br(we.policy,ie.home);if(ke.length>0){on(j,400,{errors:ke});return}on(j,200,xk(ie,we.command,we.policy,Y));return}if(N.method==="POST"&&de.pathname==="/api/policy"){let fe=await Sr(N);if(!fe.ok){on(j,fe.status,{errors:[fe.error]});return}let we=Fn(ie,fe.value,Y);on(j,we.errors.length>0?400:200,we);return}if(N.method==="POST"&&de.pathname==="/api/reset"){on(j,200,Fn(ie,te,Y));return}if(N.method==="POST"&&de.pathname==="/api/repair"){on(j,200,Ou(ie,Y));return}if(N.method==="POST"&&de.pathname==="/api/policy/project/choose-directory"){let fe=await(Y.chooseDirectory??Us)();if("path"in fe)re.dir=fe.path,re.revision+=1;on(j,200,{cancelled:"cancelled"in fe,..."error"in fe?{error:fe.error}:{}});return}if(N.method==="GET"&&de.pathname==="/api/policy/project"){let fe=tf(re,Y),we=rf(ie,fe,Y),ke=we?{projection:{},diagnostics:[we]}:Yp(fe,ie.home),Re=wr(ie,Y);on(j,200,{path:h(fe),revision:re.revision,baseline:Re.baseline,userPolicyDiagnostics:Re.diagnostics,projection:ke.projection,projectionDiagnostics:ke.diagnostics,canPickDirectory:Ms(process.platform,process.env)});return}if(N.method==="POST"&&de.pathname==="/api/policy/project/diff"){let fe=await Zp(ie,N,j,re,Y);if(!fe)return;let we=Yp(fe.dir,ie.home),ke=wr(ie,Y).baseline,Re=ee(ke,ue(fe.proposal,ie.home).policy);on(j,200,{rows:Ro(ee(ke,we.projection).policy,Re.policy,!1),weakenings:Re.weakenings,existingFileDiagnostics:we.diagnostics});return}if(N.method==="POST"&&de.pathname==="/api/policy/project/apply"){let fe=await Zp(ie,N,j,re,Y);if(!fe)return;let we=Ck(fe.dir,fe.proposal,ie.home);on(j,we.errors.length>0?500:200,we);return}if(N.method==="GET"&&de.pathname==="/api/activity"){let fe=oe(ie,Y),we=Sk(de.searchParams.get("days"),fe);if(we===null){on(j,400,{error:`days must be an integer between 1 and ${fe}`});return}on(j,200,Bp(ie,we,Y.activityLogsDir));return}if(N.method==="POST"&&de.pathname==="/api/rules/choose-directory"){on(j,200,await Us());return}if(N.method==="GET"&&de.pathname==="/api/rules"){let fe=Q(ie,Gs(Y)),we=new Map(fe.rules.map((ke)=>[ke.name,ke]));on(j,200,{projectPath:Y.cwd??process.cwd(),canPickDirectory:Ms(process.platform,process.env),rulebooks:fe.rulebooks.map((ke)=>({source:ke.source,spec:ke.spec,name:ke.name,version:ke.version,rules:ke.rules.flatMap((Re)=>{let Te=we.get(Re);if(!Te)return[];return[{name:Te.name,command:Te.command,subcommand:Te.subcommand,block_args:Te.block_args,reason:Te.reason}]})})),errors:fe.errors,warnings:fe.warnings});return}if(N.method==="GET"&&de.pathname==="/api/star/context"){on(j,200,await(Y.fetchStarContext??(()=>Nk(ie,{logsDir:Y.activityLogsDir})))());return}if(N.method==="POST"&&de.pathname==="/api/star"){let fe=await(Y.starRepo??Ik)();on(j,200,fe.ok?{ok:!0}:{ok:!1,fallbackUrl:gk});return}if(N.method==="GET"&&de.pathname==="/api/integrations"){on(j,200,await(Y.fetchIntegrations??(()=>Ok(ie)))());return}if(N.method==="GET"&&de.pathname==="/api/health"){on(j,200,await(Y.fetchHealth??Dk)());return}if(N.method==="POST"&&(de.pathname==="/api/install"||de.pathname==="/api/uninstall")){let fe=await Sr(N);if(!fe.ok){on(j,fe.status,{errors:[fe.error]});return}let we=fe.value?.target;if(typeof we!=="string"||!On.some((Re)=>Re.target===we)){on(j,400,{error:"unknown target"});return}let ke=de.pathname==="/api/install"?"install":"uninstall";on(j,200,await(Y.runIntegration??Lk)(ke,we));return}on(j,404,{error:"Not found"})}function Gs(_){return{..._,cwd:_.cwd??process.cwd()}}function tf(_,N){return _.dir??N.cwd??process.cwd()}function rf(_,N,j){if(!A(_,{...j,cwd:N}))return null;return`${h(N)} is the user policy, not a project policy; choose a project directory, or run the GUI from one`}function Yp(_,N){let j=h(_),J=pk(j)?Ot(j):{value:void 0,errors:[]},Y=ue(J.value,N);return{projection:Y.policy,diagnostics:[...J.errors,...Y.diagnostics]}}async function Zp(_,N,j,J,Y){let re=tf(J,Y),ie=J.revision,de=await Sr(N);if(!de.ok)return on(j,de.status,{errors:[de.error]}),null;let fe=de.value;if(typeof fe?.revision!=="number")return on(j,400,{errors:["revision must be a number"]}),null;if(fe.revision!==ie)return on(j,409,{errors:[hk]}),null;let we=rf(_,re,Y);if(we)return on(j,400,{errors:[we]}),null;let ke=kk(fe.proposal,_.home);if(ke.length>0)return on(j,400,{errors:ke}),null;return{dir:re,proposal:fe.proposal}}function kk(_,N){let j=br(_,N);if(j.length>0)return j;return _?.audit===void 0?[]:[vk]}function Ck(_,N,j){let J=h(_),Y=Eo(N,k(N,j));try{return g(i(w(_,"project policy"),J),`${JSON.stringify(Y,null,2)}
5763
+ `),{path:J,errors:[]}}catch(re){return{path:J,errors:[re instanceof Error?re.message:String(re)]}}}function xk(_,N,j,J){let Y=k(j,_.home),re=R(_,Gs(J)),ie=Oe({rules:re.policy.rules,transparentWrappers:re.policy.transparentWrappers,commandTools:re.policy.commandTools,safety:Be(Y.safety),worktreeMode:Y.workflow.worktree_mode,destructiveCommandProtectionEnabled:Y.destructive_command_protection.enabled,destructiveCommandRuleOverrides:Y.destructive_command_protection.overrides,destructiveCommandAllowPaths:Y.destructive_command_protection.allow_paths,secretProtection:{enabled:Y.secret_protection.enabled,disabledRules:We(Y.secret_protection.overrides),denyPaths:Y.secret_protection.deny_paths,allowPaths:Y.secret_protection.allow_paths}});return pr(N,{policySnapshot:ie,cwd:J.cwd,userConfigDir:J.userConfigDir},_)}function Sk(_,N){if(_===null)return Math.min(yk,N);let j=Number(_);if(!Number.isInteger(j)||j<1||j>N)return null;return j}function Pk(_,N,j){if(N.searchParams.get("token")!==j)return!1;if(_.method!=="POST")return!0;return _.headers["x-cc-safety-net-token"]===j}var Rk=1048576;async function Sr(_){let N=[],j=0;for await(let J of _){let Y=J;if(j+=Y.byteLength,j>Rk)return{ok:!1,status:413,error:"Request body is too large"};N.push(Y)}try{return{ok:!0,value:JSON.parse(Buffer.concat(N).toString("utf-8")||"{}")}}catch(J){return{ok:!1,status:400,error:`Invalid JSON: ${J instanceof Error?J.message:String(J)}`}}}function Ek(_,N){_.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),_.end(N)}function on(_,N,j){_.writeHead(N,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),_.end(JSON.stringify(j))}function _k(_){return new Promise((N,j)=>{_.close((J)=>J?j(J):N())})}function Tk(_){return new Promise((N)=>{let j=()=>{process.off("SIGINT",J),process.off("SIGTERM",J)},J=()=>{j(),_.close().then(N)};process.once("SIGINT",J),process.once("SIGTERM",J)})}function Ak(_){let N=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",j=process.platform==="win32"?["/c","start","",_]:[_];return new Promise((J,Y)=>{let re=Qp(N,j,{detached:!0,stdio:"ignore"}),ie=(fe)=>{re.off("spawn",de),Y(fe)},de=()=>{re.off("error",ie),re.unref(),J()};re.once("error",ie),re.once("spawn",de)})}async function Ik(_="gh",N=ef){return{ok:await jk(_,["api","-X","PUT",`/user/starred/${Bs}`],N)===0}}async function Ok(_,N={}){let j=await Lr((Y)=>qt({environment:_,cwd:process.cwd(),openCodeVersion:Y}).status!=="n/a",N.fetcher),J=$k(_,j);return{targets:Rn.map((Y)=>{let re=J.find((ie)=>ie.platform===Y.id);return{target:Y.id,label:cn(Y.id),version:j.versions[Y.id]??null,status:re?.configured?"active":re?.detected?"disabled":re?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:j.version,nodeVersion:j.nodeVersion,platform:j.platform}}}function $k(_,N){return Vt(_,process.cwd(),{ampPluginListOutput:N.ampPluginListOutput,codexPluginListOutput:N.codexPluginListOutput,copilotCliVersion:N.versions["copilot-cli"],openCodeVersion:N.versions.opencode,openCodePluginListOutput:N.openCodePluginListOutput})}async function Dk(_={}){let N=await(_.checkUpdates??Gn)();return{update:{latestVersion:N.latestVersion??null,updateAvailable:N.updateAvailable}}}var Xp=Promise.resolve();function Lk(_,N,j={}){let J=async()=>{let re=[],{log:ie,error:de}=console;console.log=(...fe)=>re.push(fe.map(String).join(" ")),console.error=console.log;try{return{ok:await vr(_,[],{selectTargets:async()=>[N],output:new mk({write(we,ke,Re){re.push(String(we).replace(/\n$/,"")),Re()}}),...j})===0,output:re.join(`
5764
+ `)}}finally{console.log=ie,console.error=de}},Y=Xp.then(J);return Xp=Y.then(()=>{return},()=>{return}),Y}async function Nk(_,N={}){let[j,J]=await Promise.all([Hk(N.fetchRepo),Promise.resolve(Ar(_,oe(_),N.logsDir).totalBlocked)]);return{starCount:j,blockedTotal:J}}function jk(_,N,j){return new Promise((J)=>{let Y=Qp(_,N,{stdio:"ignore",windowsHide:!0}),re=!1,ie=setTimeout(()=>{Y.kill(),de(null)},j),de=(fe)=>{if(re)return;re=!0,clearTimeout(ie),J(fe)};Y.once("error",()=>de(null)),Y.once("close",de)})}async function Hk(_=fetch){try{let N=await _(`https://api.github.com/repos/${Bs}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(ef)});if(!N.ok)return null;let j=await N.json();return typeof j.stargazers_count==="number"?j.stargazers_count:null}catch{return null}}function Fk(_){if(_[0]!=="help")return!1;let N=_[1];if(!N)fs(),process.exit(0);if(fr(N))process.exit(0);console.error(`Unknown command: ${N}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var Mk={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),fr("hook",console.error),process.exit(1)},install:async(_)=>{process.exit(await vr("install",_))},update:async(_)=>{process.exit(await _s(_))},uninstall:async(_)=>{process.exit(await vr("uninstall",_))},rule:async(_)=>{process.exit(await Mp(c(),_))},policy:async(_)=>{process.exit(await Nu(c(),_))},status:async(_)=>{if($n(mn({label:"status"},_).errors))process.exit(1);Gp(c())},statusline:async(_)=>{let N=mn({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},_);if(N.errors.length===0&&N.flags.claudeCode){await Fs(c());return}if($n(N.errors),!N.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");fr("statusline",console.error),process.exit(1)},doctor:async(_)=>{let N=is(_);if(!N)process.exit(1);let j=await Yc(c(),{json:N.json,skipUpdateCheck:N.skipUpdateCheck});process.exit(j)},logs:async(_)=>{process.exit(await Zs(c(),_))},gui:async(_)=>{process.exit(await nf(_))},explain:async(_)=>{process.exit(await ad(c(),_))}};async function Uk(_){let N=mn({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},_);if(Fk(_))return;let j=_[0],J=j?Tr(j):void 0;if(N.help&&J&&J.name!=="rule")fr(J.name),process.exit(0);if(!j||N.help&&!J)fs(),process.exit(0);if(N.flags.version)dd(),process.exit(0);if(J){await Mk[J.name](_.slice(1));return}if(j==="--statusline"){await Fs(c());return}console.error(j.startsWith("-")?`Unknown option: ${j}`:`Unknown command: ${j}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Uk as runCli};