cc-safety-net 2.7.0 → 2.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/amp/cc-safety-net/index.ts +49 -49
- package/dist/api.js +1 -1
- package/dist/bin/hook.js +49 -49
- package/dist/chunks/{index-tkzcnve3.js → index-09qa5y78.js} +1 -1
- package/dist/chunks/{index-b4k2tzcq.js → index-38xbyz1h.js} +2 -2
- package/dist/chunks/index-3xe319mt.js +53 -0
- package/dist/chunks/{index-sdtdk6k2.js → index-7rakvb2n.js} +1 -1
- package/dist/chunks/{index-d5x57kmb.js → index-bn4xwa1w.js} +2 -2
- package/dist/chunks/index-s5gfmv1q.js +2 -0
- package/dist/cli.js +49 -49
- package/dist/deepseek-harness/index.js +1 -1
- package/dist/index.js +4 -4
- package/dist/openclaw/cc-safety-net/index.js +49 -49
- package/dist/openclaw/cc-safety-net/openclaw.plugin.json +1 -1
- package/dist/openclaw/cc-safety-net/package.json +1 -1
- package/dist/pi/index.js +1 -1
- package/package.json +5 -3
- package/dist/chunks/index-e31kf4tz.js +0 -53
- package/dist/chunks/index-fe2vhtvz.js +0 -2
package/dist/cli.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import{l,a,Ve,dt,A,Pt,pt,c,r,ft,O,k,xe,At,h,je,
|
|
1
|
+
import{l,a,Ve,dt,A,Pt,pt,c,r,ft,O,k,xe,At,h,je,b,gt,d,i,R,s,pe,o,x,we,q,Ot,Dt,m,Ce,Ee,Nt,j,re,fe,T,Lt,D,S,me,K,p,L,oe,ht,yt,U,P,M,ke,Re,Ke,ge,f,e,Je,Ue,Ye,Te,vt,bt,he,He,ye,Ze,ie,J,Xe,Pe,Y,xt,Z,se,ae,ve,St,wt,_,N,Qe,Ct,tt,w,nt,Ge,_e,C,t,ce,Ae,E,H,y,F,Mt,rt,ot,g,G}from"./chunks/index-3xe319mt.js";import{ct}from"./chunks/index-7rakvb2n.js";import{it,Oe}from"./chunks/index-09qa5y78.js";import{v,B,u,We,n,De,lt,Rt,ze}from"./chunks/index-s5gfmv1q.js";import"./chunks/index-38xbyz1h.js";import{ue,Q,ut,W,z}from"./chunks/index-bn4xwa1w.js";var vf=["-h","--help"];function fn(I,V){let X=Object.entries(I.booleans??{}),ee=Object.entries(I.values??{}),ne=Object.entries(I.lists??{}),te=Object.fromEntries(X.map(([Le])=>[Le,!1])),le={},de=Object.fromEntries(ne.map(([Le])=>[Le,[]])),be=[],Se=[],Ie=!1,$e=-1;for(let[Le,Ne]of V.entries()){if(Le<=$e)continue;if(Ne==="--"){be.push(...V.slice(Le+1));break}if(vf.includes(Ne)){Ie=!0;continue}let Fe=X.find(([,tn])=>tn.includes(Ne));if(Fe){te[Fe[0]]=!0;continue}let Be=ee.find(([,tn])=>tn.includes(Ne));if(Be){let tn=V[Le+1];if(tn===void 0||tn.startsWith("-")){Se.push(`${Ne} requires a value`);continue}le[Be[0]]=tn,$e=Le+1;continue}let Me=ne.find(([,tn])=>tn.includes(Ne));if(Me){let tn=V.slice(Le+1),en=tn.findIndex((ln)=>ln.startsWith("-")),on=tn.slice(0,en===-1?tn.length:en);if(on.length===0){Se.push(`${Ne} requires at least one value`);continue}de[Me[0]]=[...de[Me[0]]??[],...on],$e=Le+on.length;continue}if(Ne.startsWith("-")){Se.push(`Unknown option for ${I.label}: ${Ne}`);continue}if(I.positionals==="tail"){be.push(...V.slice(Le));break}be.push(Ne)}if(I.positionals!=="list"&&I.positionals!=="tail")Se.push(...be.map((Le)=>`Unexpected argument for ${I.label}: ${Le}`));return{flags:te,values:le,lists:de,positionals:be,help:Ie,errors:Se}}function In(I){for(let V of I)console.error(V);return I.length>0}import{readdirSync as Sf,statSync as Qs,unlinkSync as Rf}from"node:fs";import{basename as ea,dirname as Ef,isAbsolute as Tf,join as Af,relative as _f,resolve as If,sep as Of}from"node:path";var Ys=(I)=>{let V=Date.now()-new Date(I).getTime();if(!Number.isFinite(V))return"";let X=Math.floor(V/60000),ee=Math.floor(X/60),ne=Math.floor(ee/24);if(ne>0)return`${ne}d ago`;if(ee>0)return`${ee}h ago`;if(X>0)return`${X}m ago`;return"just now"},Jo=(I)=>{let V=(I??"").trim().split(/\s+/).filter((ne)=>ne&&!/^[A-Za-z_][A-Za-z0-9_]*=/.test(ne)),X=V[0]?.split("/").pop();if(!X)return null;let ee=V[1];return ee&&/^[a-z][a-z0-9-]*$/.test(ee)?`${X} ${ee}`:X};function Zs(I){let V=(ne)=>`${ne.sessionId}
|
|
2
2
|
${Jo(ne.segment||ne.command)}`,X=I.filter((ne)=>ne.decision!=="allow"),ee=X.filter((ne)=>ne.sessionId).reduce((ne,te)=>ne.set(V(te),(ne.get(V(te))??0)+1),new Map);return new Set(X.filter((ne)=>ne.failureStage||(ee.get(V(ne))??0)>=2))}import{existsSync as bf,readdirSync as wf,readFileSync as kf}from"node:fs";import{join as Cf}from"node:path";function Jn(I,V){try{return wf(I,{withFileTypes:!0,encoding:"utf8"}).flatMap((X)=>{let ee=Cf(I,X.name);if(X.isDirectory())return Jn(ee,V);if(X.name.endsWith(".jsonl"))return[ee];return[]})}catch{if(V&&bf(I))V.count++;return[]}}var xf=["segment","reason","sessionId","decision","agent","ruleId","failureStage"];function Pf(I){if(!I||typeof I!=="object"||Array.isArray(I))return!1;let V=I;if(typeof V.ts!=="string"||typeof V.command!=="string")return!1;return xf.every((X)=>V[X]===void 0||typeof V[X]==="string")}function Ft(I,V){try{return kf(I,"utf-8").split(`
|
|
3
|
-
`).filter(Boolean).flatMap((X)=>{try{let ee=JSON.parse(X);if(!Pf(ee)){if(V)V.count++;return[]}return[ee]}catch{if(V)V.count++;return[]}})}catch{if(V)V.count++;return[]}}function mn(I){return Array.from(I,(V)=>{let X=V.charCodeAt(0);if(X<=31||X>=127&&X<=159)return`\\x${X.toString(16).padStart(2,"0")}`;return V}).join("")}function $f(I,V){let X=ue(I),ee=fn({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},V);if(In(ee.errors))return null;if(ee.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(ee.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let ne=ee.values.limit===void 0?20:Xs(ee.values.limit);if(ne===null)return console.error("--limit must be a positive number"),null;let te=ee.values.since===void 0?Math.min(30,X):Xs(ee.values.since);if(te===null||te>X)return console.error(`--since must be a positive number of days no greater than ${X}`),null;let le={limit:ne,limitExplicit:ee.values.limit!==void 0,since:te,sinceExplicit:ee.values.since!==void 0,all:ee.flags.all,json:ee.flags.json,suspect:ee.flags.suspect,pruneLegacy:ee.flags.pruneLegacy,dryRun:ee.flags.dryRun,id:ee.values.id,agent:ee.values.agent,rule:ee.values.rule,session:ee.values.session,project:ee.values.project===void 0?void 0:If(ee.values.project)};if(le.id&&(le.agent!==void 0||le.rule!==void 0||le.session!==void 0||le.project!==void 0||le.suspect||le.sinceExplicit||le.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(le.pruneLegacy&&(le.id!==void 0||le.agent!==void 0||le.rule!==void 0||le.session!==void 0||le.project!==void 0||le.suspect||le.all||le.sinceExplicit||le.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(le.dryRun&&!le.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return le}async function na(I,V,X={}){let ee=$f(I,V);if(!ee)return 1;let ne=X.logsDir??W(I);if(ee.pruneLegacy)return Df(ne,ee.json,ee.dryRun);if(!ne)return console.log(ee.json?"[]":ee.id?`No retained audit log entry found for id ${mn(ee.id)}.`:"No audit log entries found."),0;Q(I,ne);let te={count:0},le=Jn(ne,te).flatMap(($e)=>Ft($e,te).map((Le)=>({entry:Le,file:$e})));if(te.count>0)console.error(`warning: ${te.count} audit log ${te.count===1?"source":"sources"} could not be read; these results are incomplete`);if(ee.id)return Ff(le,ee,X.timeZone);let de=Date.now()-ee.since*24*60*60*1000,
|
|
4
|
-
`)}function ra(I,V){let X=new Date(I);if(Number.isNaN(X.getTime()))return I;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:V}).format(X)}function Xs(I){let V=Number(I);return Number.isFinite(V)&&V>0?V:null}var oa={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 ia={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:"--shell",argument:"<auto|posix|powershell>",description:"Parse the command as this shell (default: auto)"},{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"',"cc-safety-net explain --shell posix 'rmdir /s /q d:\\'"]};var sa={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 zo=["npx","--offline","--no-install","@deepseek-ai/dsh","--version"],aa=["cursor-agent","--version"],la=[{id:"antigravity-cli",displayName:"Antigravity CLI",runtime:{flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",runtime:{displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",runtime:{flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",runtime:{flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",runtime:{flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",runtime:{flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",runtime:{flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",runtime:{flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",install:{flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",install:{flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",install:{flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",runtime:{flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"deepseek-harness",displayName:"DeepSeek Harness",install:{flag:"--deepseek-harness",artifactKind:"package",probeCommand:zo}},{id:"devin",displayName:"Devin CLI",runtime:{flags:["-dv","--devin"],description:"Run as Devin CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--devin",artifactKind:"hook config",probeCommand:["devin","--version"]}},{id:"droid",displayName:"Factory Droid",runtime:{flags:["-fd","--droid"],description:"Run as Factory Droid PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--droid",artifactKind:"hook config",probeCommand:["droid","--version"]}},{id:"amp",displayName:"Amp Code",install:{flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Wo=la.slice().sort((I,V)=>I.displayName.localeCompare(V.displayName,"en")),Or=Wo.map((I)=>I.id).sort((I,V)=>Number(V==="claude-code")-Number(I==="claude-code")),ir=Wo.filter((I)=>("runtime"in I)).map((I)=>({id:I.id,displayName:"displayName"in I.runtime?I.runtime.displayName:I.displayName,flags:I.runtime.flags,legacyFlags:"legacyFlags"in I.runtime?I.runtime.legacyFlags:[],description:I.runtime.description,legacyTopLevelFlags:I.runtime.legacyTopLevelFlags})),xn=Wo.map((I)=>({id:I.id,...I.install})),qf=Object.fromEntries(la.map((I)=>[I.id,I.displayName]));function cn(I){return qf[I]}var Vf=ir.map((I)=>({flags:I.flags.join(", "),description:I.description})),Kf=ir.flatMap((I)=>I.flags.map((V)=>`cc-safety-net hook ${V}`)),ca={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Vf,{flags:"-h, --help",description:"Show this help"}],examples:Kf};var da={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...xn.map((I)=>({flags:I.flag,description:`Install ${cn(I.id)} ${I.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...xn.map((I)=>`cc-safety-net install ${I.flag}`)]},ua={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...xn.map((I)=>({flags:I.flag,description:`Uninstall ${cn(I.id)} ${I.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...xn.map((I)=>`cc-safety-net uninstall ${I.flag}`)]},pa={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 fa={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var $r={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var Yo=[{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"}],Zo=["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"],Ht={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"},...Yo.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",...Zo,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var ma={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 ga={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 Dr=[ma,oa,fa,ia,Ht,$r,da,pa,ua,ca,sa,ga];function Jf(I){return I.aliases??[]}function Nr(I){let V=I.toLowerCase();return Dr.find((X)=>X.name.toLowerCase()===V||Jf(X).some((ee)=>ee.toLowerCase()===V))}import{existsSync as Dy}from"node:fs";import{basename as zf}from"node:path";function Lr(I,V=7,X=W(I)){let ee=Date.now()-V*24*60*60*1000,ne=[],te=new Set,le=0,de,ve,Se,Ie;if(X)Q(I,X);let $e={count:0},Le=X?Jn(X,$e):[];for(let Fe of Le)for(let Be of Ft(Fe,$e)){if(Be.decision==="allow")continue;let Me=new Date(Be.ts).getTime();if(Me>=ee){if(le++,te.add(Be.sessionId??zf(Fe,".jsonl")),ve===void 0||Me<=ve)de=Be.ts,ve=Me;if(Ie===void 0||Me>Ie)Se=Be.ts,Ie=Me;Wf(ne,Be,Me)}}let Ne=ne.map((Fe)=>({timestamp:Fe.ts,command:Fe.command,reason:Fe.reason,relativeTime:Ys(new Date(Fe.ts))}));return{totalBlocked:le,sessionCount:te.size,recentEntries:Ne,oldestEntry:de,newestEntry:Se,unreadable:$e.count}}function Wf(I,V,X){let ee=I.findIndex((ne)=>X>new Date(ne.ts).getTime());if(ee===-1){if(I.length<3)I.push(V);return}if(I.splice(ee,0,V),I.length>3)I.pop()}import{dirname as am}from"node:path";import{dirname as Yf,join as Zf,resolve as Xf}from"node:path";var Qf="config.json";function yn(I,V,X,ee){x(em(I),`${JSON.stringify(V,null,2)}
|
|
5
|
-
`,X,ee)}function em(I){return typeof I==="string"?pe(I):I}function Qo(I){return{errors:he(tm(I),": "," "),ruleNames:new Set(Ze(I).map((V)=>V.toLowerCase()))}}var nm="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",ha="must match pattern (letters, numbers, hyphens, underscores)";function tm(I){if(!ya(I))return[e([],"Config must be an object")];return[...I.version===1?[]:[e(["version"],"must be 1")],...rm(I.rules)]}function rm(I){if(I===void 0)return[];if(!Array.isArray(I))return[e(["rules"],"must be an array")];return[...I.flatMap((V,X)=>ya(V)?om(V,["rules",X]):[e(["rules",X],"must be an object")]),...Je(I)]}function om(I,V){return[...Xo(I.name,[...V,"name"],"required string",m,nm),...Xo(I.command,[...V,"command"],"required string",P,ha),...I.subcommand===void 0?[]:Xo(I.subcommand,[...V,"subcommand"],"must be a string if provided",P,ha),...im(I.block_args,[...V,"block_args"]),...sm(I.reason,[...V,"reason"]),...I.intent===void 0||He(I.intent)?[]:[e([...V,"intent"],Ue)]]}function Xo(I,V,X,ee,ne){if(typeof I!=="string")return[e(V,X)];return ee.test(I)?[]:[e(V,ne)]}function im(I,V){if(!Array.isArray(I))return[e(V,"required array")];if(I.length===0)return[e(V,"must have at least one element")];return I.flatMap((X,ee)=>{if(typeof X!=="string")return[e([...V,ee],"must be a string")];return X===""?[e([...V,ee],"must not be empty")]:[]})}function sm(I,V){if(typeof I!=="string")return[e(V,"required string")];if(I==="")return[e(V,"must not be empty")];return I.length>M?[e(V,`must be at most ${M} characters`)]:[]}function ya(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}function ei(I){let V=va(I);if(!V.ok)return V.result;return Qo(V.parsed)}function va(I){let V=[],X=new Set;try{let ee=typeof I==="string"?pe(I):I,ne=o(ee);if(ne===null)return V.push(`File not found: ${ee.path}`),{ok:!1,result:{errors:V,ruleNames:X}};if(!ne.trim())return V.push("Config file is empty"),{ok:!1,result:{errors:V,ruleNames:X}};return{ok:!0,parsed:JSON.parse(ne)}}catch(ee){if(ee instanceof i)return V.push(ee.message),{ok:!1,result:{errors:V,ruleNames:X}};let ne=ee instanceof Error?ee.message:String(ee);return V.push(ee instanceof SyntaxError?"Invalid JSON":ne),{ok:!1,result:{errors:V,ruleNames:X}}}}function Ut(I){return Xf(I,".safety-net.json")}function Fn(I){let V=va(I);if(!V.ok)return V.result;let X=bt(V.parsed);return{errors:X.errors,ruleNames:X.sources}}function Bt(I,V={}){return Zf(Yf(me(I,V)),Qf)}function ba(I,V,X){let ee;try{if(o(V)===null)return{path:I,exists:!1,valid:!1,ruleCount:0};ee=Fn(V),ee.errors.push(...J(I,X))}catch(ne){if(!(ne instanceof i))throw ne;ee={errors:[ne.message],ruleNames:new Set}}return{path:I,exists:!0,valid:ee.errors.length===0,ruleCount:ee.ruleNames.size,...ee.errors.length>0?{errors:ee.errors}:{}}}function lm(I,V){return{source:V,name:I.name,command:I.command,subcommand:I.subcommand,blockArgs:[...I.block_args],reason:I.reason}}function wa(I,V){let X=K(I),ee=D(V),ne=am(X),te=ie(I,{cwd:V,userConfigPath:X,projectConfigPath:ee,userConfigDir:ne}),le=oe(I,{cwd:V,userConfigPath:X,projectConfigPath:ee,userConfigDir:ne}),de=new Map(te.rulebooks.flatMap((ve)=>ve.rules.map((Se)=>[Se,ve.source])));return{userConfig:ba(X,le.userConfigTarget,le.userScope),projectConfig:ba(ee,le.projectConfigTarget,le.projectScope),effectiveRules:te.rules.map((ve)=>lm(ve,de.get(ve.name)??"project"))}}var cm=[{flag:r.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:r.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:r.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:r.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:r.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:r.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:r.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:r.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"},{flag:r.projectTightenOnly,description:"Ignore project policy settings that weaken the user policy",defaultBehavior:"off"}];function ka(I){return[...cm.map((V)=>({name:V.flag.name,value:xe(V.flag,I.env),isSet:At(V.flag,I.env),legacyName:V.flag.legacyName,legacyValue:V.flag.legacyName?I.env.get(V.flag.legacyName):void 0,legacyIsSet:V.flag.legacyName?I.env.get(V.flag.legacyName)!==void 0:void 0,description:V.description,defaultBehavior:V.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:I.env.get("CC_SAFETY_NET_HOME"),isSet:I.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var Ca={error:0,warning:1,info:2},dm=["policy","config","audit"];function um(I){return I.map((V)=>{if(V==="ownership")return"is not owned by the current user";if(V==="permissions")return"has unsafe permissions";if(V==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var pm=[{derive:(I)=>I.hooks.length>0&&I.hooks.every((V)=>!V.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(I)=>I.hooks.filter((V)=>V.inspectionStatus==="failed").map((V)=>{let X=cn(V.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${X} inspection failed`,detail:`Doctor could not verify the ${X} integration configuration.`,fixHint:`Correct the reported ${X} configuration error, then run \`cc-safety-net doctor\` again.`,integration:V.platform}})},{derive:(I)=>I.userConfig.exists&&!I.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:I.userConfig.path}]:[]},{derive:(I)=>I.projectConfig.exists&&!I.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:I.projectConfig.path}]:[]},{derive:(I)=>I.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${I.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:(I)=>I.v2Leftovers&&I.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: ${I.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(I)=>I.legacyConfigs&&I.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: ${I.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:(I)=>{let V=I.environment.find((X)=>X.name==="CC_SAFETY_NET_AUDIT_SCOPE");return ft(V?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...dm.map((I)=>({derive:(V)=>V.posture.directories.filter((X)=>X.kind===I&&X.status==="unsafe").map((X)=>({checkId:`posture.${I}-directory-unsafe`,severity:"error",title:`${I[0]?.toUpperCase()}${I.slice(1)} directory is unsafe`,detail:`The ${I} directory ${um(X.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...X.path?{path:X.path}:{}}))})),{derive:(I)=>{let V=[...I.effectiveSafety.weakenedRuleOverrides].sort();return V.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${V.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${V.join(", ")}.`}]:[]}}];function xa(I){return pm.flatMap((V,X)=>V.derive(I).map((ee,ne)=>({finding:ee,catalogOrder:X,occurrence:ne}))).sort((V,X)=>Ca[V.finding.severity]-Ca[X.finding.severity]||V.catalogOrder-X.catalogOrder||V.occurrence-X.occurrence).map((V)=>V.finding)}function On(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var fm=(I)=>On()?`\x1B[32m${I}\x1B[0m`:I,mm=(I)=>On()?`\x1B[33m${I}\x1B[0m`:I,gm=(I)=>On()?`\x1B[34m${I}\x1B[0m`:I,hm=(I)=>On()?`\x1B[36m${I}\x1B[0m`:I,ym=(I)=>On()?`\x1B[31m${I}\x1B[0m`:I,vm=(I)=>On()?`\x1B[2m${I}\x1B[0m`:I,bm=(I)=>On()?`\x1B[1m${I}\x1B[0m`:I,qe={green:fm,yellow:mm,blue:gm,cyan:hm,red:ym,dim:vm,bold:bm},wm="\x1B[0m",km=[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 Cm(I){let V=I;return()=>(V=(V*1664525+1013904223)%4294967296,V/4294967296)}function xm(I){let V=[...km],X=Cm(I);for(let ee=V.length-1;ee>0;ee--){let ne=Math.floor(X()*(ee+1)),te=V[ee];V[ee]=V[ne],V[ne]=te}return V}function Pm(I,V=0){if(!On())return"";let X=xm(V);return`\x1B[38;5;${X[I%X.length]}m`}function Pa(I,V,X=0){if(!On())return`"${I}"`;return`${Pm(V,X)}"${I}"${wm}`}function jr(I){return I==="default"?"built-in default":`${I} policy`}var Sm=new RegExp("\x1B\\[[0-9;]*m","g"),ni=(I)=>I.replace(Sm,"").length;function zn(I){let V=(I.headers??I.rows[0]??[]).map((le,de)=>{let ve=Math.max(...I.rows.map((Se)=>ni(Se[de]??"")));return Math.max(ni(le),ve)}),X=(le,de)=>le+" ".repeat(Math.max(0,de-ni(le))),ee=(le,de)=>de[0]+V.map((ve)=>le.repeat(ve+2)).join(de[1])+de[2],ne=(le)=>`│ ${le.map((de,ve)=>X(de,V[ve]??0)).join(" │ ")} │`,te=I.headers?[` ${ne(I.headers)}`,` ${ee("─",["├","┼","┤"])}`]:[];return[` ${ee("─",["┌","┬","┐"])}`,...te,...I.rows.map((le)=>` ${ne(le)}`),` ${ee("─",["└","┴","┘"])}`].join(`
|
|
3
|
+
`).filter(Boolean).flatMap((X)=>{try{let ee=JSON.parse(X);if(!Pf(ee)){if(V)V.count++;return[]}return[ee]}catch{if(V)V.count++;return[]}})}catch{if(V)V.count++;return[]}}function mn(I){return Array.from(I,(V)=>{let X=V.charCodeAt(0);if(X<=31||X>=127&&X<=159)return`\\x${X.toString(16).padStart(2,"0")}`;return V}).join("")}function $f(I,V){let X=ue(I),ee=fn({label:"logs",booleans:{all:["--all"],suspect:["--suspect"],json:["--json"],pruneLegacy:["--prune-legacy"],dryRun:["--dry-run"]},values:{id:["--id"],limit:["--limit"],since:["--since"],agent:["--agent"],rule:["--rule"],session:["--session"],project:["--project"]}},V);if(In(ee.errors))return null;if(ee.values.id!==void 0&&!/^[a-f0-9]{16}$/.test(ee.values.id))return console.error("--id must be 16 hexadecimal characters"),null;let ne=ee.values.limit===void 0?20:Xs(ee.values.limit);if(ne===null)return console.error("--limit must be a positive number"),null;let te=ee.values.since===void 0?Math.min(30,X):Xs(ee.values.since);if(te===null||te>X)return console.error(`--since must be a positive number of days no greater than ${X}`),null;let le={limit:ne,limitExplicit:ee.values.limit!==void 0,since:te,sinceExplicit:ee.values.since!==void 0,all:ee.flags.all,json:ee.flags.json,suspect:ee.flags.suspect,pruneLegacy:ee.flags.pruneLegacy,dryRun:ee.flags.dryRun,id:ee.values.id,agent:ee.values.agent,rule:ee.values.rule,session:ee.values.session,project:ee.values.project===void 0?void 0:If(ee.values.project)};if(le.id&&(le.agent!==void 0||le.rule!==void 0||le.session!==void 0||le.project!==void 0||le.suspect||le.sinceExplicit||le.limitExplicit))return console.error("--id cannot be combined with --agent, --rule, --session, --project, --suspect, --since, or --limit"),null;if(le.pruneLegacy&&(le.id!==void 0||le.agent!==void 0||le.rule!==void 0||le.session!==void 0||le.project!==void 0||le.suspect||le.all||le.sinceExplicit||le.limitExplicit))return console.error("--prune-legacy cannot be combined with --id, --agent, --rule, --session, --project, --suspect, --all, --since, or --limit"),null;if(le.dryRun&&!le.pruneLegacy)return console.error("--dry-run requires --prune-legacy"),null;return le}async function na(I,V,X={}){let ee=$f(I,V);if(!ee)return 1;let ne=X.logsDir??W(I);if(ee.pruneLegacy)return Df(ne,ee.json,ee.dryRun);if(!ne)return console.log(ee.json?"[]":ee.id?`No retained audit log entry found for id ${mn(ee.id)}.`:"No audit log entries found."),0;Q(I,ne);let te={count:0},le=Jn(ne,te).flatMap(($e)=>Ft($e,te).map((Le)=>({entry:Le,file:$e})));if(te.count>0)console.error(`warning: ${te.count} audit log ${te.count===1?"source":"sources"} could not be read; these results are incomplete`);if(ee.id)return Ff(le,ee,X.timeZone);let de=Date.now()-ee.since*24*60*60*1000,be=le.filter(($e)=>Hf($e,ee,ne,de)),Se=ee.suspect?Zs(be.map(($e)=>$e.entry)):null,Ie=(Se?be.filter(($e)=>Se.has($e.entry)):be).sort(($e,Le)=>Date.parse(Le.entry.ts)-Date.parse($e.entry.ts)).slice(0,ee.limit);if(ee.json)return console.log(JSON.stringify(Ie.map(($e)=>$e.entry),null,2)),0;if(Ie.length===0)return console.log("No audit log entries found."),0;for(let $e of Ie)console.log(Bf($e.entry,X.timeZone));return 0}function Df(I,V,X){let ee=I?Lf(I).map((de)=>Af(I,de)):[];if(X)return Nf(ee,V);let ne=[],te=0,le=0;for(let de of ee){let be=Qs(de,{throwIfNoEntry:!1})?.size??0,Se=jf(de);if(Se){ne.push(`${ea(de)}: ${Se}`);continue}te++,le+=be}if(V)return console.log(JSON.stringify({removedFiles:te,removedBytes:le,failedFiles:ne.length})),ne.length===0?0:1;console.log(te===0&&ne.length===0?"No legacy audit log files found.":`Removed ${te} legacy audit log ${te===1?"file":"files"} (${ta(le)}).`);for(let de of ne)console.error(`Could not remove ${mn(de)}`);if(console.log("Nested v2 audit logs were not changed."),te>0)console.log("This deletion cannot be undone.");return ne.length===0?0:1}function Nf(I,V){let X=I.reduce((ee,ne)=>ee+(Qs(ne,{throwIfNoEntry:!1})?.size??0),0);if(V)return console.log(JSON.stringify({dryRun:!0,files:I.length,bytes:X})),0;if(console.log(I.length===0?"No legacy audit log files found.":`Would remove ${I.length} legacy audit log ${I.length===1?"file":"files"} (${ta(X)}).`),console.log("Nested v2 audit logs are not included."),I.length>0)console.log("Run the same command without --dry-run to delete them.");return 0}function Lf(I){try{return Sf(I,{withFileTypes:!0}).filter((V)=>V.isFile()&&V.name.endsWith(".jsonl")).map((V)=>V.name)}catch{return[]}}function jf(I){try{return Rf(I),null}catch(V){return V instanceof Error?V.message:String(V)}}function ta(I){let V=["B","KiB","MiB","GiB"],X=Math.min(Math.floor(Math.log2(Math.max(I,1))/10),V.length-1);return`${Math.round(I/1024**X*10)/10} ${V[X]}`}function Ff(I,V,X){let ee=I.filter((te)=>te.entry.id===V.id);if(ee.length>1)return console.error(`Multiple audit log entries found for id ${mn(V.id??"")}.`),1;if(V.json)return console.log(JSON.stringify(ee.map((te)=>te.entry),null,2)),0;let ne=ee[0];if(!ne)return console.log(`No retained audit log entry found for id ${mn(V.id??"")}.`),0;return console.log(Gf(ne.entry,X)),0}function Hf(I,V,X,ee){if(!V.all&&I.entry.decision==="allow")return!1;if(Date.parse(I.entry.ts)<ee)return!1;if(V.agent!==void 0&&I.entry.agent!==V.agent)return!1;if(V.rule!==void 0&&I.entry.ruleId!==V.rule)return!1;if(V.session!==void 0&&!Mf(I,X,V.session))return!1;if(V.project!==void 0&&!Uf(I.entry.cwd,V.project))return!1;return!0}function Mf(I,V,X){if(I.entry.sessionId===X)return!0;return Ef(I.file)===V&&ea(I.file,".jsonl")===X}function Uf(I,V){if(!I)return!1;let X=_f(V,I);return X!==".."&&!X.startsWith(`..${Of}`)&&!Tf(X)}function Bf(I,V){let X=mn(I.id??"-"),ee=mn(I.decision??"deny"),ne=I.cwd?` [${mn(I.cwd)}]`:"",te=I.segment||I.command,le=te===I.command?"":"↳ ",de=te.length>50?`${te.slice(0,50)}…`:te;return`${X.padEnd(16)} ${mn(ra(I.ts,V))} ${ee.padEnd(5)} ${mn(I.agent??"-").padEnd(15)} ${mn(I.ruleId??"-").padEnd(20)} ${le}${mn(de)}${ne}`}function Gf(I,V){let X=(ne)=>mn(ne===void 0||ne===null||ne===""?"-":ne),ee=I.shape?`${I.agent??"-"} (shape: ${I.shape})`:I.agent??"-";return[`id: ${X(I.id)}`,`ts: ${X(ra(I.ts,V))}`,`decision: ${X(I.decision)}`,`agent: ${X(ee)}`,`level: ${X(I.level)}`,`tool: ${X(I.toolName)}`,`rule: ${X(I.ruleId)}`,`intent: ${X(I.intent)}`,`stage: ${X(I.failureStage)}`,`error: ${X(I.errorCode)}`,`session: ${X(I.sessionId)}`,`cwd: ${X(I.cwd)}`,`version: ${X(I.v)}`,`truncated: ${X(I.truncated===!0?"yes":void 0)}`,`reason: ${X(I.reason)}`,`command: ${X(I.command)}`,`segment: ${X(I.segment)}`].join(`
|
|
4
|
+
`)}function ra(I,V){let X=new Date(I);if(Number.isNaN(X.getTime()))return I;return new Intl.DateTimeFormat("sv-SE",{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",hourCycle:"h23",timeZone:V}).format(X)}function Xs(I){let V=Number(I);return Number.isFinite(V)&&V>0?V:null}var oa={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 ia={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:"--shell",argument:"<auto|posix|powershell>",description:"Parse the command as this shell (default: auto)"},{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"',"cc-safety-net explain --shell posix 'rmdir /s /q d:\\'"]};var sa={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 zo=["npx","--offline","--no-install","@deepseek-ai/dsh","--version"],aa=["cursor-agent","--version"],la=[{id:"antigravity-cli",displayName:"Antigravity CLI",runtime:{flags:["-ac","--agy-cli"],description:"Run as Antigravity CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--agy-cli",artifactKind:"hook config",probeCommand:["agy","--version"]}},{id:"claude-code",displayName:"Claude Code",runtime:{displayName:"Coding CLI",flags:["-cc","--coding-cli"],legacyFlags:["--claude-code"],description:"Run as Coding CLI PreToolUse hook",legacyTopLevelFlags:["-cc","--claude-code"]},install:{flag:"--claude-code",artifactKind:"plugin",probeCommand:["claude","--version"]}},{id:"codex",displayName:"Codex",runtime:{flags:["-cx","--codex"],description:"Run as a Codex PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--codex",artifactKind:"plugin",probeCommand:["codex","--version"]}},{id:"copilot-cli",displayName:"GitHub Copilot CLI",runtime:{flags:["-cp","--copilot-cli"],description:"Run as GitHub Copilot CLI PreToolUse hook",legacyTopLevelFlags:["-cp","--copilot-cli"]},install:{flag:"--copilot-cli",artifactKind:"plugin",probeCommand:["copilot","--binary-version"]}},{id:"gemini-cli",displayName:"Gemini CLI",runtime:{flags:["-gc","--gemini-cli"],description:"Run as Gemini CLI BeforeTool hook",legacyTopLevelFlags:["-gc","--gemini-cli"]},install:{flag:"--gemini-cli",artifactKind:"extension",probeCommand:["gemini","--version"]}},{id:"grok-build",displayName:"Grok Build",runtime:{flags:["-gb","--grok-build"],description:"Run as Grok Build PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--grok-build",artifactKind:"hook config",probeCommand:["grok","--version"]}},{id:"hermes-agent",displayName:"Hermes Agent",runtime:{flags:["-ha","--hermes-agent"],description:"Run as Hermes Agent pre_tool_call hook",legacyTopLevelFlags:[]},install:{flag:"--hermes-agent",artifactKind:"plugin",probeCommand:["hermes","--version"]}},{id:"kimi-code",displayName:"Kimi Code",runtime:{flags:["-kc","--kimi-code"],description:"Run as Kimi Code PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--kimi-code",artifactKind:"hook config",probeCommand:["kimi","--version"]}},{id:"openclaw",displayName:"OpenClaw",install:{flag:"--openclaw",artifactKind:"plugin",probeCommand:["openclaw","--version"]}},{id:"opencode",displayName:"OpenCode",install:{flag:"--opencode",artifactKind:"plugin",probeCommand:["opencode","--version"]}},{id:"pi",displayName:"Pi",install:{flag:"--pi",artifactKind:"package",probeCommand:["pi","--version"]}},{id:"cursor",displayName:"Cursor",runtime:{flags:["-cu","--cursor"],description:"Run as Cursor preToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--cursor",artifactKind:"hook config",probeCommand:["cursor","--version"]}},{id:"deepseek-harness",displayName:"DeepSeek Harness",install:{flag:"--deepseek-harness",artifactKind:"package",probeCommand:zo}},{id:"devin",displayName:"Devin CLI",runtime:{flags:["-dv","--devin"],description:"Run as Devin CLI PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--devin",artifactKind:"hook config",probeCommand:["devin","--version"]}},{id:"droid",displayName:"Factory Droid",runtime:{flags:["-fd","--droid"],description:"Run as Factory Droid PreToolUse hook",legacyTopLevelFlags:[]},install:{flag:"--droid",artifactKind:"hook config",probeCommand:["droid","--version"]}},{id:"amp",displayName:"Amp Code",install:{flag:"--amp",artifactKind:"plugin",probeCommand:["amp","--version"]}}],Wo=la.slice().sort((I,V)=>I.displayName.localeCompare(V.displayName,"en")),Or=Wo.map((I)=>I.id).sort((I,V)=>Number(V==="claude-code")-Number(I==="claude-code")),ir=Wo.filter((I)=>("runtime"in I)).map((I)=>({id:I.id,displayName:"displayName"in I.runtime?I.runtime.displayName:I.displayName,flags:I.runtime.flags,legacyFlags:"legacyFlags"in I.runtime?I.runtime.legacyFlags:[],description:I.runtime.description,legacyTopLevelFlags:I.runtime.legacyTopLevelFlags})),xn=Wo.map((I)=>({id:I.id,...I.install})),qf=Object.fromEntries(la.map((I)=>[I.id,I.displayName]));function cn(I){return qf[I]}var Vf=ir.map((I)=>({flags:I.flags.join(", "),description:I.description})),Kf=ir.flatMap((I)=>I.flags.map((V)=>`cc-safety-net hook ${V}`)),ca={name:"hook",description:"Run as an agent CLI hook (reads JSON from stdin)",usage:"hook INTEGRATION_FLAG",options:[...Vf,{flags:"-h, --help",description:"Show this help"}],examples:Kf};var da={name:"install",description:"Install CC Safety Net into a coding agent CLI",usage:"install [TARGET_FLAG]",options:[...xn.map((I)=>({flags:I.flag,description:`Install ${cn(I.id)} ${I.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net install",...xn.map((I)=>`cc-safety-net install ${I.flag}`)]},ua={name:"uninstall",description:"Uninstall CC Safety Net from a coding agent CLI",usage:"uninstall [TARGET_FLAG]",options:[...xn.map((I)=>({flags:I.flag,description:`Uninstall ${cn(I.id)} ${I.artifactKind}`})),{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net uninstall",...xn.map((I)=>`cc-safety-net uninstall ${I.flag}`)]},pa={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 fa={name:"logs",description:"Browse audit log entries recorded by hooks",usage:"logs [options]",options:[{flags:"--id",argument:"<id>",description:"Show one entry from retained history by its 16-character id (not guaranteed once it is older than the configured retention)"},{flags:"--limit",argument:"<n>",description:"Maximum entries to print",default:"20"},{flags:"--since",argument:"<days>",description:"Only include entries newer than this many days (max: the configured audit retention, 1-365)",default:"30"},{flags:"--agent",argument:"<name>",description:"Filter by agent name"},{flags:"--rule",argument:"<ruleId>",description:"Filter by rule id"},{flags:"--session",argument:"<id>",description:"Filter by session id"},{flags:"--project",argument:"<path>",description:"Filter by project path"},{flags:"--suspect",description:"Only denials that look like false positives"},{flags:"--all",description:"Include allow entries"},{flags:"--prune-legacy",description:"Permanently delete all legacy root-level logs; nested logs are untouched"},{flags:"--dry-run",description:"With --prune-legacy, report what would be deleted and delete nothing"},{flags:"--json",description:"Output entries as JSON"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net logs --id 3fa9c2d1a70e8b42","cc-safety-net logs --agent claude-code","cc-safety-net logs --project . --since 7","cc-safety-net logs --suspect --since 7","cc-safety-net logs --json","cc-safety-net logs --prune-legacy --dry-run","cc-safety-net logs --prune-legacy"]};var $r={name:"policy",description:"Check and apply project or user policy proposals",usage:"policy <subcommand>",subcommands:[{usage:"check <file>",description:"Validate a policy proposal and print its diff"},{usage:"apply <file>",description:"Apply a proposal after confirming in a terminal"}],options:[{flags:"-g, --global",description:"Use the user-scope policy instead of the project one"},{flags:"-h, --help",description:"Show this help"}],examples:["cc-safety-net policy check proposal.json","cc-safety-net policy apply proposal.json","cc-safety-net policy apply proposal.json --global"]};var Yo=[{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"}],Zo=["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"],Ht={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"},...Yo.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",...Zo,"cc-safety-net rule update","cc-safety-net rule migrate --cleanup","cc-safety-net rule verify"]};var ma={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 ga={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 Dr=[ma,oa,fa,ia,Ht,$r,da,pa,ua,ca,sa,ga];function Jf(I){return I.aliases??[]}function Nr(I){let V=I.toLowerCase();return Dr.find((X)=>X.name.toLowerCase()===V||Jf(X).some((ee)=>ee.toLowerCase()===V))}import{existsSync as Dy}from"node:fs";import{basename as zf}from"node:path";function Lr(I,V=7,X=W(I)){let ee=Date.now()-V*24*60*60*1000,ne=[],te=new Set,le=0,de,be,Se,Ie;if(X)Q(I,X);let $e={count:0},Le=X?Jn(X,$e):[];for(let Fe of Le)for(let Be of Ft(Fe,$e)){if(Be.decision==="allow")continue;let Me=new Date(Be.ts).getTime();if(Me>=ee){if(le++,te.add(Be.sessionId??zf(Fe,".jsonl")),be===void 0||Me<=be)de=Be.ts,be=Me;if(Ie===void 0||Me>Ie)Se=Be.ts,Ie=Me;Wf(ne,Be,Me)}}let Ne=ne.map((Fe)=>({timestamp:Fe.ts,command:Fe.command,reason:Fe.reason,relativeTime:Ys(new Date(Fe.ts))}));return{totalBlocked:le,sessionCount:te.size,recentEntries:Ne,oldestEntry:de,newestEntry:Se,unreadable:$e.count}}function Wf(I,V,X){let ee=I.findIndex((ne)=>X>new Date(ne.ts).getTime());if(ee===-1){if(I.length<3)I.push(V);return}if(I.splice(ee,0,V),I.length>3)I.pop()}import{dirname as am}from"node:path";import{dirname as Yf,join as Zf,resolve as Xf}from"node:path";var Qf="config.json";function yn(I,V,X,ee){x(em(I),`${JSON.stringify(V,null,2)}
|
|
5
|
+
`,X,ee)}function em(I){return typeof I==="string"?pe(I):I}function Qo(I){return{errors:he(tm(I),": "," "),ruleNames:new Set(Ze(I).map((V)=>V.toLowerCase()))}}var nm="must match pattern (letters, numbers, hyphens, underscores; max 64 chars)",ha="must match pattern (letters, numbers, hyphens, underscores)";function tm(I){if(!ya(I))return[e([],"Config must be an object")];return[...I.version===1?[]:[e(["version"],"must be 1")],...rm(I.rules)]}function rm(I){if(I===void 0)return[];if(!Array.isArray(I))return[e(["rules"],"must be an array")];return[...I.flatMap((V,X)=>ya(V)?om(V,["rules",X]):[e(["rules",X],"must be an object")]),...Je(I)]}function om(I,V){return[...Xo(I.name,[...V,"name"],"required string",m,nm),...Xo(I.command,[...V,"command"],"required string",P,ha),...I.subcommand===void 0?[]:Xo(I.subcommand,[...V,"subcommand"],"must be a string if provided",P,ha),...im(I.block_args,[...V,"block_args"]),...sm(I.reason,[...V,"reason"]),...I.intent===void 0||He(I.intent)?[]:[e([...V,"intent"],Ue)]]}function Xo(I,V,X,ee,ne){if(typeof I!=="string")return[e(V,X)];return ee.test(I)?[]:[e(V,ne)]}function im(I,V){if(!Array.isArray(I))return[e(V,"required array")];if(I.length===0)return[e(V,"must have at least one element")];return I.flatMap((X,ee)=>{if(typeof X!=="string")return[e([...V,ee],"must be a string")];return X===""?[e([...V,ee],"must not be empty")]:[]})}function sm(I,V){if(typeof I!=="string")return[e(V,"required string")];if(I==="")return[e(V,"must not be empty")];return I.length>M?[e(V,`must be at most ${M} characters`)]:[]}function ya(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}function ei(I){let V=va(I);if(!V.ok)return V.result;return Qo(V.parsed)}function va(I){let V=[],X=new Set;try{let ee=typeof I==="string"?pe(I):I,ne=o(ee);if(ne===null)return V.push(`File not found: ${ee.path}`),{ok:!1,result:{errors:V,ruleNames:X}};if(!ne.trim())return V.push("Config file is empty"),{ok:!1,result:{errors:V,ruleNames:X}};return{ok:!0,parsed:JSON.parse(ne)}}catch(ee){if(ee instanceof i)return V.push(ee.message),{ok:!1,result:{errors:V,ruleNames:X}};let ne=ee instanceof Error?ee.message:String(ee);return V.push(ee instanceof SyntaxError?"Invalid JSON":ne),{ok:!1,result:{errors:V,ruleNames:X}}}}function Ut(I){return Xf(I,".safety-net.json")}function Fn(I){let V=va(I);if(!V.ok)return V.result;let X=vt(V.parsed);return{errors:X.errors,ruleNames:X.sources}}function Bt(I,V={}){return Zf(Yf(me(I,V)),Qf)}function ba(I,V,X){let ee;try{if(o(V)===null)return{path:I,exists:!1,valid:!1,ruleCount:0};ee=Fn(V),ee.errors.push(...J(I,X))}catch(ne){if(!(ne instanceof i))throw ne;ee={errors:[ne.message],ruleNames:new Set}}return{path:I,exists:!0,valid:ee.errors.length===0,ruleCount:ee.ruleNames.size,...ee.errors.length>0?{errors:ee.errors}:{}}}function lm(I,V){return{source:V,name:I.name,command:I.command,subcommand:I.subcommand,blockArgs:[...I.block_args],reason:I.reason}}function wa(I,V){let X=K(I),ee=D(V),ne=am(X),te=ie(I,{cwd:V,userConfigPath:X,projectConfigPath:ee,userConfigDir:ne}),le=oe(I,{cwd:V,userConfigPath:X,projectConfigPath:ee,userConfigDir:ne}),de=new Map(te.rulebooks.flatMap((be)=>be.rules.map((Se)=>[Se,be.source])));return{userConfig:ba(X,le.userConfigTarget,le.userScope),projectConfig:ba(ee,le.projectConfigTarget,le.projectScope),effectiveRules:te.rules.map((be)=>lm(be,de.get(be.name)??"project"))}}var cm=[{flag:r.level,description:"Safety level preset: standard, strict, or paranoid",defaultBehavior:"standard"},{flag:r.strict,description:"Legacy; equivalent to safety.overrides.fail_closed",defaultBehavior:"permissive"},{flag:r.paranoid,description:"Legacy; equivalent to safety.overrides.paranoid_rm and paranoid_interpreters",defaultBehavior:"off"},{flag:r.paranoidRm,description:"Legacy; equivalent to safety.overrides.paranoid_rm",defaultBehavior:"off"},{flag:r.paranoidInterpreters,description:"Legacy; equivalent to safety.overrides.paranoid_interpreters",defaultBehavior:"off"},{flag:r.worktree,description:"Allow local git discards in linked worktrees",defaultBehavior:"off"},{flag:r.debug,description:"Print diagnostic messages to stderr",defaultBehavior:"off"},{flag:r.auditScope,description:"Command decisions recorded: all, or blocked (privacy-minimizing, denials only)",defaultBehavior:"all"},{flag:r.projectTightenOnly,description:"Ignore project policy settings that weaken the user policy",defaultBehavior:"off"}];function ka(I){return[...cm.map((V)=>({name:V.flag.name,value:xe(V.flag,I.env),isSet:At(V.flag,I.env),legacyName:V.flag.legacyName,legacyValue:V.flag.legacyName?I.env.get(V.flag.legacyName):void 0,legacyIsSet:V.flag.legacyName?I.env.get(V.flag.legacyName)!==void 0:void 0,description:V.description,defaultBehavior:V.defaultBehavior})),{name:"CC_SAFETY_NET_HOME",value:I.env.get("CC_SAFETY_NET_HOME"),isSet:I.env.get("CC_SAFETY_NET_HOME")!==void 0,description:"Override user-scope config/cache directory",defaultBehavior:"~/.cc-safety-net"}]}var Ca={error:0,warning:1,info:2},dm=["policy","config","audit"];function um(I){return I.map((V)=>{if(V==="ownership")return"is not owned by the current user";if(V==="permissions")return"has unsafe permissions";if(V==="symlink")return"is a symbolic link";return"is not a directory"}).join(" and ")}var pm=[{derive:(I)=>I.hooks.length>0&&I.hooks.every((V)=>!V.configured)?[{checkId:"integration.none-configured",severity:"error",title:"No integration configured",detail:"CC Safety Net is not connected to any supported coding-agent integration.",fixHint:"Run `cc-safety-net install` and configure at least one integration."}]:[]},{derive:(I)=>I.hooks.filter((V)=>V.inspectionStatus==="failed").map((V)=>{let X=cn(V.platform);return{checkId:"integration.inspection-failed",severity:"error",title:`${X} inspection failed`,detail:`Doctor could not verify the ${X} integration configuration.`,fixHint:`Correct the reported ${X} configuration error, then run \`cc-safety-net doctor\` again.`,integration:V.platform}})},{derive:(I)=>I.userConfig.exists&&!I.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:I.userConfig.path}]:[]},{derive:(I)=>I.projectConfig.exists&&!I.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:I.projectConfig.path}]:[]},{derive:(I)=>I.configState.state==="degraded"?[{checkId:"config.runtime-degraded",severity:"warning",title:"Runtime is enforcing a fallback configuration",detail:`The rejected candidate configuration is not active: ${I.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:(I)=>I.v2Leftovers&&I.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: ${I.v2Leftovers.join(", ")}.`,fixHint:"Run `cc-safety-net rule sync` (add `--global` for user scope) to migrate them, then rerun doctor."}]:[]},{derive:(I)=>I.legacyConfigs&&I.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: ${I.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:(I)=>{let V=I.environment.find((X)=>X.name==="CC_SAFETY_NET_AUDIT_SCOPE");return ft(V?.value)==="invalid"?[{checkId:"environment.audit-scope-invalid",severity:"warning",title:"Audit scope value is invalid",detail:"CC_SAFETY_NET_AUDIT_SCOPE is not `all` or `blocked`, so allowed command decisions are not recorded.",fixHint:"Set CC_SAFETY_NET_AUDIT_SCOPE to `all` or `blocked`, then restart the integration."}]:[]}},...dm.map((I)=>({derive:(V)=>V.posture.directories.filter((X)=>X.kind===I&&X.status==="unsafe").map((X)=>({checkId:`posture.${I}-directory-unsafe`,severity:"error",title:`${I[0]?.toUpperCase()}${I.slice(1)} directory is unsafe`,detail:`The ${I} directory ${um(X.issues)}.`,fixHint:"Ensure this is a real directory owned by the current user with no group or other write access, then rerun doctor.",...X.path?{path:X.path}:{}}))})),{derive:(I)=>{let V=[...I.effectiveSafety.weakenedRuleOverrides].sort();return V.length>0?[{checkId:"posture.rule-overrides-weaken-preset",severity:"warning",title:"Rule overrides weaken the selected preset",detail:`Explicit overrides disable rules the resolved preset would enable: ${V.join(", ")}.`,fixHint:`Remove these \`off\` overrides or set them to \`on\`: ${V.join(", ")}.`}]:[]}}];function xa(I){return pm.flatMap((V,X)=>V.derive(I).map((ee,ne)=>({finding:ee,catalogOrder:X,occurrence:ne}))).sort((V,X)=>Ca[V.finding.severity]-Ca[X.finding.severity]||V.catalogOrder-X.catalogOrder||V.occurrence-X.occurrence).map((V)=>V.finding)}function On(){return Boolean(process.stdout.isTTY&&!process.env.NO_COLOR)}var fm=(I)=>On()?`\x1B[32m${I}\x1B[0m`:I,mm=(I)=>On()?`\x1B[33m${I}\x1B[0m`:I,gm=(I)=>On()?`\x1B[34m${I}\x1B[0m`:I,hm=(I)=>On()?`\x1B[36m${I}\x1B[0m`:I,ym=(I)=>On()?`\x1B[31m${I}\x1B[0m`:I,vm=(I)=>On()?`\x1B[2m${I}\x1B[0m`:I,bm=(I)=>On()?`\x1B[1m${I}\x1B[0m`:I,qe={green:fm,yellow:mm,blue:gm,cyan:hm,red:ym,dim:vm,bold:bm},wm="\x1B[0m",km=[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 Cm(I){let V=I;return()=>(V=(V*1664525+1013904223)%4294967296,V/4294967296)}function xm(I){let V=[...km],X=Cm(I);for(let ee=V.length-1;ee>0;ee--){let ne=Math.floor(X()*(ee+1)),te=V[ee];V[ee]=V[ne],V[ne]=te}return V}function Pm(I,V=0){if(!On())return"";let X=xm(V);return`\x1B[38;5;${X[I%X.length]}m`}function Pa(I,V,X=0){if(!On())return`"${I}"`;return`${Pm(V,X)}"${I}"${wm}`}function jr(I){return I==="default"?"built-in default":`${I} policy`}var Sm=new RegExp("\x1B\\[[0-9;]*m","g"),ni=(I)=>I.replace(Sm,"").length;function zn(I){let V=(I.headers??I.rows[0]??[]).map((le,de)=>{let be=Math.max(...I.rows.map((Se)=>ni(Se[de]??"")));return Math.max(ni(le),be)}),X=(le,de)=>le+" ".repeat(Math.max(0,de-ni(le))),ee=(le,de)=>de[0]+V.map((be)=>le.repeat(be+2)).join(de[1])+de[2],ne=(le)=>`│ ${le.map((de,be)=>X(de,V[be]??0)).join(" │ ")} │`,te=I.headers?[` ${ne(I.headers)}`,` ${ee("─",["├","┼","┤"])}`]:[];return[` ${ee("─",["┌","┬","┐"])}`,...te,...I.rows.map((le)=>` ${ne(le)}`),` ${ee("─",["└","┴","┘"])}`].join(`
|
|
6
6
|
`)}function Sa(I){let V=[];V.push("Hook Integration"),V.push(Rm(I));let X=[],ee=[];for(let ne of I){let te=cn(ne.platform);if(ne.errors&&ne.errors.length>0)for(let le of ne.errors)if(ne.configured)X.push({platform:te,message:le});else ee.push({platform:te,message:le})}for(let ne of X)V.push(` Warning (${ne.platform}): ${ne.message}`);for(let ne of ee)V.push(qe.red(` Error (${ne.platform}): ${ne.message}`));return V.join(`
|
|
7
|
-
`)}function Rm(I){let V=["Platform","Discovery","Configuration","Inspection"],X=I.map((ee)=>{let ne=cn(ee.platform);if(ee.inspectionStatus==="not-inspected"){let
|
|
7
|
+
`)}function Rm(I){let V=["Platform","Discovery","Configuration","Inspection"],X=I.map((ee)=>{let ne=cn(ee.platform);if(ee.inspectionStatus==="not-inspected"){let be=qe.dim("Not inspected");return[ne,be,be,be]}let te=ee.detected?qe.green("Detected"):ee.inspectionStatus==="failed"?qe.red("Unknown"):qe.dim("Not detected"),le=ee.configured?qe.green("Configured"):ee.detected?qe.yellow("Not configured"):ee.inspectionStatus==="failed"?qe.red("Unknown"):qe.dim("Not applicable"),de=ee.inspectionStatus==="verified"?qe.green("Verified"):ee.inspectionStatus==="failed"?qe.red("Failed"):qe.dim("Not applicable");return[ne,te,le,de]});return zn({headers:V,rows:X})}function Ra(I){let X=["Guard Engine Verification",` Synthetic self-test: ${I.failed>0?qe.red(`${I.passed}/${I.total} FAIL`):qe.green(`${I.passed}/${I.total} passed`)}`],ee=I.results.filter((ne)=>!ne.passed);if(ee.length>0){X.push(""),X.push(qe.red(" Failures:"));for(let ne of ee)X.push(qe.red(` • ${ne.description}`)),X.push(qe.red(` expected ${ne.expected}, got ${ne.actual}`))}return X.join(`
|
|
8
8
|
`)}function Em(I){if(I.length===0)return" (no custom rules)";let V=["Source","Name","Command","Block Args"],X=I.map((ee)=>[ee.source,ee.name,ee.subcommand?`${ee.command} ${ee.subcommand}`:ee.command,ee.blockArgs.join(", ")]);return zn({headers:V,rows:X})}function Ea(I){let V=[];if(V.push("Configuration"),V.push(Tm(I.userConfig,I.projectConfig)),V.push(""),I.effectiveRules.length>0)V.push(` Effective rules (${I.effectiveRules.length} total):`),V.push(Em(I.effectiveRules));else V.push(" Effective rules: (none - using built-in rules only)");return V.join(`
|
|
9
9
|
`)}function Tm(I,V){let X=["Scope","Status"],ee=(te)=>{if(!te.exists)return qe.dim("N/A");if(!te.valid)return qe.red(`Invalid (${te.errors?.[0]??"unknown error"})`);return qe.green("Configured")},ne=[["User",ee(I)],["Project",ee(V)]];return zn({headers:X,rows:ne})}function Ta(I){let V=[];return V.push("Environment"),V.push(Am(I)),V.join(`
|
|
10
|
-
`)}function Aa(I){let V=I.effectiveSafety.policyScopes,X=["Effective Safety",` Selected preset: ${I.effectiveSafety.selectedPreset}${V?` (${jr(V.levelScope)})`:""}`,` Effective: ${I.effectiveSafety.level}`],ee=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[ne,te]of ee){let le=I.effectiveSafety.capabilities[ne],de=le.enabled?qe.green("ON"):qe.dim("OFF"),
|
|
10
|
+
`)}function Aa(I){let V=I.effectiveSafety.policyScopes,X=["Effective Safety",` Selected preset: ${I.effectiveSafety.selectedPreset}${V?` (${jr(V.levelScope)})`:""}`,` Effective: ${I.effectiveSafety.level}`],ee=[["fail_closed","fail_closed"],["paranoid_rm","paranoid_rm"],["paranoid_interpreters","paranoid_interpreters"]];for(let[ne,te]of ee){let le=I.effectiveSafety.capabilities[ne],de=le.enabled?qe.green("ON"):qe.dim("OFF"),be=le.sources.length>0?` (${le.sources.join(", ")})`:"";X.push(` ${te}: ${de} via ${le.source}${be}`)}if(V&&V.weakenings.length>0){X.push(` Project policy deltas${V.weakeningsIgnored?" (ignored)":""}:`);for(let ne of V.weakenings)X.push(` ${ne}`)}X.push(` Stored rule customizations: ${I.effectiveSafety.ruleCounts.stored}`),X.push(` Effective rule customizations: ${I.effectiveSafety.ruleCounts.effective}`);for(let[ne,te]of Object.entries(I.effectiveSafety.ruleOverrides))X.push(` ${ne}: ${te}`);return X.join(`
|
|
11
11
|
`)}function _a(I){let V=["Findings"];if(I.length===0)return V.push(" No findings from inspected doctor facts."),V.join(`
|
|
12
12
|
`);for(let X of I){let ee=`[${X.severity.toUpperCase()}] ${X.checkId}: ${mn(X.title)}`,ne=X.severity==="error"?qe.red:X.severity==="warning"?qe.yellow:qe.blue;if(V.push(` ${ne(ee)}`),V.push(` ${mn(X.detail)}`),X.path)V.push(` Path: ${mn(X.path)}`);if(X.fixHint)V.push(` Fix: ${mn(X.fixHint)}`)}return V.join(`
|
|
13
13
|
`)}function Am(I){let V=["Variable","Status","Legacy"],X=I.map((ee)=>{let ne=ee.isSet?qe.green("✓"):qe.dim("✗"),te=ee.legacyName&&ee.legacyIsSet?`${ee.legacyName} ${qe.green("✓")}`:ee.legacyName??"";return[ee.name,ne,te]});return zn({headers:V,rows:X})}function Ia(I){let V=[];if(I.totalBlocked===0)V.push("Recent Activity"),V.push(" No blocked commands in the last 7 days"),V.push(" Tip: This is normal for new installations");else V.push(`Recent Activity · last 7 days (${I.totalBlocked} blocked / ${I.sessionCount} sessions)`),V.push(_m(I.recentEntries));if(I.unreadable>0)V.push(` Warning: ${I.unreadable} audit log ${I.unreadable===1?"source":"sources"} could not be read; this summary is incomplete`);return V.join(`
|
|
@@ -18,30 +18,30 @@ ${Jo(ne.segment||ne.command)}`,X=I.filter((ne)=>ne.decision!=="allow"),ee=X.filt
|
|
|
18
18
|
`)}function Fr(I){return zn({rows:I})}function $a(I){let V=[];return V.push("System Info"),V.push(Im(I)),V.join(`
|
|
19
19
|
`)}function Im(I){let V=["Component","Version"],X=(te)=>{if(te===null)return qe.dim("not found");return te},ne=[{label:"cc-safety-net",value:I.version},...Or.map((te)=>({label:cn(te),value:I.versions[te]??null})),{label:"Node.js",value:I.nodeVersion},{label:"npm",value:I.npmVersion},{label:"Bun",value:I.bunVersion},{label:"Platform",value:I.platform}].map((te)=>[te.label,X(te.value)]);return zn({headers:V,rows:ne})}function Da(I){if(I.findings.length===0)return qe.green(`
|
|
20
20
|
No findings from inspected doctor facts.`);let V={error:I.findings.filter((te)=>te.severity==="error").length,warning:I.findings.filter((te)=>te.severity==="warning").length,info:I.findings.filter((te)=>te.severity==="info").length},X=["error","warning","info"].filter((te)=>V[te]>0).map((te)=>`${V[te]} ${te}`),ee=I.findings.length===1?"finding":"findings",ne=`
|
|
21
|
-
${I.findings.length} ${ee}: ${X.join(", ")}.`;if(V.error>0)return qe.red(ne);if(V.warning>0)return qe.yellow(ne);return qe.blue(ne)}import{lstatSync as Om}from"node:fs";import{dirname as ti}from"node:path";function ri(I,V){try{let X=Om(V);if(X.isSymbolicLink())return{kind:I,path:V,status:"unsafe",issues:["symlink"]};if(!X.isDirectory())return{kind:I,path:V,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:I,path:V,status:"unknown",issues:[]};let ee=[...X.uid!==process.getuid()?["ownership"]:[],...(X.mode&18)!==0?["permissions"]:[]];return{kind:I,path:V,status:ee.length>0?"unsafe":"safe",issues:ee}}catch(X){if(typeof X==="object"&&X!==null&&"code"in X&&X.code==="ENOENT")return{kind:I,path:V,status:"not-applicable",issues:[]};return{kind:I,path:V,status:"unknown",issues:[]}}}function Na(I,V){let X=W(I);return{directories:[ri("policy",ti(ti(V))),ri("config",ti(V)),...X?[ri("audit",X)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as $m}from"node:child_process";import{existsSync as La}from"node:fs";import{delimiter as Dm,extname as Nm,join as Lm}from"node:path";import{stripVTControlCharacters as ja}from"node:util";var Ha="2.7.
|
|
22
|
-
`)[0]?.trim()||null}async function Mr(I,V=Gt,X=process.cwd()){let ee=Promise.all(xn.map(async($e)=>[$e.id,Hr(await V([...$e.probeCommand]))])),[ne,te,le,de,
|
|
23
|
-
`).map((Ie)=>Array.from(Ie)),le=Math.max(...te.map((Ie)=>Ie.length)),de=12000*te.filter((Ie)=>Ie.length>0).length/40,
|
|
24
|
-
`.repeat(te.length-1)}${Bm(te.length-1)}`:""}\x1B7`);try{for(let Ie=1;Ie<=
|
|
21
|
+
${I.findings.length} ${ee}: ${X.join(", ")}.`;if(V.error>0)return qe.red(ne);if(V.warning>0)return qe.yellow(ne);return qe.blue(ne)}import{lstatSync as Om}from"node:fs";import{dirname as ti}from"node:path";function ri(I,V){try{let X=Om(V);if(X.isSymbolicLink())return{kind:I,path:V,status:"unsafe",issues:["symlink"]};if(!X.isDirectory())return{kind:I,path:V,status:"unsafe",issues:["not-directory"]};if(process.platform==="win32"||typeof process.getuid!=="function")return{kind:I,path:V,status:"unknown",issues:[]};let ee=[...X.uid!==process.getuid()?["ownership"]:[],...(X.mode&18)!==0?["permissions"]:[]];return{kind:I,path:V,status:ee.length>0?"unsafe":"safe",issues:ee}}catch(X){if(typeof X==="object"&&X!==null&&"code"in X&&X.code==="ENOENT")return{kind:I,path:V,status:"not-applicable",issues:[]};return{kind:I,path:V,status:"unknown",issues:[]}}}function Na(I,V){let X=W(I);return{directories:[ri("policy",ti(ti(V))),ri("config",ti(V)),...X?[ri("audit",X)]:[{kind:"audit",status:"unknown",issues:[]}]]}}import{spawn as $m}from"node:child_process";import{existsSync as La}from"node:fs";import{delimiter as Dm,extname as Nm,join as Lm}from"node:path";import{stripVTControlCharacters as ja}from"node:util";var Ha="2.7.2",jm=5000,Fm="_CC_SAFETY_NET_TEST_SPAWN_PLATFORM";function un(){return Ha}function oi(I,V){let X=I[V];if(X)return X;let ee=Object.keys(I).find((ne)=>ne.toLowerCase()===V.toLowerCase()&&!!I[ne]);return ee?I[ee]:X}function Hm(I){return(oi(I,"PATHEXT")||".COM;.EXE;.BAT;.CMD").split(";").filter((V)=>V.length>0)}function Mm(I,V){let X=Nm(I)?[I]:[...Hm(V).map((ee)=>`${I}${ee}`),I];if(I.includes("/")||I.includes("\\"))return X.find((ee)=>La(ee))??I;return(oi(V,"PATH")??"").split(Dm).flatMap((ee)=>X.map((ne)=>Lm(ee,ne))).find((ee)=>La(ee))??I}function Fa(I){if(!/[\s"&|<>^]/.test(I))return I;return`"${I.replace(/"/g,'""')}"`}function Wn(I,V){let[X,...ee]=I,ne=V[Fm]==="win32"?"win32":process.platform;if(!X||ne!=="win32")return{cmd:X??"",args:ee};let te=Mm(X,V);if(!/\.(?:bat|cmd)$/i.test(te))return{cmd:te,args:ee};return{cmd:oi(V,"COMSPEC")??"cmd.exe",args:["/d","/c",["call",Fa(te),...ee.map(Fa)].join(" ")]}}var Gt=async(I,V=jm)=>{let X=await Um(I,{timeoutMs:V});if(X.code!==0)return null;return ja(X.stdout).trim()||ja(X.stderr).trim()||null};function Um(I,V){let[X,...ee]=I;if(!X)return Promise.resolve({code:null,stdout:"",stderr:""});return new Promise((ne)=>{try{let te=Wn([X,...ee],process.env),le=$m(te.cmd,te.args,{stdio:["ignore","pipe","pipe"]}),de=!1,be="",Se="";le.stdout.on("data",(Le)=>{be+=Le.toString()}),le.stderr.on("data",(Le)=>{Se+=Le.toString()});let Ie=(Le)=>{if(de)return;de=!0,clearTimeout($e),ne(Le)},$e=setTimeout(()=>{le.kill(),Ie({code:null,stdout:be,stderr:Se})},V.timeoutMs);le.on("close",(Le)=>{Ie({code:Le,stdout:be,stderr:Se})}),le.on("error",()=>{Ie({code:null,stdout:be,stderr:Se})})}catch{ne({code:null,stdout:"",stderr:""})}})}function Hr(I){if(!I)return null;let V=/Claude Code\s+(\d+\.\d+\.\d+)/i.exec(I);if(V)return V[1]??null;let X=/v?(\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)/i.exec(I);if(X)return X[1]??null;return I.split(`
|
|
22
|
+
`)[0]?.trim()||null}async function Mr(I,V=Gt,X=process.cwd()){let ee=Promise.all(xn.map(async($e)=>[$e.id,Hr(await V([...$e.probeCommand]))])),[ne,te,le,de,be,Se,Ie]=await Promise.all([ee,ee.then(async($e)=>{let Le=$e.find(([Be])=>Be==="opencode")?.[1];if(!Le?.startsWith("2.")||!I(Le))return null;let Ne=["--param",`location[directory]=${X}`],Fe=["opencode","api","integration.list",...Ne];return await V(Fe,30000),V(["opencode","api","plugin.list",...Ne],30000)}),V(["codex","plugin","list"],30000),V(["amp","plugins","list"],30000),V(["node","--version"]),V(["npm","--version"]),V(["bun","--version"])]);return{version:Ha,versions:Object.fromEntries(ne),codexPluginListOutput:le,ampPluginListOutput:de,openCodePluginListOutput:te,nodeVersion:Hr(be),npmVersion:Hr(Se),bunVersion:Hr(Ie),platform:`${process.platform} ${process.arch}`}}function ii(I,V){if(V==="dev")return!1;let X=I.split(".").map(Number),ee=V.split(".").map(Number),[ne=0,te=0,le=0]=X,[de=0,be=0,Se=0]=ee;if(ne!==de)return ne>de;if(te!==be)return te>be;return le>Se}async function Hn(){let I=un(),V=new AbortController,X=setTimeout(()=>V.abort(),3000);try{let ee=await fetch("https://registry.npmjs.org/cc-safety-net/latest",{signal:V.signal});if(!ee.ok)return{currentVersion:I,latestVersion:null,updateAvailable:!1,error:`npm registry returned ${ee.status}`};let ne=await ee.json(),te=ii(ne.version,I);return{currentVersion:I,latestVersion:ne.version,updateAvailable:te}}catch(ee){return{currentVersion:I,latestVersion:null,updateAvailable:!1,error:ee instanceof Error?ee.message:"Network error"}}finally{clearTimeout(X)}}import*as Ja from"node:readline";var Ga=(I)=>`\x1B[${I}B`,Bm=(I)=>`\x1B[${I}A`;var Ma=["░","▒","▓","╱","╲","┃","━","┏","┓","┗","┛","╋"];function Gm(I){return new Promise((V)=>setTimeout(V,I))}function qm(I,V,X){if(!X)return V(I);if(X.aborted)return Promise.resolve();return new Promise((ee,ne)=>{let te=()=>X.removeEventListener("abort",le),le=()=>{te(),ee()};X.addEventListener("abort",le,{once:!0}),V(I).then(()=>{te(),ee()},(de)=>{te(),ne(de)})})}function Ur(I){return Math.max(0,Math.min(1,I))}function qt(I){return Math.max(0,Math.min(255,Math.round(I)))}function si(I){return I<=0.0031308?12.92*I:1.055*I**0.4166666666666667-0.055}function Vm(I,V,X){let ee=X*Math.PI/180,ne=V*Math.cos(ee),te=V*Math.sin(ee),le=(I+0.3963377774*ne+0.2158037573*te)**3,de=(I-0.1055613458*ne-0.0638541728*te)**3,be=(I-0.0894841775*ne-1.291485548*te)**3;return{blue:qt(si(Ur(-0.0041960863*le-0.7034186147*de+1.707614701*be))*255),green:qt(si(Ur(-1.2684380046*le+2.6097574011*de-0.3413193965*be))*255),red:qt(si(Ur(4.0767416621*le-3.3077115913*de+0.2309699292*be))*255)}}function ai(I,V){let X=(V*I*180/Math.PI%360+360)%360;return Vm(0.72,0.15,X)}function qa(I,V=0.1){let X=ai(V,I);return`\x1B[38;2;${X.red};${X.green};${X.blue}m`}function Km(I,V){return{blue:qt(I.blue+(255-I.blue)*V),green:qt(I.green+(255-I.green)*V),red:qt(I.red+(255-I.red)*V)}}function Va(I,V,X){let ee=Math.imul(I+2654435769,2246822507)^Math.imul(V+3266489909,668265263)^Math.imul(X+374761393,2654435761),ne=ee^ee>>>15,te=Math.imul(ne,739982445),le=te^te>>>12,de=Math.imul(le,695872825);return((de^de>>>15)>>>0)/4294967296}function Jm(I,V,X){let ee=Math.floor(Va(I,V,X)*Ma.length);return Ma[ee]??"░"}function Ua(I){let V=Ur(I);return V*V*V*(V*(V*6-15)+10)}function zm(I){if(I.length===0)return"";let V=[],X=!1,ee="";for(let ne of I){let te=`${ne.red};${ne.green};${ne.blue}`;if(ne.bold!==X)V.push(ne.bold?"\x1B[1m":"\x1B[22m"),X=ne.bold;if(te!==ee)V.push(`\x1B[38;2;${te}m`),ee=te;V.push(ne.character)}return`${V.join("")}\x1B[22m\x1B[39m`}function Wm(I,V,X,ee,ne){return I.map((te,le)=>({...ai(X,ee+V+le/ne),bold:!1,character:te}))}function Ym(I,V,X,ee,ne,te,le,de){let be=Math.max(1,ee*0.75),Se=Math.min(1,X/be),Ie=ne*Ua(Se),$e=Math.max(0,(X-be)/Math.max(1,ee-be)),Le=(1-Ua(X/ee))*de*2,Ne=0.35*Math.max(0,1-$e*2),Fe=Se>=1,Be=Math.min(I.length,Math.ceil(Ie+2+1));return I.slice(0,Be).map((Me,tn)=>{let en=ai(te,le+V+tn/de+Le),on=tn+Va(V,tn,7919)*2-1;if(on>Ie+2)return{...en,bold:!1,character:" "};let ln=Ie-on,nn=0.8*Math.exp(-(ln*ln)/12.5),sn=Math.min(0.9,nn+Ne),Sn=!Fe&&on>Ie-4;return{...Km(en,sn),bold:sn>0.3,character:Sn?Jm(V,tn,X):Me}})}function Ba(I){return`\x1B[?2026h${I.map((V,X)=>`\x1B8${X>0?Ga(X):""}${zm(V)}`).join("")}\x1B[?2026l`}async function li(I,V={}){if(!I)return;let X=V.output??process.stdout,ee=V.sleep??Gm,ne=V.seed??0,te=I.split(`
|
|
23
|
+
`).map((Ie)=>Array.from(Ie)),le=Math.max(...te.map((Ie)=>Ie.length)),de=12000*te.filter((Ie)=>Ie.length>0).length/40,be=le>0?Math.max(1,Math.ceil(de/16.666666666666668)):0,Se=be>0?de/be:0;X.write(`\x1B[?25l${te.length>1?`${`
|
|
24
|
+
`.repeat(te.length-1)}${Bm(te.length-1)}`:""}\x1B7`);try{for(let Ie=1;Ie<=be;Ie+=1){if(V.signal?.aborted)break;X.write(Ba(te.map(($e,Le)=>Ym($e,Le,Ie,be,le,0.1,ne,3)))),await qm(Se,ee,V.signal)}}finally{if(X.write(Ba(te.map((Ie,$e)=>Wm(Ie,$e,0.1,ne,3)))),X.write("\x1B8"),te.length>1)X.write(Ga(te.length-1));X.write(`
|
|
25
25
|
\x1B[0m\x1B[?25h`)}}var Ka=["┏━┛┏━┛ ┏━┛┏━┃┏━┛┏━┛━┏┛┃ ┃ ┏━ ┏━┛━┏┛","┃ ┃ ━━┃┏━┃┏━┛┏━┛ ┃ ━┏┛ ┃ ┃┏━┛ ┃ ","━━┛━━┛ ━━┛┛ ┛┛ ━━┛ ┛ ┛ ┛ ┛━━┛ ┛ "].join(`
|
|
26
|
-
`);function Zm(I){return Boolean(I.isTTY)}async function sr(I={}){let V=I.output??process.stdout;if(!Zm(V))return;let X=I.input??process.stdin,ee={output:V,seed:I.seed??Math.random()*8192,sleep:I.sleep};if(!X.isTTY||typeof X.setRawMode!=="function"){await li(Ka,ee);return}let ne=new AbortController,te=X.readableFlowing===!0,le=X.isRaw===!0,de=!1,
|
|
27
|
-
`).map((X)=>kg.exec(X)?.[1]).find((X)=>X!==void 0);if(!V)return{platform:"amp",status:"n/a"};if(V!=="active")return{platform:"amp",status:"disabled",method:qr,configPath:qr,errors:[`Amp personal plugin cc-safety-net is ${V}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:qr,configPath:qr}}import{existsSync as Tg,readFileSync as Ag}from"node:fs";import{isAbsolute as cP,join as Eg}from"node:path";function lr(I){return Eg(I,".gemini","config","hooks.json")}var il=new Map([["run_command","auto"]]),sl="manage_task";var _g=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Ig(I){if(!I||typeof I!=="object"||Array.isArray(I))return[];return Object.values(I).flatMap((V)=>{if(!V||typeof V!=="object"||Array.isArray(V))return[];let X=V,ee=X.PreToolUse;if(!Array.isArray(ee))return[];return ee.flatMap((ne)=>{if(!ne||typeof ne!=="object"||Array.isArray(ne))return[];let te=ne.hooks;if(!Array.isArray(te))return[];return te.flatMap((le)=>{if(!le||typeof le!=="object"||Array.isArray(le))return[];let de=le.command;if(typeof de!=="string"||!_g.test(de))return[];return[{command:de,enabled:X.enabled!==!1}]})})})}function al(I){let V=lr(I.environment.home);if(!Tg(V))return{platform:"antigravity-cli",status:"n/a",configPath:V};let X;try{X=Ig(JSON.parse(Ag(V,"utf-8")))}catch(ee){return{platform:"antigravity-cli",status:"n/a",configPath:V,errors:[`Failed to parse Antigravity hooks config ${V}: ${ee instanceof Error?ee.message:String(ee)}`]}}if(X.some((ee)=>ee.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:V};if(X.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:V};return{platform:"antigravity-cli",status:"n/a",configPath:V}}import{existsSync as Og}from"node:fs";import{join as $n}from"node:path";var zr="cc-safety-net@cc-marketplace";function Wr(I){return I.env.get("CLAUDE_CONFIG_DIR")||$n(I.home,".claude")}function ll(I){return $n(I.env.get("CLAUDE_CODE_PLUGIN_CACHE_DIR")||$n(Wr(I),"plugins"),"installed_plugins.json")}function cl(I,V){let X=n(n(I,"plugins"),V);return Array.isArray(X)&&X.length>0}function Yr(I,V){let X=
|
|
26
|
+
`);function Zm(I){return Boolean(I.isTTY)}async function sr(I={}){let V=I.output??process.stdout;if(!Zm(V))return;let X=I.input??process.stdin,ee={output:V,seed:I.seed??Math.random()*8192,sleep:I.sleep};if(!X.isTTY||typeof X.setRawMode!=="function"){await li(Ka,ee);return}let ne=new AbortController,te=X.readableFlowing===!0,le=X.isRaw===!0,de=!1,be=(Se,Ie)=>{if(Ie.ctrl&&Ie.name==="c")de=!0;if(de||Ie.name==="return"||Ie.name==="enter")ne.abort()};Ja.emitKeypressEvents(X),X.on("keypress",be),X.setRawMode(!0),X.resume();try{await li(Ka,{...ee,signal:ne.signal})}finally{if(X.off("keypress",be),X.setRawMode(le),!te)X.pause()}if(!de)return;if(I.onInterrupt){I.onInterrupt();return}process.kill(process.pid,"SIGINT")}import{createHash as ng}from"node:crypto";import{existsSync as Wa}from"node:fs";import{dirname as Br,join as Ya}from"node:path";import{dirname as za,join as Xm}from"node:path";var Qm="rule.lock";function eg(I){return Xm(za(I),Qm)}function hn(I,V){let X=V.global?V.userConfigPath??K(I,V):V.projectConfigPath??D(V.cwd??process.cwd()),ee=V.global?ht(I,V):yt(X,V.cwd??process.cwd()),ne=eg(X);return{configDir:za(X),configPath:X,lockPath:ne,filesystemScope:ee,configTarget:s(ee,X),lockTarget:s(ee,ne)}}var tg="`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.",rg="cache",og="rulebooks";function Za(I,V={}){let X=hn(I,V),ee=s(X.filesystemScope,Qa(X.configDir)),ne=o(X.lockTarget);if(console.log(tg),ne===null&&!Wa(ee.path))return console.log(`No v2 lock or cache leftovers found in ${Br(X.configDir)}; nothing to migrate.`),0;let te=cg(ne),le=f(X.configTarget);if(!le.config&&(o(X.configTarget)!==null||te.size>0))return console.error(`Cannot migrate: the rules config in ${Br(X.configDir)} is missing or unreadable while v2 leftovers remain. Restore rule.json, then re-run rule sync.`),1;let de=le.config?.rules??[];for(let be of de.flatMap((Se)=>ig(Se,te,X,ee,V.global===!0)))console.log(be);return q(X.lockTarget),Ot(ee),console.log(`Removed the v2 lock and cache under ${Br(X.configDir)}.`),0}function Xa(I,V){return[...new Set([{cwd:V},{cwd:V,global:!0}].flatMap((X)=>{let ee=hn(I,X);return[ee.lockPath,Qa(ee.configDir)]}))].filter((X)=>Wa(X))}function ig(I,V,X,ee,ne){if(!T(I))return[];let te=j(I).name,le=s(X.filesystemScope,U(X.configDir,te)),de=o(le);if(de!==null&&sg(de,te))return[];let be=V.get(I),Se=be?ag(be,te,ee.path,X.filesystemScope):null;if(Se===null)return[`Could not migrate ${I} from the v2 cache. Run \`cc-safety-net rule update ${I}${ne?" --global":""}\` to vendor it.`];if(x(le,Se),de!==null)return[`Restored ${I} from the v2 cache over an invalid file.`];return[`Vendored ${I} from the v2 cache.`]}function sg(I,V){let X=Pe(I);return!("problem"in X)&&X.rulebook.name===V}function ag(I,V,X,ee){let ne=Ya(X,og,`${lg(I)}--${I.digest.replace("sha256:","").slice(0,12)}`,Ce),te=o(s(ee,ne));if(te===null||pg(te)!==I.digest)return null;let le=Pe(te);if("problem"in le||le.rulebook.name!==V)return null;return te}function Qa(I){return Ya(Br(I),rg)}function lg(I){return([I.owner,I.repo,I.display_ref,I.name].every((ee)=>typeof ee==="string"&&ee!=="")?`${I.owner}/${I.repo}#${I.display_ref}/${I.name}`:I.spec).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"rulebook"}function cg(I){let V=I===null?null:ug(I),X=el(V)&&Array.isArray(V.rulebooks)?V.rulebooks:[];return new Map(X.filter(dg).map((ee)=>[ee.spec,ee]))}function dg(I){return el(I)&&typeof I.spec==="string"&&typeof I.digest==="string"}function el(I){return!!I&&typeof I==="object"}function ug(I){try{return JSON.parse(I)}catch{return null}}function pg(I){return`sha256:${ng("sha256").update(I).digest("hex")}`}var nl="\r\x1B[2K",fg="\x1B[?25l",mg="\x1B[39m",gg="\x1B[?25h",hg=100,yg=0.55,vg=80,tl=["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"];function bg(I){return new Promise((V)=>setTimeout(V,I))}async function Gr(I,V={}){let X=V.output??process.stdout;if(!X.isTTY)return I;let ee=V.sleep??bg,ne=!1,te=I.then((de)=>(ne=!0,de),(de)=>{throw ne=!0,de});if(await Promise.race([te.then(()=>!0),ee(hg).then(()=>!1)]))return te;X.write(fg);try{for(let de=0;!ne;de+=1)X.write(`${nl}${qa(de*yg)}${tl[de%tl.length]}${mg} ${V.loadingMessage??"Loading…"}`),await Promise.race([te,ee(vg)]);return await te}finally{X.write(`${nl}${gg}`)}}async function ar(I,V,X,ee={}){let ne=V();if(I)await X();if(I&&ne.ready)await Gr(ne.ready,ee);return ne.finish()}import{stripVTControlCharacters as wg}from"node:util";var qr="amp plugins list",kg=/^\s*[✓✗]\s+cc-safety-net(?:\.ts)?\s+\(User Plugins\)\s+(\S+)\s*$/;function rl(I){if(!I.ampPluginListOutput)return{platform:"amp",status:"n/a"};let V=wg(I.ampPluginListOutput).split(`
|
|
27
|
+
`).map((X)=>kg.exec(X)?.[1]).find((X)=>X!==void 0);if(!V)return{platform:"amp",status:"n/a"};if(V!=="active")return{platform:"amp",status:"disabled",method:qr,configPath:qr,errors:[`Amp personal plugin cc-safety-net is ${V}; run "plugins: reload" in Amp or reinstall with install --amp`]};return{platform:"amp",status:"configured",method:qr,configPath:qr}}import{existsSync as Tg,readFileSync as Ag}from"node:fs";import{isAbsolute as cP,join as Eg}from"node:path";function lr(I){return Eg(I,".gemini","config","hooks.json")}var il=new Map([["run_command","auto"]]),sl="manage_task";var _g=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*(?:--agy-cli|-ac)(\s|["']|$)/;function Ig(I){if(!I||typeof I!=="object"||Array.isArray(I))return[];return Object.values(I).flatMap((V)=>{if(!V||typeof V!=="object"||Array.isArray(V))return[];let X=V,ee=X.PreToolUse;if(!Array.isArray(ee))return[];return ee.flatMap((ne)=>{if(!ne||typeof ne!=="object"||Array.isArray(ne))return[];let te=ne.hooks;if(!Array.isArray(te))return[];return te.flatMap((le)=>{if(!le||typeof le!=="object"||Array.isArray(le))return[];let de=le.command;if(typeof de!=="string"||!_g.test(de))return[];return[{command:de,enabled:X.enabled!==!1}]})})})}function al(I){let V=lr(I.environment.home);if(!Tg(V))return{platform:"antigravity-cli",status:"n/a",configPath:V};let X;try{X=Ig(JSON.parse(Ag(V,"utf-8")))}catch(ee){return{platform:"antigravity-cli",status:"n/a",configPath:V,errors:[`Failed to parse Antigravity hooks config ${V}: ${ee instanceof Error?ee.message:String(ee)}`]}}if(X.some((ee)=>ee.enabled))return{platform:"antigravity-cli",status:"configured",method:"hook config",configPath:V};if(X.length>0)return{platform:"antigravity-cli",status:"disabled",method:"hook config",configPath:V};return{platform:"antigravity-cli",status:"n/a",configPath:V}}import{existsSync as Og}from"node:fs";import{join as $n}from"node:path";var zr="cc-safety-net@cc-marketplace";function Wr(I){return I.env.get("CLAUDE_CONFIG_DIR")||$n(I.home,".claude")}function ll(I){return $n(I.env.get("CLAUDE_CODE_PLUGIN_CACHE_DIR")||$n(Wr(I),"plugins"),"installed_plugins.json")}function cl(I,V){let X=n(n(I,"plugins"),V);return Array.isArray(X)&&X.length>0}function Yr(I,V){let X=v(ll(I));return X.kind==="ok"&&cl(X.value,V)}function ui(I){return dl(ll(I),$n(Wr(I),"settings.json"))}function dl(I,V){let X=v(I);if(X.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(X.kind==="missing")return{platform:"claude-code",status:"n/a"};if(!cl(X.value,zr))return{platform:"claude-code",status:"n/a"};let ee=v(V);if(ee.kind==="unreadable")return{platform:"claude-code",status:"not-inspected"};if(!(ee.kind==="ok"&&n(n(ee.value,"enabledPlugins"),zr)===!0))return{platform:"claude-code",status:"disabled",method:"plugin config",configPath:V,errors:[`${zr} is installed but not enabled in Claude Code`]};return{platform:"claude-code",status:"configured",method:"plugin config",configPath:I}}function ul(I){let V=$n(I.home,".claude"),X=$n(V,"plugins","installed_plugins.json");if(dl(X,$n(V,"settings.json")).status!=="configured")return;let ee=v(X),ne=ee.kind==="ok"?n(n(ee.value,"plugins"),zr):void 0,te=(Array.isArray(ne)?ne:[]).filter((Se)=>n(Se,"scope")==="user").map((Se)=>n(Se,"installPath")).find((Se)=>typeof Se==="string");if(!te)return;let le=$n(te,".cursor-plugin","plugin.json"),de=v(le),be=de.kind==="ok"?n(de.value,"hooks"):void 0;return typeof be==="string"&&Og($n(te,be))?le:void 0}function pl(I){return ui(I.environment)}var fl="Start Codex, open `/hooks`, select the cc-safety-net PreToolUse hook, and press `t` to trust it.";function ml(I){if(!I.codexPluginListOutput)return{platform:"codex",status:"n/a"};let V=I.codexPluginListOutput.split(`
|
|
28
28
|
`).find((X)=>X.includes("https://github.com/kenryu42/cc-safety-net.git"));if(!V)return{platform:"codex",status:"n/a"};if(!V.includes("installed,"))return{platform:"codex",status:"n/a"};if(!V.includes("installed, enabled"))return{platform:"codex",status:"disabled",method:"codex plugin list",configPath:"codex plugin list",errors:["Codex plugin line for https://github.com/kenryu42/cc-safety-net.git must contain installed, enabled."]};return{platform:"codex",status:"configured",method:"codex plugin list",configPath:"codex plugin list",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 eo,readdirSync as $g,readFileSync as Dg}from"node:fs";import{join as vn}from"node:path";function gn(I){let V="",X=0,ee=!1,ne=!1,te=-1;while(X<I.length){let le=I[X],de=I[X+1];if(ne){V+=le,ne=!1,X++;continue}if(le==='"'&&!ee){ee=!0,te=-1,V+=le,X++;continue}if(le==='"'&&ee){ee=!1,V+=le,X++;continue}if(le==="\\"&&ee){ne=!0,V+=le,X++;continue}if(ee){V+=le,X++;continue}if(le==="/"&&de==="/"){while(X<I.length&&I[X]!==`
|
|
29
|
-
`)X++;continue}if(le==="/"&&de==="*"){X+=2;while(X<I.length-1){if(I[X]==="*"&&I[X+1]==="/"){X+=2;break}X++}continue}if(le===","){te=V.length,V+=le,X++;continue}if(le==="}"||le==="]"){if(te!==-1){let
|
|
29
|
+
`)X++;continue}if(le==="/"&&de==="*"){X+=2;while(X<I.length-1){if(I[X]==="*"&&I[X+1]==="/"){X+=2;break}X++}continue}if(le===","){te=V.length,V+=le,X++;continue}if(le==="}"||le==="]"){if(te!==-1){let be=V.slice(te+1);if(/^\s*$/.test(be))V=V.slice(0,te)+be}te=-1,V+=le,X++;continue}if(!/\s/.test(le))te=-1;V+=le,X++}return V}function hl(I,V,X){let ee=V+1,ne=!1;while(ee<I.length){if(ne){ne=!1,ee++;continue}if(I[ee]==="\\"){ne=!0,ee++;continue}if(I[ee]==='"')return ee+1;ee++}throw Error(X)}function fi(I,V,X){let ee=I[V],ne=ee==="["?"]":"}",te=0,le=V;while(le<I.length){let de=X.skipComment?.(I,le)??le;if(de!==le){le=de;continue}if(I[le]==='"'){le=hl(I,le,X.stringError);continue}if(I[le]===ee)te++;if(I[le]===ne){if(te--,te===0)return le}le++}throw Error(X.bracketError)}function yl(I,V){let X=I.lastIndexOf(`
|
|
30
30
|
`,V)+1;return/^[ \t]*/.exec(I.slice(X))?.[0]??""}function vl(I,V){let X=V.end+(/^\s*/.exec(I.slice(V.end))?.[0].length??0);if(I[X]===","){let le=I[X+1]===`
|
|
31
31
|
`?X+2:X+1;return`${I.slice(0,V.start)}${I.slice(le)}`}let ee=I.slice(0,V.start).search(/\s*$/)-1;if(I[ee]!==",")return`${I.slice(0,V.start)}${I.slice(V.end)}`;let ne=I.lastIndexOf(`
|
|
32
32
|
`,ee-1),te=ne!==-1&&/^\s*$/.test(I.slice(ne+1,ee))?ne:ee;return`${I.slice(0,te)}${I.slice(V.end)}`}function pi(I,V){if(I.startsWith("//",V)){let X=I.indexOf(`
|
|
33
|
-
`,V+2);return X===-1?I.length:X+1}if(I.startsWith("/*",V)){let X=I.indexOf("*/",V+2);return X===-1?I.length:X+2}return V}function gl(I,V){let X=V;while(X<I.length){if(/\s/.test(I[X]??"")){X++;continue}let ee=pi(I,X);if(ee===X)return X;X=ee}return X}function bl(I,V,X){let ee=0,ne=0;while(ne<I.length){let te=pi(I,ne);if(te!==ne){ne=te;continue}if(I[ne]==='"'){let le=hl(I,ne,X.stringError);if(ee===1&&JSON.parse(I.slice(ne,le))===V){let de=gl(I,le),
|
|
33
|
+
`,V+2);return X===-1?I.length:X+1}if(I.startsWith("/*",V)){let X=I.indexOf("*/",V+2);return X===-1?I.length:X+2}return V}function gl(I,V){let X=V;while(X<I.length){if(/\s/.test(I[X]??"")){X++;continue}let ee=pi(I,X);if(ee===X)return X;X=ee}return X}function bl(I,V,X){let ee=0,ne=0;while(ne<I.length){let te=pi(I,ne);if(te!==ne){ne=te;continue}if(I[ne]==='"'){let le=hl(I,ne,X.stringError);if(ee===1&&JSON.parse(I.slice(ne,le))===V){let de=gl(I,le),be=gl(I,de+1);if(I[de]===":"&&I[be]==="[")return{start:be,end:fi(I,be,{skipComment:pi,...X})}}ne=le;continue}if(I[ne]==="{"||I[ne]==="[")ee++;if(I[ne]==="}"||I[ne]==="]")ee--;ne++}return}var En="cc-safety-net@cc-marketplace",Zr=["cc-marketplace","cc-safety-net"],wl=["_direct","copilot-safety-net"],kl=["cc-marketplace","safety-net"],Cl="safety-net@cc-marketplace";function Xr(I,V){let X=V.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`(^|[^a-z0-9-])${X}([^a-z0-9-]|$)`,"m").test(I??"")}function xl(I){return Xr(I,"cc-safety-net@cc-marketplace")}function Pl(I){return Xr(I,"cc-marketplace")}function Sl(I){return Xr(I,"copilot-safety-net")}function Rl(I){return Xr(I,"safety-net@cc-marketplace")}function Qr(I){if(!I?.includes("cc-safety-net"))return!1;return/(^|\s)hook\s+(?:[^\s]+\s+)*(--copilot-cli|-cp)(\s|$)/.test(I)}function Tl(I,V){if(!I)return null;let X=I.match(/(\d+)\.(\d+)\.(\d+)/);if(!X)return null;let ee=[Number(X[1]),Number(X[2]),Number(X[3])];for(let ne=0;ne<V.length;ne++){let te=ee[ne]??0,le=V[ne]??0;if(te!==le)return te>le}return!0}function Ng(I){return Tl(I,[0,0,422])}function Lg(I){return Tl(I,[1,0,8])}function ur(I){return I.env.get("COPILOT_HOME")||vn(I.home,".copilot")}function Al(I){return I.disableAllHooks!==!0&&_l(I)}function _l(I){return(I.hooks?.preToolUse??[]).some((X)=>{if(X.type!==void 0&&X.type!=="command")return!1;return Qr(X.command)||Qr(X.bash)||Qr(X.powershell)||Qr(X.exec&&[X.exec,...X.args??[]].join(" "))})}function cr(I){return I===void 0||typeof I==="string"}function jg(I){return I===void 0||Array.isArray(I)&&I.every((V)=>typeof V==="string")}function Fg(I){if(!I||typeof I!=="object"||Array.isArray(I))return!1;let V=I;if(V.disableAllHooks!==void 0&&typeof V.disableAllHooks!=="boolean")return!1;if(V.hooks===void 0)return!0;if(!V.hooks||typeof V.hooks!=="object"||Array.isArray(V.hooks))return!1;let X=V.hooks.preToolUse;if(X===void 0)return!0;return Array.isArray(X)&&X.every((ee)=>ee!==null&&typeof ee==="object"&&!Array.isArray(ee)&&cr(ee.type)&&cr(ee.command)&&cr(ee.bash)&&cr(ee.powershell)&&cr(ee.exec)&&jg(ee.args))}function mi(I,V){try{let X=JSON.parse(gn(Dg(I,"utf-8")));if(!Fg(X)){V?.push(`Invalid hook config ${I}: hooks.preToolUse must be an array of hook objects`);return}return X}catch(X){V?.push(`Failed to parse ${I}: ${X instanceof Error?X.message:String(X)}`);return}}function Il(I,V){try{return $g(I).filter((X)=>X.endsWith(".json")).sort((X,ee)=>X.localeCompare(ee))}catch(X){return V?.push(`Failed to read ${I}: ${X instanceof Error?X.message:String(X)}`),[]}}function Hg(I,V){if(!eo(I))return[];let X=[];for(let ee of Il(I,V)){let ne=vn(I,ee),te=mi(ne,V);if(te&&Al(te))X.push(ne)}return X}function dr(I,V){if(!eo(I))return;let X=mi(I,V);if(!X)return;return{path:I,config:X}}function El(I,V,X,ee){if(V){I.push(`GitHub Copilot CLI ${V} does not support ${X}; requires ${ee}+`);return}I.push(`GitHub Copilot CLI version unavailable; skipping ${X} because it requires ${ee}+`)}function Mg(I){for(let V of I){if(V?.config.disableAllHooks===!0)return V.path;if(V?.config.disableAllHooks===!1)return}return}function Ug(I,V,X,ee){let ne=ur(I),te=vn(V,".github","hooks"),le=vn(ne,"hooks"),de=vn(V,".github","copilot"),be=vn(V,".claude"),Se=Lg(X),Ie=Se===!0?ee:void 0,$e=[dr(vn(de,"settings.local.json"),Ie),dr(vn(de,"settings.json"),Ie),dr(vn(be,"settings.local.json"),Ie),dr(vn(be,"settings.json"),Ie)],Le=dr(vn(ne,"settings.json"),Ie),Ne=[Le?.config.disableAllHooks===!0?void 0:Le];if(Se!==!1){let nn=Mg($e);if(nn){if(Se===null)ee.push(`GitHub Copilot CLI version unavailable; treating disableAllHooks in ${nn} as active`);return{activeConfigPaths:[],repoInlineSources:$e,disabledBy:nn}}}let Fe=Hg(te,ee),Be=Ng(X),Me=Be===!0?ee:void 0,tn=eo(le)?Il(le,Me):[],en=[];for(let nn of tn){let sn=vn(le,nn),Sn=mi(sn,Me);if(Sn&&Al(Sn))en.push(sn)}if(Be!==!0&&en.length>0)El(ee,X,`user hook files in ${le}`,"0.0.422"),en.length=0;let on=[];for(let nn of[...$e,...Ne]){if(!nn)continue;if(!_l(nn.config))continue;if(Se===!0){on.push(nn);continue}El(ee,X,"inline hook definitions in Copilot config files","1.0.8");break}let ln=(nn)=>nn.filter((sn)=>!!sn&&on.includes(sn)).map((sn)=>sn.path);return{activeConfigPaths:[...ln($e),...Fe,...ln(Ne),...en],repoInlineSources:$e}}function Ol(I){let V=[],X=Ug(I.environment,I.cwd,I.copilotCliVersion,V);if(X.disabledBy)return{platform:"copilot-cli",status:"disabled",method:"hook config",configPath:X.disabledBy,configPaths:[X.disabledBy],errors:V.length>0?V:void 0};let ee=ur(I.environment),ne=vn(ee,"installed-plugins",...Zr),te=eo(ne),le=vn(ee,"settings.json"),de=v(le,gn),be=(Ne)=>n(n(Ne,"enabledPlugins"),En),Se=X.repoInlineSources.find((Ne)=>typeof be(Ne?.config)==="boolean"),Ie=Se??(de.kind==="ok"?{path:le,config:de.value}:void 0);if(te&&!Se&&de.kind==="unreadable")return{platform:"copilot-cli",status:"not-inspected"};let $e=te&&Ie!==void 0&&be(Ie.config)===!1;if($e&&X.activeConfigPaths.length===0)return{platform:"copilot-cli",status:"disabled",method:"plugin config",configPath:Ie.path,errors:[`${En} is installed but not enabled in Copilot CLI`]};let Le=te&&!$e;if(Le||X.activeConfigPaths.length>0){let Ne=X.activeConfigPaths[0];return{platform:"copilot-cli",status:"configured",method:Le?"plugin config":"hook config",configPath:Ne??(Le?ne:void 0),configPaths:X.activeConfigPaths.length>0?X.activeConfigPaths:void 0,errors:V.length>0?V:void 0}}return{platform:"copilot-cli",status:"n/a",errors:V.length>0?V:void 0}}import{existsSync as Ci,readdirSync as nh,readFileSync as th}from"node:fs";import{join as ki}from"node:path";import{existsSync as bi,mkdirSync as zg,readFileSync as Wg,rmSync as Yg}from"node:fs";import{dirname as Zg,join as no}from"node:path";import{existsSync as Bg,renameSync as Gg,statSync as qg,writeFileSync as Vg}from"node:fs";function an(I,V){let X=`${I}.${process.pid}.tmp`;Vg(X,V,Bg(I)?{mode:qg(I).mode&511}:{}),Gg(X,I)}import{spawn as Kg}from"node:child_process";function Jg(I){return I.join(" ")}function gi(I,V,X){return[`Failed to run ${Jg(I)}${V===null?"":` (exit ${V})`}.`,X.trim()].filter(Boolean).join(`
|
|
34
34
|
`)}function hi(I){let V={stdout:"",stderr:""};return I.stdout.setEncoding("utf-8"),I.stderr.setEncoding("utf-8"),I.stdout.on("data",(X)=>{V.stdout+=X}),I.stderr.on("data",(X)=>{V.stderr+=X}),V}function pn(I,V){return new Promise((X,ee)=>{let ne=Wn([...I],process.env),te=Kg(ne.cmd,ne.args,{stdio:["ignore","pipe","pipe"]}),le=hi(te),de=()=>[le.stdout,le.stderr].filter(Boolean).join(`
|
|
35
|
-
`),
|
|
36
|
-
${de()}`.trim())))},
|
|
35
|
+
`),be=V?.timeoutMs??120000,Se=setTimeout(()=>{te.kill(),ee(Error(gi(I,null,`Timed out after ${be}ms.
|
|
36
|
+
${de()}`.trim())))},be);te.on("error",(Ie)=>{clearTimeout(Se),ee(Error(gi(I,null,`${Ie.message}
|
|
37
37
|
${de()}`.trim())))}),te.on("close",(Ie)=>{if(clearTimeout(Se),Ie!==0){ee(Error(gi(I,Ie,de())));return}X(V?.stdoutOnly?le.stdout:de())})})}async function yi(I){for(let V of I)await pn(V)}async function $l(I){for(let V of I)try{await pn(V)}catch(X){console.warn(X instanceof Error?X.message:String(X))}}var bn=Object.fromEntries(ir.map((I)=>[I.id,`npx -y cc-safety-net hook ${I.flags[1]}`]));var fr=bn.cursor,Dl=30;function ro(I){return no(I.home,".cursor","hooks.json")}var pr="cc-safety-net";function wi(I){let V=no(I.home,".cursor","plugins");return{cache:no(V,"cache",pr),marketplaceClone:no(V,"marketplaces","github.com","kenryu42","cc-safety-net")}}async function Nl(I){let V=Object.values(wi(I));if(!V.some((ee)=>bi(ee)))return;let X="No marketplace matches";return await pn(["cursor-agent","plugin","marketplace","remove",pr]).catch((ee)=>{if(!(ee instanceof Error&&ee.message.includes(X)))throw ee}),V.forEach((ee)=>Yg(ee,{recursive:!0,force:!0})),[`Removed the ${pr} marketplace from your Cursor account.`,"If /plugins in cursor-agent still lists CC Safety Net as installed, uninstall it there."].join(`
|
|
38
38
|
`)}function Zn(I){return typeof I==="object"&&I!==null&&!Array.isArray(I)}function vi(){return{command:fr,timeout:Dl,failClosed:!0}}function to(I){return Zn(I)&&I.command===fr}function Xg(I){return Object.keys(I).length===3&&I.command===fr&&I.timeout===Dl&&I.failClosed===!0}function Qg(I){try{return JSON.parse(Wg(I,"utf-8"))}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Cursor hooks config ${I}: ${V.message}`);throw V}}function Ll(I){let V=Qg(I);if(!Zn(V))throw Error(`Cursor hooks config ${I} must be a JSON object`);if(V.version!==1)throw Error(`Cursor hooks config ${I} must set "version": 1`);if(V.hooks!==void 0&&!Zn(V.hooks))throw Error(`Cursor hooks config ${I} "hooks" must be an object`);let X=Zn(V.hooks)?V.hooks.preToolUse:void 0;if(X!==void 0&&!Array.isArray(X))throw Error(`Cursor hooks config ${I} "hooks.preToolUse" must be an array`);return V}function jl(I){let V=Zn(I.hooks)?I.hooks.preToolUse:void 0;return Array.isArray(V)?V:[]}function eh(I){if(!I.some(to))return[...I,vi()];return I.reduce((V,X)=>{if(!to(X))return V.result.push(X),V;if(!V.inserted)V.result.push(vi()),V.inserted=!0;return V},{result:[],inserted:!1}).result}function Fl(I,V,X){let ee=Zn(V.hooks)?V.hooks:{},ne={...V,hooks:{...ee,preToolUse:X}};an(I,`${JSON.stringify(ne,null,2)}
|
|
39
39
|
`)}function Hl(I){let V=ro(I);if(!bi(V))return zg(Zg(V),{recursive:!0}),an(V,`${JSON.stringify({version:1,hooks:{preToolUse:[vi()]}},null,2)}
|
|
40
40
|
`),{path:V,alreadyInstalled:!1};let X=Ll(V),ee=jl(X),ne=ee.filter(to);if(Zn(X.hooks)&&Array.isArray(X.hooks.preToolUse)&&ne.length===1&&ne[0]!==void 0&&Xg(ne[0]))return{path:V,alreadyInstalled:!0};return Fl(V,X,eh(ee)),{path:V,alreadyInstalled:!1}}function Ml(I){let V=ro(I);if(!bi(V))return{path:V,alreadyInstalled:!1};let X=Ll(V),ee=jl(X),ne=ee.filter((te)=>!to(te));if(ne.length===ee.length)return{path:V,alreadyInstalled:!1};return Fl(V,X,ne),{path:V,alreadyInstalled:!0}}function rh(I){if(!I||typeof I!=="object"||Array.isArray(I))return[];let V=I.hooks;if(!V||typeof V!=="object"||Array.isArray(V))return[];let X=V.preToolUse;if(!Array.isArray(X))return[];return X.filter((ee)=>!!ee&&typeof ee==="object"&&!Array.isArray(ee)&&ee.command===fr)}function oh(I){let V=[];if(I.length>1)V.push("Multiple managed cc-safety-net hooks found; reinstall to collapse duplicates");let X=I[0];if(X&&X.failClosed!==!0)V.push('Managed hook is missing "failClosed": true; reinstall to repair');if(X&&X.timeout!==30)V.push('Managed hook "timeout" is not 30; reinstall to repair');return V}var oo="Claude Code plugin",xi="Cursor plugin";function ih(I){let V=ki(wi(I).cache,pr);if(!Ci(V))return{};try{return{version:nh(V).map((X)=>ki(V,X)).find((X)=>Ci(ki(X,".cache-complete")))}}catch{return{unreadable:V}}}function sh(I,V){if(V){let ne=["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:xi,configPath:V,duplicate:`The Cursor plugin also runs this check, so every tool call is checked twice. ${ne} 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:`${ne} If /plugins in cursor-agent does not list CC Safety Net as installed, run \`cc-safety-net install --cursor\`.`}}let X=ul(I);if(!X)return;let ee="Cursor runs the Claude Code plugin only while it imports Claude Code plugins, which doctor cannot check.";return{method:oo,configPath:X,duplicate:`The Claude Code plugin also runs this check in Cursor, so every tool call is checked twice. ${ee} If Cursor runs it, run \`cc-safety-net uninstall --cursor\` to remove this hook.`,alone:`${ee} If it stops, run \`cc-safety-net install --cursor\`.`}}function Ul(I){let V=ah(I),X=ih(I.environment);if(X.unreadable)return V.status==="configured"?{...V,errors:[...V.errors??[],`Cannot read ${X.unreadable}, so doctor cannot tell whether the Cursor plugin also runs this check.`]}:{platform:"cursor",status:"not-inspected"};let ee=sh(I.environment,X.version);if(!ee)return V;if(V.status==="configured")return{...V,errors:[...V.errors??[],ee.duplicate]};return{platform:"cursor",status:"configured",method:ee.method,configPath:ee.configPath,errors:[...V.errors??[],ee.alone]}}function ah(I){let V=ro(I.environment);if(!Ci(V))return{platform:"cursor",status:"n/a",configPath:V};let X;try{X=JSON.parse(th(V,"utf-8"))}catch(te){return{platform:"cursor",status:"n/a",configPath:V,errors:[`Failed to parse Cursor hooks config ${V}: ${te instanceof Error?te.message:String(te)}`]}}let ee=rh(X);if(ee.length===0)return{platform:"cursor",status:"n/a",configPath:V};let ne=oh(ee);return{platform:"cursor",status:"configured",method:"hook config",configPath:V,errors:ne.length>0?ne:void 0}}import{existsSync as fh}from"node:fs";import{existsSync as ql,mkdirSync as lh,readFileSync as ch}from"node:fs";import{dirname as dh,join as Ri}from"node:path";function Pi(I){return typeof I==="object"&&I!==null&&!Array.isArray(I)}function Si(I,V){return Pi(I)&&I.command===V}function Bl(I,V){return Pi(I)&&Array.isArray(I.hooks)&&I.hooks.some((X)=>Si(X,V))}function Xn(I,V){return{hooks:[{type:"command",command:I,timeout:V}]}}function Dn(I,V){return I.flatMap((X)=>{if(!Pi(X)||!Array.isArray(X.hooks))return[X];let ee=X.hooks.filter((ne)=>!Si(ne,V));if(ee.length===X.hooks.length)return[X];return ee.length===0?[]:[{...X,hooks:ee}]})}function Vt(I,V,X){let ee=I.filter((ne)=>Bl(ne,V));return ee.length===1&&JSON.stringify(ee[0])===JSON.stringify(Xn(V,X))}function Kt(I,V){return I.find((X)=>Bl(X,V))}function Jt(I,V,X){let ee=Array.isArray(I.hooks)?I.hooks.find((ne)=>Si(ne,V)):void 0;return[...I.matcher===void 0||I.matcher===""||I.matcher==="*"?[]:['Managed hook has a "matcher" that narrows coverage; reinstall to repair'],...ee?.type==="command"?[]:['Managed hook "type" is not "command"; reinstall to repair'],...ee?.timeout===X?[]:[`Managed hook "timeout" is not ${X}; reinstall to repair`]]}var Qn=bn.devin,io=30,uh={config:{},hooks:{},preToolUse:[]};function so(I,V=process.platform){let X=V==="win32"?I.env.get("APPDATA")||Ri(I.home,"AppData","Roaming"):I.env.get("XDG_CONFIG_HOME")||Ri(I.home,".config");return Ri(X,"devin","config.json")}function Gl(I){return typeof I==="object"&&I!==null&&!Array.isArray(I)}function ph(I){try{return{ok:!0,value:JSON.parse(gn(ch(I,"utf-8")))}}catch(V){return{ok:!1,message:V instanceof Error?V.message:String(V)}}}function Ei(I){let V=ph(I);if(!V.ok)return`Failed to parse Devin CLI config ${I}: ${V.message}`;let X=V.value;if(!Gl(X))return`Devin CLI config ${I} must be a JSON object`;let ee=X.hooks===void 0?{}:X.hooks;if(!Gl(ee))return`Devin CLI config ${I} "hooks" must be an object`;let ne=ee.PreToolUse===void 0?[]:ee.PreToolUse;if(!Array.isArray(ne))return`Devin CLI config ${I} "hooks.PreToolUse" must be an array`;return{config:X,hooks:ee,preToolUse:ne}}function Vl(I){let V=Ei(I);if(typeof V==="string")throw Error(V);return V}function Kl(I,V,X){let ee={...V.config,hooks:{...V.hooks,PreToolUse:X}};an(I,`${JSON.stringify(ee,null,2)}
|
|
41
41
|
`)}function Jl(I){let V=so(I),X=ql(V)?Vl(V):uh;if(Vt(X.preToolUse,Qn,io))return{path:V,alreadyInstalled:!0};return lh(dh(V),{recursive:!0}),Kl(V,X,[...Dn(X.preToolUse,Qn),Xn(Qn,io)]),{path:V,alreadyInstalled:!1}}function zl(I){let V=so(I);if(!ql(V))return{path:V,alreadyInstalled:!1};let X=Vl(V),ee=Dn(X.preToolUse,Qn);if(JSON.stringify(ee)===JSON.stringify(X.preToolUse))return{path:V,alreadyInstalled:!1};return Kl(V,X,ee),{path:V,alreadyInstalled:!0}}function Wl(I){let V=so(I.environment);if(!fh(V))return{platform:"devin",status:"n/a",configPath:V};let X=Ei(V);if(typeof X==="string")return{platform:"devin",status:"n/a",configPath:V,errors:[X]};let ee=Kt(X.preToolUse,Qn);if(!ee)return{platform:"devin",status:"n/a",configPath:V};let ne=Jt(ee,Qn,io);return{platform:"devin",status:"configured",method:"hook config",configPath:V,errors:ne.length>0?ne:void 0}}import{existsSync as wh,readFileSync as kh}from"node:fs";import{existsSync as zt,mkdirSync as mh,readFileSync as gh,rmSync as hh}from"node:fs";import{dirname as yh,join as Ai}from"node:path";var et=bn.droid,ao=30;function lo(I){return Ai(I.home,".factory","hooks.json")}function Yl(I){return Ai(I.home,".factory","settings.json")}function Zl(I){return Ai(I.home,".factory","hooks","hooks.json")}function Ti(I){return typeof I==="object"&&I!==null&&!Array.isArray(I)}function Xl(I){try{return JSON.parse(gn(gh(I,"utf-8")))}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Factory Droid hooks config ${I}: ${V.message}`);throw V}}function _i(I){let V=Xl(I);if(!Ti(V))throw Error(`Factory Droid hooks config ${I} must be a JSON object`);if(V.PreToolUse===void 0||Array.isArray(V.PreToolUse))return V;throw Error(`Factory Droid hooks config ${I} "PreToolUse" must be an array`)}function vh(I){if(!zt(I))return{};let V=Xl(I);return Ti(V)&&Ti(V.hooks)&&V.hooks.PreToolUse!==void 0?{PreToolUse:V.hooks.PreToolUse}:{}}function bh(I){let V=Zl(I);return{...vh(Yl(I)),...zt(V)?_i(V):{}}}function Ql(I){return Array.isArray(I.PreToolUse)?I.PreToolUse:[]}function ec(I,V,X){an(I,`${JSON.stringify({...V,PreToolUse:X},null,2)}
|
|
42
|
-
`)}function nc(I){let V=lo(I),X=zt(V),ee=X?_i(V):bh(I),ne=Ql(ee);if(X&&Vt(ne,et,ao))return{path:V,alreadyInstalled:!0};return mh(yh(V),{recursive:!0}),ec(V,ee,[...Dn(ne,et),Xn(et,ao)]),{path:V,alreadyInstalled:!1}}function tc(I){let V=lo(I);if(!zt(V))return{path:V,alreadyInstalled:!1};let X=_i(V),ee=Ql(X),ne=Dn(ee,et);if(JSON.stringify(ne)===JSON.stringify(ee))return{path:V,alreadyInstalled:!1};let te=zt(Yl(I))||zt(Zl(I));if(ne.length===0&&Object.keys(X).length===1&&!te)return hh(V),{path:V,alreadyInstalled:!0};return ec(V,X,ne),{path:V,alreadyInstalled:!0}}function rc(I){let V=lo(I.environment);if(!wh(V))return{platform:"droid",status:"n/a",configPath:V};let X;try{X=JSON.parse(gn(kh(V,"utf-8")))}catch(le){return{platform:"droid",status:"n/a",configPath:V,errors:[`Failed to parse Factory Droid hooks config ${V}: ${le instanceof Error?le.message:String(le)}`]}}let ee=typeof X==="object"&&X!==null&&"PreToolUse"in X?X.PreToolUse:void 0,ne=Kt(Array.isArray(ee)?ee:[],et);if(!ne)return{platform:"droid",status:"n/a",configPath:V};let te=[...ne.commandRegex===void 0||ne.commandRegex===""?[]:['Managed hook has a "commandRegex" that narrows coverage; reinstall to repair'],...Jt(ne,et,ao)];return{platform:"droid",status:"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{existsSync as Ch}from"node:fs";import{join as Ii}from"node:path";var Oi="gemini-safety-net";function $i(I){let V=Ii(I.home,".gemini","extensions"),X=Ii(V,Oi);if(!Ch(X))return{platform:"gemini-cli",status:"n/a"};let ee=Ii(V,"extension-enablement.json"),ne=
|
|
43
|
-
`)}function dc(I){let V=po(I);if(!sc(V))return xh(Sh(V),{recursive:!0}),co(V,{},[Di]),{path:V,alreadyInstalled:!1};let X=lc(ac(V,"utf-8"));if(!X)return co(V,{},[Di]),{path:V,alreadyInstalled:!1};let ee=cc(X);if(Vt(ee,Mn,uo))return{path:V,alreadyInstalled:!0};return co(V,X,[...Dn(ee,Mn),Di]),{path:V,alreadyInstalled:!1}}function uc(I){let V=po(I);if(!sc(V))return{path:V,alreadyInstalled:!1};let X=lc(ac(V,"utf-8"));if(!X)return{path:V,alreadyInstalled:!1};let ee=cc(X),ne=Dn(ee,Mn);if(JSON.stringify(ne)===JSON.stringify(ee))return{path:V,alreadyInstalled:!1};let te=fo(X.hooks)?X.hooks:{};if(ne.length===0&&Object.keys(X).length===1&&Object.keys(te).length===1)return Ph(V),{path:V,alreadyInstalled:!0};return co(V,X,ne),{path:V,alreadyInstalled:!0}}function Ni(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}function Ah(I){try{return Eh(I,{throwIfNoEntry:!1})?.isFile()===!0?fc(I,"utf-8"):""}catch{return}}function mc(I){let V=po(I.environment);if(!Rh(V))return{platform:"grok-build",status:"n/a",configPath:V};let X;try{X=JSON.parse(fc(V,"utf-8"))}catch($e){return{platform:"grok-build",status:"n/a",configPath:V,errors:[`Failed to parse Grok Build hooks config ${V}: ${$e instanceof Error?$e.message:String($e)}`]}}let ee=Ni(X)&&Ni(X.hooks)&&Array.isArray(X.hooks.PreToolUse)?X.hooks.PreToolUse:[],ne=Kt(ee,Mn);if(!ne)return{platform:"grok-build",status:"n/a",configPath:V};let te=Array.isArray(ne.hooks)?ne.hooks.findIndex(($e)=>Ni($e)&&$e.command===Mn):-1,le=`global/cc-safety-net:pre_tool_use[${ee.indexOf(ne)}].hooks[${te}]`,de=Th(pc(pc(V)),"disabled-hooks"),
|
|
44
|
-
`).some(($e)=>$e.trim()===le)===!0,Ie=[...
|
|
42
|
+
`)}function nc(I){let V=lo(I),X=zt(V),ee=X?_i(V):bh(I),ne=Ql(ee);if(X&&Vt(ne,et,ao))return{path:V,alreadyInstalled:!0};return mh(yh(V),{recursive:!0}),ec(V,ee,[...Dn(ne,et),Xn(et,ao)]),{path:V,alreadyInstalled:!1}}function tc(I){let V=lo(I);if(!zt(V))return{path:V,alreadyInstalled:!1};let X=_i(V),ee=Ql(X),ne=Dn(ee,et);if(JSON.stringify(ne)===JSON.stringify(ee))return{path:V,alreadyInstalled:!1};let te=zt(Yl(I))||zt(Zl(I));if(ne.length===0&&Object.keys(X).length===1&&!te)return hh(V),{path:V,alreadyInstalled:!0};return ec(V,X,ne),{path:V,alreadyInstalled:!0}}function rc(I){let V=lo(I.environment);if(!wh(V))return{platform:"droid",status:"n/a",configPath:V};let X;try{X=JSON.parse(gn(kh(V,"utf-8")))}catch(le){return{platform:"droid",status:"n/a",configPath:V,errors:[`Failed to parse Factory Droid hooks config ${V}: ${le instanceof Error?le.message:String(le)}`]}}let ee=typeof X==="object"&&X!==null&&"PreToolUse"in X?X.PreToolUse:void 0,ne=Kt(Array.isArray(ee)?ee:[],et);if(!ne)return{platform:"droid",status:"n/a",configPath:V};let te=[...ne.commandRegex===void 0||ne.commandRegex===""?[]:['Managed hook has a "commandRegex" that narrows coverage; reinstall to repair'],...Jt(ne,et,ao)];return{platform:"droid",status:"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{existsSync as Ch}from"node:fs";import{join as Ii}from"node:path";var Oi="gemini-safety-net";function $i(I){let V=Ii(I.home,".gemini","extensions"),X=Ii(V,Oi);if(!Ch(X))return{platform:"gemini-cli",status:"n/a"};let ee=Ii(V,"extension-enablement.json"),ne=v(ee);if(ne.kind==="unreadable")return{platform:"gemini-cli",status:"not-inspected"};let te=ne.kind==="ok"?n(n(ne.value,Oi),"overrides"):void 0;if(Array.isArray(te)&&te.some((de)=>typeof de==="string"&&de.startsWith("!")))return{platform:"gemini-cli",status:"disabled",method:"extension config",configPath:ee,errors:[`${Oi} is disabled in Gemini CLI`]};return{platform:"gemini-cli",status:"configured",method:"extension config",configPath:X}}function oc(I){return $i(I.environment)}import{existsSync as Rh,readFileSync as fc,statSync as Eh}from"node:fs";import{dirname as pc,join as Th}from"node:path";import{existsSync as sc,mkdirSync as xh,readFileSync as ac,rmSync as Ph}from"node:fs";import{dirname as Sh,join as ic}from"node:path";var Mn=bn["grok-build"],uo=30,Di=Xn(Mn,uo);function po(I){return ic(I.env.get("GROK_HOME")??ic(I.home,".grok"),"hooks","cc-safety-net.json")}function fo(I){return typeof I==="object"&&I!==null&&!Array.isArray(I)}function lc(I){try{let V=JSON.parse(I);return fo(V)?V:null}catch{return null}}function cc(I){let V=fo(I.hooks)?I.hooks.PreToolUse:void 0;return Array.isArray(V)?V:[]}function co(I,V,X){let ee=fo(V.hooks)?V.hooks:{};an(I,`${JSON.stringify({...V,hooks:{...ee,PreToolUse:X}},null,2)}
|
|
43
|
+
`)}function dc(I){let V=po(I);if(!sc(V))return xh(Sh(V),{recursive:!0}),co(V,{},[Di]),{path:V,alreadyInstalled:!1};let X=lc(ac(V,"utf-8"));if(!X)return co(V,{},[Di]),{path:V,alreadyInstalled:!1};let ee=cc(X);if(Vt(ee,Mn,uo))return{path:V,alreadyInstalled:!0};return co(V,X,[...Dn(ee,Mn),Di]),{path:V,alreadyInstalled:!1}}function uc(I){let V=po(I);if(!sc(V))return{path:V,alreadyInstalled:!1};let X=lc(ac(V,"utf-8"));if(!X)return{path:V,alreadyInstalled:!1};let ee=cc(X),ne=Dn(ee,Mn);if(JSON.stringify(ne)===JSON.stringify(ee))return{path:V,alreadyInstalled:!1};let te=fo(X.hooks)?X.hooks:{};if(ne.length===0&&Object.keys(X).length===1&&Object.keys(te).length===1)return Ph(V),{path:V,alreadyInstalled:!0};return co(V,X,ne),{path:V,alreadyInstalled:!0}}function Ni(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}function Ah(I){try{return Eh(I,{throwIfNoEntry:!1})?.isFile()===!0?fc(I,"utf-8"):""}catch{return}}function mc(I){let V=po(I.environment);if(!Rh(V))return{platform:"grok-build",status:"n/a",configPath:V};let X;try{X=JSON.parse(fc(V,"utf-8"))}catch($e){return{platform:"grok-build",status:"n/a",configPath:V,errors:[`Failed to parse Grok Build hooks config ${V}: ${$e instanceof Error?$e.message:String($e)}`]}}let ee=Ni(X)&&Ni(X.hooks)&&Array.isArray(X.hooks.PreToolUse)?X.hooks.PreToolUse:[],ne=Kt(ee,Mn);if(!ne)return{platform:"grok-build",status:"n/a",configPath:V};let te=Array.isArray(ne.hooks)?ne.hooks.findIndex(($e)=>Ni($e)&&$e.command===Mn):-1,le=`global/cc-safety-net:pre_tool_use[${ee.indexOf(ne)}].hooks[${te}]`,de=Th(pc(pc(V)),"disabled-hooks"),be=Ah(de),Se=be?.split(`
|
|
44
|
+
`).some(($e)=>$e.trim()===le)===!0,Ie=[...be===void 0?[`Cannot read ${de}, so doctor cannot tell whether Grok Build skips the hook`]:[],...Se?[`Grok Build skips the hook: ${le} is listed in ${de}; enable it in /hooks`]:[],...Jt(ne,Mn,uo)];return{platform:"grok-build",status:Se?"disabled":"configured",method:"hook config",configPath:V,errors:Ie.length>0?Ie:void 0}}import{readFileSync as xc}from"node:fs";import{join as Pc}from"node:path";var Cn="cc-safety-net",Li="# cc-safety-net managed Hermes Agent plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --hermes-agent",_h=30;function gc(I){return`${Li}
|
|
45
45
|
# version: ${I}
|
|
46
46
|
`}function Ih(I){return`${gc(I)}name: ${Cn}
|
|
47
47
|
version: "${I}"
|
|
@@ -219,30 +219,30 @@ def _pre_tool_call(tool_name="", args=None, session_id="", task_id="", **_):
|
|
|
219
219
|
|
|
220
220
|
def register(ctx):
|
|
221
221
|
ctx.register_hook("pre_tool_call", _pre_tool_call)
|
|
222
|
-
`}function mr(I){return[{name:"__init__.py",content:Oh(I)},{name:"plugin.yaml",content:Ih(I)}]}import{mkdirSync as $h,readdirSync as Dh,readFileSync as hc,rmSync as ji}from"node:fs";import{basename as Nh,dirname as Lh,join as Nn}from"node:path";var jh="__pycache__",Fh=/^[a-z0-9][a-z0-9_-]{0,63}$/;function Hh(I){try{return hc(I,"utf-8").trim()}catch{return}}function Fi(I){let V=I.env.get("HERMES_HOME")?.trim();if(V&&Nh(Lh(V))==="profiles")return V;let X=V||Nn(I.home,".hermes"),ee=Nn(X,"active_profile"),ne=Hh(ee),te=ne?.toLowerCase();if(!te||te==="default")return X;if(!Fh.test(te))throw Error(`Invalid Hermes profile name "${ne}" in ${ee}; run \`hermes profile use <name>\` with a valid profile.`);return Nn(X,"profiles",te)}function Hi(I){return Nn(Fi(I),"plugins",Cn)}function Mi(I){return I.startsWith(Li)}function Ui(I,V){let X=Hi(I),ee=u(X);if(ee&&(ee.isSymbolicLink()||!ee.isDirectory()))throw Error(`Refusing to ${V} ${X}: not a regular directory. Move or remove it and rerun ${V==="install"?"install":"uninstall"} --hermes-agent.`);return X}function yc(I,V){let X=u(I);if(!X)return;if(X.isSymbolicLink()||!X.isFile())throw Error(`Refusing to ${V} ${I}: not a regular file. Move or remove it.`);let ee=hc(I,"utf-8");if(!Mi(ee))throw Error(`Refusing to ${V} unmanaged file at ${I}. Move or remove it.`);return ee}function vc(I){let V=Ui(I,"install"),X=mr(un());if(X.map((ne)=>yc(Nn(V,ne.name),"overwrite")).every((ne,te)=>ne===X[te]?.content))return{path:V,alreadyInstalled:!0};return $h(V,{recursive:!0}),X.forEach((ne)=>{an(Nn(V,ne.name),ne.content)}),{path:V,alreadyInstalled:!1}}function Bi(I){let V=Ui(I,"remove");if(!u(V))return[];return mr(un()).filter((X)=>yc(Nn(V,X.name),"remove")!==void 0)}function bc(I){let V=Ui(I,"remove");if(!u(V))return{path:V,alreadyInstalled:!1};let X=Bi(I);if(X.forEach((ee)=>{ji(Nn(V,ee.name))}),ji(Nn(V,jh),{recursive:!0,force:!0}),Dh(V).length===0)ji(V,{recursive:!0});return{path:V,alreadyInstalled:X.length>0}}var gr="hermes-agent",wc=/^([^\s#][^:]*):/,Mh=/^\s+([A-Za-z_][\w-]*):/,kc=/^\s+-\s*(.*)$/;function Uh(I){return I.trim().replace(/^(["'])(.*)\1$/,"$2")}function Bh(I){let V=I.split(/\r?\n/),X=V.findIndex((te)=>wc.exec(te)?.[1]?.trim()==="plugins");if(X===-1)return[];let ee=V.slice(X+1),ne=ee.findIndex((te)=>wc.test(te));return ne===-1?ee:ee.slice(0,ne)}function Cc(I,V){let X=Bh(I),ee=X.findIndex((le)=>Mh.exec(le)?.[1]===V);if(ee===-1)return[];let ne=X.slice(ee+1),te=ne.findIndex((le)=>!kc.test(le));return(te===-1?ne:ne.slice(0,te)).map((le)=>Uh(kc.exec(le)?.[1]??""))}function Gh(I){try{return xc(Pc(Fi(I),"config.yaml"),"utf-8")}catch{return}}function Gi(I){let V=Gh(I)??"";return Cc(V,"enabled").includes(Cn)&&!Cc(V,"disabled").includes(Cn)}function Sc(I){return/^# version:\s*(.+)$/m.exec(I)?.[1]?.trim()}function qh(I,V){let X=u(I);if(!X)return{error:`${V.name} is missing from ${I}; run install --hermes-agent`};if(X.isSymbolicLink()||!X.isFile())return{error:`${I} is a symlink or not a regular file; move or remove it`};try{let ee=xc(I,"utf-8");if(!Mi(ee))return{error:`Unmanaged ${V.name} occupies ${I}; move or remove it`};if(Sc(ee)===un()&&ee!==V.content)return{error:`Modified ${V.name} occupies ${I}; run install --hermes-agent to restore it`};return{content:ee}}catch(ee){return{error:`Failed to read ${I}: ${ee instanceof Error?ee.message:String(ee)}`}}}function Vh(I){try{return{path:Hi(I)}}catch(V){return{error:V instanceof Error?V.message:String(V)}}}function Rc(I){let V=Vh(I.environment);if("error"in V)return{platform:gr,status:"n/a",errors:[V.error]};let X=V.path,ee=We(gr,X);if(ee)return ee;let ne=mr(un()).map((
|
|
222
|
+
`}function mr(I){return[{name:"__init__.py",content:Oh(I)},{name:"plugin.yaml",content:Ih(I)}]}import{mkdirSync as $h,readdirSync as Dh,readFileSync as hc,rmSync as ji}from"node:fs";import{basename as Nh,dirname as Lh,join as Nn}from"node:path";var jh="__pycache__",Fh=/^[a-z0-9][a-z0-9_-]{0,63}$/;function Hh(I){try{return hc(I,"utf-8").trim()}catch{return}}function Fi(I){let V=I.env.get("HERMES_HOME")?.trim();if(V&&Nh(Lh(V))==="profiles")return V;let X=V||Nn(I.home,".hermes"),ee=Nn(X,"active_profile"),ne=Hh(ee),te=ne?.toLowerCase();if(!te||te==="default")return X;if(!Fh.test(te))throw Error(`Invalid Hermes profile name "${ne}" in ${ee}; run \`hermes profile use <name>\` with a valid profile.`);return Nn(X,"profiles",te)}function Hi(I){return Nn(Fi(I),"plugins",Cn)}function Mi(I){return I.startsWith(Li)}function Ui(I,V){let X=Hi(I),ee=u(X);if(ee&&(ee.isSymbolicLink()||!ee.isDirectory()))throw Error(`Refusing to ${V} ${X}: not a regular directory. Move or remove it and rerun ${V==="install"?"install":"uninstall"} --hermes-agent.`);return X}function yc(I,V){let X=u(I);if(!X)return;if(X.isSymbolicLink()||!X.isFile())throw Error(`Refusing to ${V} ${I}: not a regular file. Move or remove it.`);let ee=hc(I,"utf-8");if(!Mi(ee))throw Error(`Refusing to ${V} unmanaged file at ${I}. Move or remove it.`);return ee}function vc(I){let V=Ui(I,"install"),X=mr(un());if(X.map((ne)=>yc(Nn(V,ne.name),"overwrite")).every((ne,te)=>ne===X[te]?.content))return{path:V,alreadyInstalled:!0};return $h(V,{recursive:!0}),X.forEach((ne)=>{an(Nn(V,ne.name),ne.content)}),{path:V,alreadyInstalled:!1}}function Bi(I){let V=Ui(I,"remove");if(!u(V))return[];return mr(un()).filter((X)=>yc(Nn(V,X.name),"remove")!==void 0)}function bc(I){let V=Ui(I,"remove");if(!u(V))return{path:V,alreadyInstalled:!1};let X=Bi(I);if(X.forEach((ee)=>{ji(Nn(V,ee.name))}),ji(Nn(V,jh),{recursive:!0,force:!0}),Dh(V).length===0)ji(V,{recursive:!0});return{path:V,alreadyInstalled:X.length>0}}var gr="hermes-agent",wc=/^([^\s#][^:]*):/,Mh=/^\s+([A-Za-z_][\w-]*):/,kc=/^\s+-\s*(.*)$/;function Uh(I){return I.trim().replace(/^(["'])(.*)\1$/,"$2")}function Bh(I){let V=I.split(/\r?\n/),X=V.findIndex((te)=>wc.exec(te)?.[1]?.trim()==="plugins");if(X===-1)return[];let ee=V.slice(X+1),ne=ee.findIndex((te)=>wc.test(te));return ne===-1?ee:ee.slice(0,ne)}function Cc(I,V){let X=Bh(I),ee=X.findIndex((le)=>Mh.exec(le)?.[1]===V);if(ee===-1)return[];let ne=X.slice(ee+1),te=ne.findIndex((le)=>!kc.test(le));return(te===-1?ne:ne.slice(0,te)).map((le)=>Uh(kc.exec(le)?.[1]??""))}function Gh(I){try{return xc(Pc(Fi(I),"config.yaml"),"utf-8")}catch{return}}function Gi(I){let V=Gh(I)??"";return Cc(V,"enabled").includes(Cn)&&!Cc(V,"disabled").includes(Cn)}function Sc(I){return/^# version:\s*(.+)$/m.exec(I)?.[1]?.trim()}function qh(I,V){let X=u(I);if(!X)return{error:`${V.name} is missing from ${I}; run install --hermes-agent`};if(X.isSymbolicLink()||!X.isFile())return{error:`${I} is a symlink or not a regular file; move or remove it`};try{let ee=xc(I,"utf-8");if(!Mi(ee))return{error:`Unmanaged ${V.name} occupies ${I}; move or remove it`};if(Sc(ee)===un()&&ee!==V.content)return{error:`Modified ${V.name} occupies ${I}; run install --hermes-agent to restore it`};return{content:ee}}catch(ee){return{error:`Failed to read ${I}: ${ee instanceof Error?ee.message:String(ee)}`}}}function Vh(I){try{return{path:Hi(I)}}catch(V){return{error:V instanceof Error?V.message:String(V)}}}function Rc(I){let V=Vh(I.environment);if("error"in V)return{platform:gr,status:"n/a",errors:[V.error]};let X=V.path,ee=We(gr,X);if(ee)return ee;let ne=mr(un()).map((be)=>qh(Pc(X,be.name),be)),te=ne.flatMap((be)=>("error"in be)?[be.error]:[]);if(te.length>0)return{platform:gr,status:"n/a",configPath:X,errors:te};let le=ne.some((be)=>("content"in be)&&Sc(be.content)!==un()),de=le?["Installed Hermes Agent plugin is outdated; run install --hermes-agent to update"]:[];if(!Gi(I.environment))return{platform:gr,status:"disabled",method:"plugin directory",configPath:X,errors:[`${Cn} is not enabled in Hermes; run \`hermes plugins enable ${Cn}\``,...de]};return{platform:gr,status:"configured",method:"plugin directory",configPath:X,errors:le?de:void 0}}import{existsSync as Kh,readFileSync as Jh}from"node:fs";import{join as Ki}from"node:path";var zh=/cc-safety-net\s+hook\s+(?:[^\s]+\s+)*--kimi-code(\s|["']|$)/,qi="cc-safety-net",go="plugin config",Wh=new Set(["event","matcher","command","timeout"]),Yh=new Set(["PreToolUse","PostToolUse","PostToolUseFailure","PermissionRequest","PermissionResult","UserPromptSubmit","UserPromptQueued","TurnStarted","Stop","StopFailure","Interrupt","SessionStart","SessionEnd","SessionHeartbeat","SubagentStart","SubagentStop","TaskStarted","PreCompact","PostCompact","Notification"]);function Ec(I){return I.env.get("KIMI_CODE_HOME")||Ki(I.home,".kimi-code")}function mo(I,V){let X=[""],ee="",ne=0;for(let te=0;te<I.length;te++){let le=I[te];if(ee!==""){let de=ee==='"'&&le==="\\"?I[++te]??"":"";if(X[X.length-1]+=le+de,de===""&&le===ee)ee="";continue}if(le==="#"){let de=I.indexOf(`
|
|
223
223
|
`,te);te=(de===-1?I.length:de)-1;continue}if(le===V&&ne===0){X.push("");continue}if(le==='"'||le==="'")ee=le;if(le==="["||le==="{")ne++;if(le==="]"||le==="}")ne--;X[X.length-1]+=le}return X.map((te)=>te.trim()).filter((te)=>te!=="")}function Tc(I){let V=/^(?:"([^"]*)"|'([^']*)'|([^\s="']+))\s*=\s*([\s\S]+)$/.exec(I);return V?{key:V[1]??V[2]??V[3]??"",value:V[4]??""}:void 0}function Vi(I){return I===void 0?void 0:/^("""|'''|"|')([\s\S]*)\1$/.exec(I)?.[2]}function Zh(I){let V=I.split(/(?=^\s*\[)/m),X=V.filter((ee)=>!/^\s*\[/.test(ee)).flatMap((ee)=>mo(ee,`
|
|
224
224
|
`)).map(Tc).find((ee)=>ee?.key==="hooks")?.value;if(X!==void 0)return mo(X.slice(1,-1),",").map((ee)=>mo(ee.slice(1,-1),","));return V.filter((ee)=>/^\s*\[\[hooks]]/.test(ee)).map((ee)=>mo(ee.replace(/^\s*\[\[hooks]]/,""),`
|
|
225
|
-
`))}function Xh(I){let V=I.map(Tc),X=I.find((Ie,$e)=>V[$e]===void 0),ee=V.find((Ie)=>Ie!==void 0&&!Wh.has(Ie.key))?.key,ne=V.find((Ie,$e)=>Ie!==void 0&&V.findIndex((Le)=>Le?.key===Ie.key)<$e)?.key,te=(Ie)=>V.find(($e)=>$e?.key===Ie)?.value,le=te("matcher"),de=te("timeout"),ve=Number(de?.replace(/(?<=[\da-f])_(?=[\da-f])/gi,""));return[[X!==void 0,`"${X}" is not a key = value pair`],[ee!==void 0,`unknown key "${ee}"`],[ne!==void 0,`duplicate key "${ne}"`],[!Yh.has(Vi(te("event"))??""),'"event" is not a Kimi Code hook event'],[le!==void 0&&Vi(le)===void 0,'"matcher" is not a string'],[!Vi(te("command")),'"command" is missing or empty'],[de!==void 0&&!(Number.isInteger(ve)&&ve>=1&&ve<=600),'"timeout" is not an integer from 1 to 600']].find(([Ie])=>Ie)?.[1]}function Qh(I){let V=Ki(Ec(I),"plugins","installed.json"),X=b(V);if(X.kind==="missing")return;let ee=X.kind==="ok"?n(X.value,"plugins"):void 0;if(!Array.isArray(ee))return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Cannot read ${V}, so doctor cannot tell whether the Kimi Code plugin is installed`]};let ne=ee.find((te)=>n(te,"id")===qi);if(ne===void 0)return;if(n(ne,"enabled")!==!0)return{platform:"kimi-code",status:"disabled",method:go,configPath:V,errors:[`${qi} is installed but not enabled in Kimi Code; run /plugins enable ${qi}`]};return{platform:"kimi-code",status:"configured",method:go,configPath:V}}function ho(I){let V=Ki(Ec(I.environment),"config.toml"),X=()=>Qh(I.environment)??{platform:"kimi-code",status:"n/a",configPath:V};if(!Kh(V))return X();let ee;try{ee=Jh(V,"utf-8")}catch(le){return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Failed to read ${V}: ${le instanceof Error?le.message:String(le)}`]}}if(!zh.test(ee))return X();let te=(/"""|'''/.test(ee)?[]:Zh(ee)).flatMap((le,de)=>{let ve=Xh(le);return ve===void 0?[]:[`Kimi Code ignores every hook because hooks entry ${de+1} is invalid (${ve}); fix it in ${V}`]});return{platform:"kimi-code",status:te.length>0?"disabled":"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{readFileSync as jc}from"node:fs";import{join as yr}from"node:path";var dn="cc-safety-net",kn="index.js",Wt="openclaw.plugin.json",Yt="package.json";var yo="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as ey,lstatSync as ny,readdirSync as ty,readFileSync as ry}from"node:fs";import{dirname as Ac,join as Un}from"node:path";import{fileURLToPath as oy}from"node:url";var Ji=Un("openclaw",dn),st=`run \`openclaw plugins enable ${dn}\``,iy="config reload superseded by a newer runtime config source",sy=[kn,Wt,Yt];function _c(I){let V=I.env.get("OPENCLAW_HOME")?.trim();return V?B(V,I.home):I.home}function Ic(I){let V=_c(I),X=I.env.get("OPENCLAW_STATE_DIR")?.trim();if(X)return B(X,V);let ee=I.env.get("OPENCLAW_CONFIG_PATH")?.trim();return ee?Ac(B(ee,V)):Un(V,".openclaw")}function Oc(I){let V=I.env.get("OPENCLAW_CONFIG_PATH")?.trim();return V?B(V,_c(I)):Un(Ic(I),"openclaw.json")}function hr(I){return Un(Ic(I),"extensions",dn)}function ay(I){let V=ty(I);if(V.length===0)return!0;if(V.some((ne)=>!sy.includes(ne)))return!1;let X=Un(I,kn),ee=u(X);return ee!==void 0&&!ee.isSymbolicLink()&&ee.isFile()&&ry(X,"utf-8").startsWith(yo)}function zi(I){let V=hr(I),X=u(V);if(!X)return;if(!X.isSymbolicLink()&&X.isDirectory()&&ay(V))return;throw Error(`Refusing to modify ${V}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function $c(){let I=Ac(oy(import.meta.url));return[Un(I,Ji),Un(I,"..",Ji),Un(I,"..","..","..","dist",Ji)]}function Wi(I=$c()){return I.find((V)=>ey(V)&&ny(V).isDirectory())}function ly(I=$c()){let V=Wi(I);if(!V)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return V}function Dc(I=ly()){return[["openclaw","plugins","install",I,"--force","--accept-capabilities"]]}function cy(I){let V=(()=>{try{return JSON.parse(I)}catch{return}})(),X=n(n(V,"plugin"),"status");return typeof X==="string"?X:void 0}async function dy(){await pn(["openclaw","plugins","enable",dn]).catch((I)=>{if(!(I instanceof Error&&I.message.includes(iy)))throw I})}async function Nc(I){let V=async()=>cy(await pn(["openclaw","plugins","inspect",dn,"--runtime","--json"],{stdoutOnly:!0})),X=await V(),ee=X==="disabled"&&I;if(ee)await dy();let ne=ee?await V():X;if(ne==="loaded")return;throw Error(`${ne===void 0?`The ${dn} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:ne==="disabled"?`OpenClaw reports the ${dn} plugin with status "disabled"; ${st}.`:`OpenClaw reports the ${dn} plugin with status "${ne}".`} Run \`openclaw plugins inspect ${dn} --runtime\` for details.`)}var vo="openclaw";function Zt(I,V){let X=yr(I,V),ee=u(X);if(!ee)return{error:`${V} is missing from ${X}; run install --openclaw`};if(ee.isSymbolicLink()||!ee.isFile())return{error:`${X} is a symlink or not a regular file; move or remove it`};try{return{content:jc(X,"utf-8")}}catch(ne){return{error:`Failed to read ${X}: ${ne instanceof Error?ne.message:String(ne)}`}}}function Fc(I){try{return JSON.parse(gn(I))}catch{return}}function uy(I){let V=Zt(I,Wt);if("error"in V)return V.error;if(n(Fc(V.content),"id")===dn)return;return`${yr(I,Wt)} is not a valid ${dn} manifest; run install --openclaw`}function py(I){let V=Zt(I,Yt);if("error"in V)return V.error;let X=n(n(Fc(V.content),"openclaw"),"extensions");if(Array.isArray(X)&&X.includes(`./${kn}`))return;return`${yr(I,Yt)} does not point OpenClaw at ${kn}; run install --openclaw`}function Lc(I){return Array.isArray(I)?I.filter((V)=>typeof V==="string"):[]}function fy(I){let V=Oc(I);if(!u(V))return`${dn} is not enabled; ${st}`;let X=(()=>{try{return JSON.parse(gn(jc(V,"utf-8")))}catch{return}})();if(X===void 0)return`Failed to read ${V}; fix it, then ${st}`;let ee=n(X,"plugins");if(n(ee,"enabled")===!1)return`plugins.enabled is false in ${V}; no OpenClaw plugin loads`;let ne=n(n(n(ee,"entries"),dn),"enabled");if(Lc(n(ee,"deny")).includes(dn)||ne===!1)return`${dn} is disabled in ${V}; ${st}`;let te=Lc(n(ee,"allow"));if(te.length>0&&!te.includes(dn))return`plugins.allow in ${V} does not list ${dn}; add it, then ${st}`;if(te.includes(dn)||ne===!0)return;return`${dn} is not enabled; ${st}`}function Hc(I){return/^\/\/ version:\s*(.+)$/m.exec(I)?.[1]?.trim()}function my(I,V,X){if(X===void 0)return[];let ee=Zt(X,kn);if(!(("content"in ee)&&Hc(ee.content)===V))return[];return[kn,Wt,Yt].flatMap((te)=>{let le=Zt(I,te),de=Zt(X,te);if("error"in le||"error"in de||le.content===de.content)return[];return[`Modified ${te} occupies ${yr(I,te)}; run install --openclaw to restore it`]})}function Mc(I){let V=hr(I.environment),X=We(vo,V);if(X)return X;let ee=Zt(V,kn),te=["error"in ee?ee.error:ee.content.startsWith(yo)?void 0:`Unmanaged ${kn} occupies ${yr(V,kn)}; move or remove it`,uy(V),py(V)].filter((Ie)=>Ie!==void 0),le="content"in ee?Hc(ee.content):void 0,de=te.length>0?te:my(V,le,Wi());if(de.length>0)return{platform:vo,status:"n/a",configPath:V,errors:de};let ve=le===un()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],Se=fy(I.environment);if(Se)return{platform:vo,status:"disabled",method:"plugin directory",configPath:V,errors:[Se,...ve]};return{platform:vo,status:"configured",method:"plugin directory",configPath:V,errors:ve.length>0?ve:void 0}}import{existsSync as xy,readFileSync as Py}from"node:fs";import{basename as Sy}from"node:path";import{existsSync as bo,readFileSync as Zi,rmSync as gy}from"node:fs";import{join as Tn}from"node:path";import{pathToFileURL as hy}from"node:url";var vr="cc-safety-net",at=`${vr}@latest`,Xi=["opencode.json","opencode.jsonc"],yy=60,vy=250,Uc="CCSafetyNetPlugin",by={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Bc(I){return Tn(I.env.get("XDG_CONFIG_HOME")||Tn(I.home,".config"),"opencode")}function Qi(I){return I.env.get("OPENCODE_CONFIG_DIR")||Bc(I)}function es(I){return Xi.map((V)=>Tn(Qi(I),V))}function ns(I){return[...new Set([Qi(I),Bc(I)])].flatMap((V)=>Xi.map((X)=>Tn(V,X)))}function Gc(I){return Tn(I.env.get("XDG_CACHE_HOME")||Tn(I.home,".cache"),"opencode","packages",at)}function qc(I){gy(Gc(I),{recursive:!0,force:!0})}async function Vc(I){let V=(await pn(["opencode","--version"],{stdoutOnly:!0})).trim(),X=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(V),ee=Number(X?.[1]),ne=Number(X?.[2]),te=Number(X?.[3]);if(!X||ee!==1&&ee!==2||ee===1&&(ne<18||ne===18&&te<29)||ee===2&&ne===0&&te<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${V||"an unknown version"}.`);if(ee===2){for(let le of es(I)){if(!bo(le))continue;let de=rs(Zi(le,"utf-8"),le);if(["plugin","plugins"].some((Se)=>{let Ie=n(de,Se);return Array.isArray(Ie)&&Ie.some(($e)=>wo($e)&&(typeof $e==="string"?$e:n($e,"package"))!==at)}))throw Error(`Change the cc-safety-net package spec in ${le} to ${at}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[],afterInstall:async()=>{if((await pn(["opencode","plugin","add",at],{stdoutOnly:!0})).includes("is already configured in"))await Yi(),await pn(["opencode","plugin","update",at]);let de=await Yi();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 ve=["--param",`location[directory]=${process.cwd()}`];await pn(["opencode","api","integration.list",...ve]);let Se=await pn(["opencode","api","plugin.list",...ve],{stdoutOnly:!0}),Ie=ts(Se);if(Ie)throw Error(Ie);if(!Kc(Se).some(Jc))throw Error("OpenCode lists no active cc-safety-net for this directory. Run `opencode api plugin.list` for details.")}}}return qc(I),{commands:[["opencode","plugin","-g","-f",at]],afterInstall:()=>ky(I)}}function Kc(I){return wy(I).filter((V)=>n(V,"id")===vr||wo(n(n(V,"source"),"target"))).map((V)=>n(V,"state"))}function Jc(I){return n(I,"status")==="active"}function ts(I){let V=Kc(I);if(V.some(Jc))return;let X=V.find((ee)=>n(ee,"status")==="failed");if(!X)return;return`OpenCode reports cc-safety-net failed: ${String(n(X,"error")).split(`
|
|
226
|
-
`)[0]}`}function wy(I){if(!I)return[];try{let V=n(JSON.parse(I),"data");return Array.isArray(V)?V:[]}catch{return[]}}async function Yi(I=1){let V=await pn(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s|\scc-safety-net@latest\s*$/m.test(V)||I===yy)return V;return await new Promise((X)=>setTimeout(X,vy)),Yi(I+1)}async function ky(I){let V=Tn(Gc(I),"node_modules",vr),X=Tn(V,"package.json");if(!bo(X))throw Error(`The OpenCode plugin cache at ${V} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${at}\` for details.`);let ee=n(JSON.parse(Zi(X,"utf-8")),"main");if(typeof ee!=="string")throw Error(`The cached OpenCode plugin at ${V} declares no "main" entry.`);let ne=Tn(V,ee);if(typeof(await import(hy(ne).href))[Uc]==="function")return;throw Error(`The cached OpenCode plugin at ${ne} does not export a callable ${Uc}, so OpenCode would load nothing and fail open.`)}function rs(I,V){try{return JSON.parse(gn(I))}catch(X){if(X instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${V}: ${X.message}`);throw X}}function wo(I){let V=typeof I==="string"?I:n(I,"package");return typeof V==="string"&&(V===vr||V.startsWith(`${vr}@`))}function os(I){return["plugin","plugins"].some((V)=>{let X=n(I,V);return Array.isArray(X)&&X.some(wo)})}function Cy(I,V){let ee=["plugin","plugins"].flatMap((ne)=>{let te=bl(I,ne,by);if(!te)return[];let le=[],de=0,
|
|
227
|
-
`));return{path:ne[0]??X??Tn(Qi(I),Xi[0]),alreadyInstalled:ne.length>0}}function Xt(I){let V=[];for(let X of I.openCodeVersion?.startsWith("2.")?es(I.environment):ns(I.environment))if(xy(X))try{let ee=Py(X,"utf-8"),ne=gn(ee),te=JSON.parse(ne);if(os(te)){let le=ts(I.openCodePluginListOutput);if(le)return{platform:"opencode",status:"disabled",method:"opencode api plugin.list",configPath:X,errors:[...V,le]};return{platform:"opencode",status:"configured",method:"plugin array",configPath:X,errors:V.length>0?V:void 0}}}catch(ee){V.push(`Failed to parse ${Sy(X)}: ${ee instanceof Error?ee.message:String(ee)}`)}return{platform:"opencode",status:"n/a",errors:V.length>0?V:void 0}}import{join as Wc}from"node:path";var Zc="dist/pi/index.js",Yc=new Set([Zc,"index.js"]),Ry=/[*?[\]{}]/;function is(I){let V=I.env.get("PI_CODING_AGENT_DIR");return Wc(V?B(V,I.home):Wc(I.home,".pi","agent"),"settings.json")}function ss(I){if(typeof I!=="string")return!1;return I==="npm:cc-safety-net"||I.startsWith("npm:cc-safety-net@")}function Ey(I){if(!Array.isArray(I)||I.length===0)return!1;if(!I.every((ee)=>typeof ee==="string"))return!1;let V=(ee)=>I.some((ne)=>ne.startsWith(ee)&&ne.slice(1).replace(/^\.[/\\]/,"")===Zc);if(V("-"))return!1;if(V("+"))return!0;let X=I.filter((ee)=>!/^[-+!]/.test(ee));return(X.length===0||X.some((ee)=>Yc.has(ee)))&&!I.some((ee)=>ee.startsWith("!")&&(Yc.has(ee.slice(1))||Ry.test(ee)))}function Xc(I){let V=is(I.environment),X=b(V);if(X.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(X.kind==="missing")return{platform:"pi",status:"n/a"};let ee=n(X.value,"packages");if(!Array.isArray(ee))return{platform:"pi",status:"n/a"};let ne=ee.find((le)=>ss(typeof le==="string"?le:n(le,"source")));if(ne===void 0)return{platform:"pi",status:"n/a"};let te=n(ne,"extensions");if(te!==void 0&&!Ey(te))return{platform:"pi",status:"disabled",method:"package config",configPath:V,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:V}}var Ty={amp:rl,"antigravity-cli":al,"claude-code":pl,codex:ml,"copilot-cli":Ol,cursor:Ul,"deepseek-harness":Rt,devin:Wl,droid:rc,"gemini-cli":oc,"grok-build":mc,"hermes-agent":Rc,"kimi-code":ho,openclaw:Mc,opencode:Xt,pi:Xc};function Qt(I,V,X){let ee={...X,cwd:V,environment:I};return Or.map((ne)=>Ay(Ty[ne](ee)))}function Ay(I){if(I.status==="not-inspected")return{platform:I.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:I.platform,detected:I.status!=="n/a",configured:I.status==="configured",inspectionStatus:I.status!=="n/a"?"verified":I.errors&&I.errors.length>0?"failed":"not-applicable",method:I.method,configPath:I.configPath,configPaths:I.configPaths,errors:I.errors}}import{join as _y}from"node:path";var Iy=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}]),Oy=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),commandTools:Object.freeze([]),safety:Object.freeze({level:"standard"}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),$y={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 Qc(I){let V=_y(I.tmpdir,"cc-safety-net-self-test"),X=Iy.map((ee)=>{let ne=z(I,d("self-test",{command:ee.command},{kind:"command",shell:"auto"},{configCwd:V,executionCwd:V},ee.command),{guard:{dependencies:{loadPolicySnapshot:()=>Oy,getModes:()=>$y,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),te=ee.expectBlocked?"blocked":"allowed",le=ne.decision.kind==="deny"?"blocked":"allowed";return{command:ee.command,description:ee.description,expected:te,actual:le,passed:te===le,reason:ne.decision.kind==="deny"?ne.decision.reason:void 0,ruleId:ne.decision.kind==="deny"?ne.decision.ruleId:void 0}});return{passed:X.filter((ee)=>ee.passed).length,failed:X.filter((ee)=>!ee.passed).length,total:X.length,results:X}}function as(I){let V=fn({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},I);if(In(V.errors))return null;return{json:V.flags.json,skipUpdateCheck:V.flags.skipUpdateCheck}}async function ed(I,V={}){let X=await ar(!V.json,()=>{let ee=Ny(I,V);return{ready:ee,finish:()=>ee}},()=>sr(),{loadingMessage:"Checking system status…"});if(V.json)console.log(JSON.stringify(X,null,2));else Ly(X);return X.engineSelfTest.failed>0||X.findings.some((ee)=>ee.severity==="error")?1:0}async function Ny(I,V){let X=V.cwd??process.cwd(),ee=await Mr((Me)=>Xt({environment:I,cwd:X,openCodeVersion:Me}).status!=="n/a",void 0,X),ne=Qt(I,X,{ampPluginListOutput:ee.ampPluginListOutput,codexPluginListOutput:ee.codexPluginListOutput,copilotCliVersion:ee.versions["copilot-cli"],openCodeVersion:ee.versions.opencode,openCodePluginListOutput:ee.openCodePluginListOutput}),te=wa(I,X),le=ka(I),de=w(I,{cwd:X}),ve=de.policy,Se=O(ve,I.env),Ie=Z(ve,Se.capabilities),$e=Lr(I,7),Le=Xa(I,X),Ne=[Ut(X),Bt(I)].filter((Me)=>Dy(Me)),Fe=V.skipUpdateCheck?{currentVersion:un(),latestVersion:null,updateAvailable:!1}:await Hn(),Be={hooks:ne,engineSelfTest:Qc(I),userConfig:te.userConfig,projectConfig:te.projectConfig,configState:nt(de),effectiveRules:te.effectiveRules,environment:le,effectiveSafety:{selectedPreset:ve.safety.level,level:Se.effectiveLevel,capabilities:Se.capabilities,ruleOverrides:ve.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(Ie).filter(([,Me])=>Me.source==="rule_override"&&Me.override==="off"&&Me.inheritedEnabled&&Me.changesInherited).map(([Me])=>Me),ruleCounts:{stored:Object.keys(ve.destructiveCommandRuleOverrides).length,effective:Object.values(Ie).filter((Me)=>Me.changesInherited).length},...de.policyScopes?{policyScopes:de.policyScopes}:{}},...Le.length>0?{v2Leftovers:Le}:{},...Ne.length>0?{legacyConfigs:Ne}:{},posture:Na(I,te.userConfig.path),activity:$e,update:Fe,system:ee};return{...Be,findings:xa(Be)}}function Ly(I){console.log(),console.log(Sa(I.hooks)),console.log(),console.log(Ra(I.engineSelfTest)),console.log(),console.log(Ea(I)),console.log(),console.log(Ta(I.environment)),console.log(),console.log(Aa(I)),console.log(),console.log(_a(I.findings)),console.log(),console.log(Ia(I.activity)),console.log(),console.log($a(I.system)),console.log(),console.log(Oa(I.update)),console.log(Da(I))}import{existsSync as jy}from"node:fs";var Fy=/^[A-Za-z0-9_@%+=:,./-]+$/,ls="Usage: cc-safety-net explain [--json] [--cwd <path>] [--shell <auto|posix|powershell>] <command>",Hy=["auto","posix","powershell"];function cs(I){let V=fn({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"],shell:["--shell"]},positionals:"tail"},I);if(In(V.errors))return console.error(ls),console.error("Pass -- before a command that starts with dashes."),null;if(V.values.cwd!==void 0&&!jy(V.values.cwd))return console.error(`Error: --cwd path does not exist: ${V.values.cwd}`),null;let X=Hy.find((ne)=>ne===V.values.shell);if(V.values.shell!==void 0&&!X)return console.error(`Error: --shell must be auto, posix, or powershell, got: ${V.values.shell}`),console.error(ls),null;let ee=V.positionals.length===1?V.positionals[0]:V.positionals.map((ne)=>Fy.test(ne)?ne:`'${ne.replaceAll("'",X==="powershell"?"''":"'\\''")}'`).join(" ");if(!ee)return console.error("Error: No command provided"),console.error(ls),null;return{json:V.flags.json,cwd:V.values.cwd,shell:X,command:ee}}function nd(I){if(I)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function td(I,V){let ee=V-18;return[`${I.dtl}${I.dh.repeat(V)}${I.dtr}`,`${I.dv} Command Analysis${" ".repeat(ee)}${I.dv}`,`${I.dbl}${I.dh.repeat(V)}${I.dbr}`]}function ds(I){return JSON.stringify(I)}function rd(I,V=0){return`[${I.map((ee,ne)=>Pa(ee,ne,V)).join(",")}]`}function br(I,V,X=70){let ee=I.split(" "),ne=[],te="";for(let le of ee)if(te&&te.length+le.length+1>X)ne.push(te),te=le;else te=te?`${te} ${le}`:le;if(te)ne.push(te);return ne.map((le,de)=>de===0?le:`${V}${le}`)}function od(I,V,X){let ee=[];switch(I.type){case"parse":return null;case"env-strip":return ee.push(""),ee.push(`STEP ${V} ${X.h} Strip environment variables`),ee.push(` Removed: ${I.envVars.map((ne)=>`${ne}=<redacted>`).join(", ")}`),ee.push(` Tokens: ${ds(I.output)}`),{lines:ee,incrementStep:!0};case"leading-tokens-stripped":return ee.push(""),ee.push(`STEP ${V} ${X.h} Strip wrappers`),ee.push(` Removed: ${I.removed.join(", ")}`),ee.push(` Tokens: ${ds(I.output)}`),{lines:ee,incrementStep:!0};case"shell-wrapper":return ee.push(""),ee.push(`STEP ${V} ${X.h} Detect shell wrapper`),ee.push(` Wrapper: ${I.wrapper} -c`),ee.push(` Inner: ${I.innerCommand}`),{lines:ee,incrementStep:!0};case"interpreter":{if(ee.push(""),ee.push(`STEP ${V} ${X.h} Detect interpreter`),ee.push(` Interpreter: ${I.interpreter}`),ee.push(` Code: ${I.codeArg}`),I.paranoidBlocked)ee.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:ee,incrementStep:!0}}case"busybox":return ee.push(""),ee.push(`STEP ${V} ${X.h} Busybox wrapper`),ee.push(` Subcommand: ${I.subcommand}`),{lines:ee,incrementStep:!0};case"transparent-wrapper":return ee.push(""),ee.push(`STEP ${V} ${X.h} Transparent wrapper`),ee.push(` Wrapper: ${I.wrapper}`),ee.push(` Tokens: ${ds(I.output)}`),{lines:ee,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"script-file":return ee.push(""),ee.push(`STEP ${V} ${X.h} Read script file`),ee.push(` Path: ${I.path}`),ee.push(` Size: ${I.bytes} bytes`),{lines:ee,incrementStep:!0};case"rule-check":{if(ee.push(""),ee.push(`STEP ${V} ${X.h} Match rules`),ee.push(` Rule: ${I.rule}()`),I.matched)ee.push(" Result: MATCHED");else ee.push(" Result: No match");return{lines:ee,incrementStep:!0}}case"worktree-relaxation":return ee.push(""),ee.push(`STEP ${V} ${X.h} Worktree relaxation`),ee.push(` Mode: ${r.worktree.name}`),ee.push(` Git cwd: ${I.gitCwd}`),ee.push(" Result: Allowed local discard in linked worktree"),{lines:ee,incrementStep:!0};case"temp-root-relaxation":return ee.push(""),ee.push(`STEP ${V} ${X.h} Temp-root relaxation`),ee.push(` Git cwd: ${I.gitCwd}`),ee.push(" Result: Allowed git discard in a temp-root repository"),{lines:ee,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(I.embeddedCommandFound)return ee.push(""),ee.push(`STEP ${V} ${X.h} Fallback scan`),ee.push(` Found: ${I.embeddedCommandFound}`),{lines:ee,incrementStep:!0};return null}case"custom-rules-check":{if(I.rulesChecked){if(ee.push(""),ee.push(`STEP ${V} ${X.h} Custom rules`),I.matched)ee.push(" Result: MATCHED");else ee.push(" Result: No match");return{lines:ee,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(I.matched)return ee.push(""),ee.push(`STEP ${V} ${X.h} Dangerous text check`),ee.push(` Token: ${I.token}`),ee.push(" Result: MATCHED"),{lines:ee,incrementStep:!0};return null}case"strict-unparseable":return ee.push(""),ee.push(`STEP ${V} ${X.h} Strict mode check`),ee.push(` Command: ${I.rawCommand}`),ee.push(" Result: ✗ UNPARSEABLE"),{lines:ee,incrementStep:!0};case"segment-skipped":return null;case"error":return ee.push(""),ee.push(`ERROR: ${I.message}`),{lines:ee,incrementStep:!1};default:return I}}function us(I,V){let X=nd(V?.asciiOnly??!1),ee=58,ne=[],te=1;ne.push(...td(X,58)),ne.push("");let le=I.trace.steps.find((Fe)=>Fe.type==="error");if(le&&le.type==="error"){ne.push("ERROR"),ne.push(` ${le.message}`),ne.push(""),ne.push("RESULT"),ne.push(` Status: ${I.result==="blocked"?qe.red("BLOCKED"):qe.green("ALLOWED")}`),ne.push(""),ne.push("CONFIG");let Fe=I.configSource??"none";return ne.push(` Path: ${Fe}`),ne.join(`
|
|
228
|
-
`)}let de=I.trace.steps.find((Fe)=>Fe.type==="parse");if(de&&de.type==="parse"){ne.push("INPUT"),ne.push(` ${de.input}`),ne.push(""),ne.push(`STEP ${te} ${X.h} Split shell commands`),te++;for(let Fe=0;Fe<de.segments.length;Fe++){let Be=de.segments[Fe];if(Be){let Me=Math.random();ne.push(` Segment ${Fe+1}: ${rd(Be,Me)}`)}}}let
|
|
229
|
-
`)}function ps(I){return JSON.stringify(I,null,2)}import{resolve as Gy}from"node:path";var id=512,sd={maxTextLength:2048,maxListLength:128,maxObjectProperties:128,maxDepth:16},My=["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 gs(I){let V=0,X={allocateSegment(){return V++},getNextSegmentIndex(){return V},branch(){let ee=I.fork(),ne=gs(ee);return{trace:ne,adopt(){I.replaceSegmentEvents(ee.finish().events),V=ne.getNextSegmentIndex()}}},recordGlobal(ee){I.record({scope:"global",step:ee})},recordSegment(ee,ne=X.currentSegmentIndex){if(ne===void 0)return;I.record({scope:"segment",segmentIndex:ne,step:ee})}};return X}function hs(I=new Set){let V=[];return{record(X){if(V.length>=id)return;ko(X.step,I,sd),V.push({...X,step:fs(X.step,sd,I)})},fork(){return hs(I)},replaceSegmentEvents(X){V.splice(0,V.length,...[...V.filter((ee)=>ee.scope==="global"),...X].slice(0,id))},finish(){return{events:V}}}}function ko(I,V,X,ee=0,ne=new WeakSet){if(typeof I==="string"){let de=I.slice(0,X.maxTextLength);if(!pt(de))return;for(let
|
|
230
|
-
`,()=>V())})}async function dd(I,V){let X=cs(V);if(!X)return 1;try{let ee=wr(X.command,{cwd:X.cwd,shell:X.shell},I),ne=!!process.env.NO_COLOR||!process.stdout.isTTY;return await cd(X.json?ps(ee):us(ee,{asciiOnly:ne})),0}catch(ee){let ne=Yy(ee instanceof g?ee.cause:ee);if(ne===void 0)throw ee;if(X.json)return await cd(JSON.stringify({error:ne})),1;return console.error(ne),1}}function Yy(I){if(I instanceof E)return I.message;if(I instanceof H)return I.message;if(I instanceof h)return I.message;if(I instanceof a&&l[I.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var ud="2.7.
|
|
225
|
+
`))}function Xh(I){let V=I.map(Tc),X=I.find((Ie,$e)=>V[$e]===void 0),ee=V.find((Ie)=>Ie!==void 0&&!Wh.has(Ie.key))?.key,ne=V.find((Ie,$e)=>Ie!==void 0&&V.findIndex((Le)=>Le?.key===Ie.key)<$e)?.key,te=(Ie)=>V.find(($e)=>$e?.key===Ie)?.value,le=te("matcher"),de=te("timeout"),be=Number(de?.replace(/(?<=[\da-f])_(?=[\da-f])/gi,""));return[[X!==void 0,`"${X}" is not a key = value pair`],[ee!==void 0,`unknown key "${ee}"`],[ne!==void 0,`duplicate key "${ne}"`],[!Yh.has(Vi(te("event"))??""),'"event" is not a Kimi Code hook event'],[le!==void 0&&Vi(le)===void 0,'"matcher" is not a string'],[!Vi(te("command")),'"command" is missing or empty'],[de!==void 0&&!(Number.isInteger(be)&&be>=1&&be<=600),'"timeout" is not an integer from 1 to 600']].find(([Ie])=>Ie)?.[1]}function Qh(I){let V=Ki(Ec(I),"plugins","installed.json"),X=v(V);if(X.kind==="missing")return;let ee=X.kind==="ok"?n(X.value,"plugins"):void 0;if(!Array.isArray(ee))return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Cannot read ${V}, so doctor cannot tell whether the Kimi Code plugin is installed`]};let ne=ee.find((te)=>n(te,"id")===qi);if(ne===void 0)return;if(n(ne,"enabled")!==!0)return{platform:"kimi-code",status:"disabled",method:go,configPath:V,errors:[`${qi} is installed but not enabled in Kimi Code; run /plugins enable ${qi}`]};return{platform:"kimi-code",status:"configured",method:go,configPath:V}}function ho(I){let V=Ki(Ec(I.environment),"config.toml"),X=()=>Qh(I.environment)??{platform:"kimi-code",status:"n/a",configPath:V};if(!Kh(V))return X();let ee;try{ee=Jh(V,"utf-8")}catch(le){return{platform:"kimi-code",status:"n/a",configPath:V,errors:[`Failed to read ${V}: ${le instanceof Error?le.message:String(le)}`]}}if(!zh.test(ee))return X();let te=(/"""|'''/.test(ee)?[]:Zh(ee)).flatMap((le,de)=>{let be=Xh(le);return be===void 0?[]:[`Kimi Code ignores every hook because hooks entry ${de+1} is invalid (${be}); fix it in ${V}`]});return{platform:"kimi-code",status:te.length>0?"disabled":"configured",method:"hook config",configPath:V,errors:te.length>0?te:void 0}}import{readFileSync as jc}from"node:fs";import{join as yr}from"node:path";var dn="cc-safety-net",kn="index.js",Wt="openclaw.plugin.json",Yt="package.json";var yo="// cc-safety-net managed OpenClaw plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --openclaw";import{existsSync as ey,lstatSync as ny,readdirSync as ty,readFileSync as ry}from"node:fs";import{dirname as Ac,join as Un}from"node:path";import{fileURLToPath as oy}from"node:url";var Ji=Un("openclaw",dn),st=`run \`openclaw plugins enable ${dn}\``,iy="config reload superseded by a newer runtime config source",sy=[kn,Wt,Yt];function _c(I){let V=I.env.get("OPENCLAW_HOME")?.trim();return V?B(V,I.home):I.home}function Ic(I){let V=_c(I),X=I.env.get("OPENCLAW_STATE_DIR")?.trim();if(X)return B(X,V);let ee=I.env.get("OPENCLAW_CONFIG_PATH")?.trim();return ee?Ac(B(ee,V)):Un(V,".openclaw")}function Oc(I){let V=I.env.get("OPENCLAW_CONFIG_PATH")?.trim();return V?B(V,_c(I)):Un(Ic(I),"openclaw.json")}function hr(I){return Un(Ic(I),"extensions",dn)}function ay(I){let V=ty(I);if(V.length===0)return!0;if(V.some((ne)=>!sy.includes(ne)))return!1;let X=Un(I,kn),ee=u(X);return ee!==void 0&&!ee.isSymbolicLink()&&ee.isFile()&&ry(X,"utf-8").startsWith(yo)}function zi(I){let V=hr(I),X=u(V);if(!X)return;if(!X.isSymbolicLink()&&X.isDirectory()&&ay(V))return;throw Error(`Refusing to modify ${V}: it does not hold a cc-safety-net managed OpenClaw plugin. Move or remove it, then run the command again.`)}function $c(){let I=Ac(oy(import.meta.url));return[Un(I,Ji),Un(I,"..",Ji),Un(I,"..","..","..","dist",Ji)]}function Wi(I=$c()){return I.find((V)=>ey(V)&&ny(V).isDirectory())}function ly(I=$c()){let V=Wi(I);if(!V)throw Error("Packaged OpenClaw plugin directory not found. Reinstall cc-safety-net and try again.");return V}function Dc(I=ly()){return[["openclaw","plugins","install",I,"--force","--accept-capabilities"]]}function cy(I){let V=(()=>{try{return JSON.parse(I)}catch{return}})(),X=n(n(V,"plugin"),"status");return typeof X==="string"?X:void 0}async function dy(){await pn(["openclaw","plugins","enable",dn]).catch((I)=>{if(!(I instanceof Error&&I.message.includes(iy)))throw I})}async function Nc(I){let V=async()=>cy(await pn(["openclaw","plugins","inspect",dn,"--runtime","--json"],{stdoutOnly:!0})),X=await V(),ee=X==="disabled"&&I;if(ee)await dy();let ne=ee?await V():X;if(ne==="loaded")return;throw Error(`${ne===void 0?`The ${dn} plugin's load state could not be verified: OpenClaw's runtime inspect report was unreadable.`:ne==="disabled"?`OpenClaw reports the ${dn} plugin with status "disabled"; ${st}.`:`OpenClaw reports the ${dn} plugin with status "${ne}".`} Run \`openclaw plugins inspect ${dn} --runtime\` for details.`)}var vo="openclaw";function Zt(I,V){let X=yr(I,V),ee=u(X);if(!ee)return{error:`${V} is missing from ${X}; run install --openclaw`};if(ee.isSymbolicLink()||!ee.isFile())return{error:`${X} is a symlink or not a regular file; move or remove it`};try{return{content:jc(X,"utf-8")}}catch(ne){return{error:`Failed to read ${X}: ${ne instanceof Error?ne.message:String(ne)}`}}}function Fc(I){try{return JSON.parse(gn(I))}catch{return}}function uy(I){let V=Zt(I,Wt);if("error"in V)return V.error;if(n(Fc(V.content),"id")===dn)return;return`${yr(I,Wt)} is not a valid ${dn} manifest; run install --openclaw`}function py(I){let V=Zt(I,Yt);if("error"in V)return V.error;let X=n(n(Fc(V.content),"openclaw"),"extensions");if(Array.isArray(X)&&X.includes(`./${kn}`))return;return`${yr(I,Yt)} does not point OpenClaw at ${kn}; run install --openclaw`}function Lc(I){return Array.isArray(I)?I.filter((V)=>typeof V==="string"):[]}function fy(I){let V=Oc(I);if(!u(V))return`${dn} is not enabled; ${st}`;let X=(()=>{try{return JSON.parse(gn(jc(V,"utf-8")))}catch{return}})();if(X===void 0)return`Failed to read ${V}; fix it, then ${st}`;let ee=n(X,"plugins");if(n(ee,"enabled")===!1)return`plugins.enabled is false in ${V}; no OpenClaw plugin loads`;let ne=n(n(n(ee,"entries"),dn),"enabled");if(Lc(n(ee,"deny")).includes(dn)||ne===!1)return`${dn} is disabled in ${V}; ${st}`;let te=Lc(n(ee,"allow"));if(te.length>0&&!te.includes(dn))return`plugins.allow in ${V} does not list ${dn}; add it, then ${st}`;if(te.includes(dn)||ne===!0)return;return`${dn} is not enabled; ${st}`}function Hc(I){return/^\/\/ version:\s*(.+)$/m.exec(I)?.[1]?.trim()}function my(I,V,X){if(X===void 0)return[];let ee=Zt(X,kn);if(!(("content"in ee)&&Hc(ee.content)===V))return[];return[kn,Wt,Yt].flatMap((te)=>{let le=Zt(I,te),de=Zt(X,te);if("error"in le||"error"in de||le.content===de.content)return[];return[`Modified ${te} occupies ${yr(I,te)}; run install --openclaw to restore it`]})}function Mc(I){let V=hr(I.environment),X=We(vo,V);if(X)return X;let ee=Zt(V,kn),te=["error"in ee?ee.error:ee.content.startsWith(yo)?void 0:`Unmanaged ${kn} occupies ${yr(V,kn)}; move or remove it`,uy(V),py(V)].filter((Ie)=>Ie!==void 0),le="content"in ee?Hc(ee.content):void 0,de=te.length>0?te:my(V,le,Wi());if(de.length>0)return{platform:vo,status:"n/a",configPath:V,errors:de};let be=le===un()?[]:["Installed OpenClaw plugin is outdated; run install --openclaw to update"],Se=fy(I.environment);if(Se)return{platform:vo,status:"disabled",method:"plugin directory",configPath:V,errors:[Se,...be]};return{platform:vo,status:"configured",method:"plugin directory",configPath:V,errors:be.length>0?be:void 0}}import{existsSync as xy,readFileSync as Py}from"node:fs";import{basename as Sy}from"node:path";import{existsSync as bo,readFileSync as Zi,rmSync as gy}from"node:fs";import{join as Tn}from"node:path";import{pathToFileURL as hy}from"node:url";var vr="cc-safety-net",at=`${vr}@latest`,Xi=["opencode.json","opencode.jsonc"],yy=60,vy=250,Uc="CCSafetyNetPlugin",by={stringError:"Unterminated string in OpenCode config",bracketError:"Unmatched plugin array in OpenCode config"};function Bc(I){return Tn(I.env.get("XDG_CONFIG_HOME")||Tn(I.home,".config"),"opencode")}function Qi(I){return I.env.get("OPENCODE_CONFIG_DIR")||Bc(I)}function es(I){return Xi.map((V)=>Tn(Qi(I),V))}function ns(I){return[...new Set([Qi(I),Bc(I)])].flatMap((V)=>Xi.map((X)=>Tn(V,X)))}function Gc(I){return Tn(I.env.get("XDG_CACHE_HOME")||Tn(I.home,".cache"),"opencode","packages",at)}function qc(I){gy(Gc(I),{recursive:!0,force:!0})}async function Vc(I){let V=(await pn(["opencode","--version"],{stdoutOnly:!0})).trim(),X=/^(?:opencode\s+)?v?(\d+)\.(\d+)\.(\d+)(?:[-+].*)?$/.exec(V),ee=Number(X?.[1]),ne=Number(X?.[2]),te=Number(X?.[3]);if(!X||ee!==1&&ee!==2||ee===1&&(ne<18||ne===18&&te<29)||ee===2&&ne===0&&te<6)throw Error(`OpenCode 1.18.29+ or 2.0.6+ is required; found ${V||"an unknown version"}.`);if(ee===2){for(let le of es(I)){if(!bo(le))continue;let de=rs(Zi(le,"utf-8"),le);if(["plugin","plugins"].some((Se)=>{let Ie=n(de,Se);return Array.isArray(Ie)&&Ie.some(($e)=>wo($e)&&(typeof $e==="string"?$e:n($e,"package"))!==at)}))throw Error(`Change the cc-safety-net package spec in ${le} to ${at}, preserving its options, then retry. Adding another spec would create a duplicate plugin ID.`)}return{commands:[],afterInstall:async()=>{if((await pn(["opencode","plugin","add",at],{stdoutOnly:!0})).includes("is already configured in"))await Yi(),await pn(["opencode","plugin","update",at]);let de=await Yi();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 be=["--param",`location[directory]=${process.cwd()}`];await pn(["opencode","api","integration.list",...be]);let Se=await pn(["opencode","api","plugin.list",...be],{stdoutOnly:!0}),Ie=ts(Se);if(Ie)throw Error(Ie);if(!Kc(Se).some(Jc))throw Error("OpenCode lists no active cc-safety-net for this directory. Run `opencode api plugin.list` for details.")}}}return qc(I),{commands:[["opencode","plugin","-g","-f",at]],afterInstall:()=>ky(I)}}function Kc(I){return wy(I).filter((V)=>n(V,"id")===vr||wo(n(n(V,"source"),"target"))).map((V)=>n(V,"state"))}function Jc(I){return n(I,"status")==="active"}function ts(I){let V=Kc(I);if(V.some(Jc))return;let X=V.find((ee)=>n(ee,"status")==="failed");if(!X)return;return`OpenCode reports cc-safety-net failed: ${String(n(X,"error")).split(`
|
|
226
|
+
`)[0]}`}function wy(I){if(!I)return[];try{let V=n(JSON.parse(I),"data");return Array.isArray(V)?V:[]}catch{return[]}}async function Yi(I=1){let V=await pn(["opencode","plugin","list"],{stdoutOnly:!0});if(/^cc-safety-net\s|\scc-safety-net@latest\s*$/m.test(V)||I===yy)return V;return await new Promise((X)=>setTimeout(X,vy)),Yi(I+1)}async function ky(I){let V=Tn(Gc(I),"node_modules",vr),X=Tn(V,"package.json");if(!bo(X))throw Error(`The OpenCode plugin cache at ${V} is missing its package, so OpenCode would load nothing and fail open. Run \`opencode plugin -g -f ${at}\` for details.`);let ee=n(JSON.parse(Zi(X,"utf-8")),"main");if(typeof ee!=="string")throw Error(`The cached OpenCode plugin at ${V} declares no "main" entry.`);let ne=Tn(V,ee);if(typeof(await import(hy(ne).href))[Uc]==="function")return;throw Error(`The cached OpenCode plugin at ${ne} does not export a callable ${Uc}, so OpenCode would load nothing and fail open.`)}function rs(I,V){try{return JSON.parse(gn(I))}catch(X){if(X instanceof SyntaxError)throw Error(`Failed to parse OpenCode config ${V}: ${X.message}`);throw X}}function wo(I){let V=typeof I==="string"?I:n(I,"package");return typeof V==="string"&&(V===vr||V.startsWith(`${vr}@`))}function os(I){return["plugin","plugins"].some((V)=>{let X=n(I,V);return Array.isArray(X)&&X.some(wo)})}function Cy(I,V){let ee=["plugin","plugins"].flatMap((ne)=>{let te=bl(I,ne,by);if(!te)return[];let le=[],de=0,be=te.start+1,Se=I.slice(te.start+1,te.end).matchAll(/\/\/[^\n]*|\/\*[\s\S]*?\*\/|"(?:\\.|[^"\\])*"|[^"\s{}[\],/]+|[{}[\],]/g);for(let Ie of Se){if(Ie[0].startsWith("//")||Ie[0].startsWith("/*"))continue;let $e=te.start+1+Ie.index;if(de===0)be=$e;if(Ie[0]==="{"||Ie[0]==="[")de++;if(Ie[0]==="}"||Ie[0]==="]")de--;if(de!==0||Ie[0]===",")continue;let Le=$e+Ie[0].length;if(wo(JSON.parse(gn(I.slice(be,Le)))))le.push({start:be,end:Le})}return le}).sort((ne,te)=>ne.start-te.start).reverse().reduce((ne,te)=>{let le=/^(?:\s|\/\/[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*,/.exec(ne.slice(te.end));if(le?.[0].includes("/")){let de=te.end+le[0].length-1;return ne.slice(0,te.start)+ne.slice(te.end,de)+ne.slice(de+1)}return vl(ne,te)},I);return rs(ee,V),ee}function zc(I){qc(I);let V=ns(I),X=V.find((te)=>bo(te)),ee=[],ne=[];for(let te of V){if(!bo(te))continue;try{let le=Zi(te,"utf-8");if(!os(rs(le,te)))continue;an(te,Cy(le,te)),ne.push(te)}catch(le){ee.push(le instanceof Error?le.message:String(le))}}if(ee.length>0)throw Error(ee.join(`
|
|
227
|
+
`));return{path:ne[0]??X??Tn(Qi(I),Xi[0]),alreadyInstalled:ne.length>0}}function Xt(I){let V=[];for(let X of I.openCodeVersion?.startsWith("2.")?es(I.environment):ns(I.environment))if(xy(X))try{let ee=Py(X,"utf-8"),ne=gn(ee),te=JSON.parse(ne);if(os(te)){let le=ts(I.openCodePluginListOutput);if(le)return{platform:"opencode",status:"disabled",method:"opencode api plugin.list",configPath:X,errors:[...V,le]};return{platform:"opencode",status:"configured",method:"plugin array",configPath:X,errors:V.length>0?V:void 0}}}catch(ee){V.push(`Failed to parse ${Sy(X)}: ${ee instanceof Error?ee.message:String(ee)}`)}return{platform:"opencode",status:"n/a",errors:V.length>0?V:void 0}}import{join as Wc}from"node:path";var Zc="dist/pi/index.js",Yc=new Set([Zc,"index.js"]),Ry=/[*?[\]{}]/;function is(I){let V=I.env.get("PI_CODING_AGENT_DIR");return Wc(V?B(V,I.home):Wc(I.home,".pi","agent"),"settings.json")}function ss(I){if(typeof I!=="string")return!1;return I==="npm:cc-safety-net"||I.startsWith("npm:cc-safety-net@")}function Ey(I){if(!Array.isArray(I)||I.length===0)return!1;if(!I.every((ee)=>typeof ee==="string"))return!1;let V=(ee)=>I.some((ne)=>ne.startsWith(ee)&&ne.slice(1).replace(/^\.[/\\]/,"")===Zc);if(V("-"))return!1;if(V("+"))return!0;let X=I.filter((ee)=>!/^[-+!]/.test(ee));return(X.length===0||X.some((ee)=>Yc.has(ee)))&&!I.some((ee)=>ee.startsWith("!")&&(Yc.has(ee.slice(1))||Ry.test(ee)))}function Xc(I){let V=is(I.environment),X=v(V);if(X.kind==="unreadable")return{platform:"pi",status:"not-inspected"};if(X.kind==="missing")return{platform:"pi",status:"n/a"};let ee=n(X.value,"packages");if(!Array.isArray(ee))return{platform:"pi",status:"n/a"};let ne=ee.find((le)=>ss(typeof le==="string"?le:n(le,"source")));if(ne===void 0)return{platform:"pi",status:"n/a"};let te=n(ne,"extensions");if(te!==void 0&&!Ey(te))return{platform:"pi",status:"disabled",method:"package config",configPath:V,errors:["npm:cc-safety-net is installed but its extension is disabled in Pi settings"]};return{platform:"pi",status:"configured",method:"package config",configPath:V}}var Ty={amp:rl,"antigravity-cli":al,"claude-code":pl,codex:ml,"copilot-cli":Ol,cursor:Ul,"deepseek-harness":Rt,devin:Wl,droid:rc,"gemini-cli":oc,"grok-build":mc,"hermes-agent":Rc,"kimi-code":ho,openclaw:Mc,opencode:Xt,pi:Xc};function Qt(I,V,X){let ee={...X,cwd:V,environment:I};return Or.map((ne)=>Ay(Ty[ne](ee)))}function Ay(I){if(I.status==="not-inspected")return{platform:I.platform,detected:!1,configured:!1,inspectionStatus:"not-inspected"};return{platform:I.platform,detected:I.status!=="n/a",configured:I.status==="configured",inspectionStatus:I.status!=="n/a"?"verified":I.errors&&I.errors.length>0?"failed":"not-applicable",method:I.method,configPath:I.configPath,configPaths:I.configPaths,errors:I.errors}}import{join as _y}from"node:path";var Iy=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}]),Oy=Object.freeze({state:"ready",diagnostics:Object.freeze([]),ruleMetadata:Object.freeze({}),policy:Object.freeze({rules:Object.freeze([]),transparentWrappers:Object.freeze([]),commandTools:Object.freeze([]),safety:Object.freeze({level:"standard"}),worktreeMode:!1,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:Object.freeze({}),destructiveCommandAllowPaths:Object.freeze([]),secretProtection:Object.freeze({enabled:!0,disabledRules:Object.freeze([]),denyPaths:Object.freeze([]),allowPaths:Object.freeze([])})})}),$y={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 Qc(I){let V=_y(I.tmpdir,"cc-safety-net-self-test"),X=Iy.map((ee)=>{let ne=z(I,d("self-test",{command:ee.command},{kind:"command",shell:"auto"},{configCwd:V,executionCwd:V},ee.command),{guard:{dependencies:{loadPolicySnapshot:()=>Oy,getModes:()=>$y,findPolicyMutation:()=>null}},audit:{agent:"self-test",getSessionId:()=>{return}}}),te=ee.expectBlocked?"blocked":"allowed",le=ne.decision.kind==="deny"?"blocked":"allowed";return{command:ee.command,description:ee.description,expected:te,actual:le,passed:te===le,reason:ne.decision.kind==="deny"?ne.decision.reason:void 0,ruleId:ne.decision.kind==="deny"?ne.decision.ruleId:void 0}});return{passed:X.filter((ee)=>ee.passed).length,failed:X.filter((ee)=>!ee.passed).length,total:X.length,results:X}}function as(I){let V=fn({label:"doctor",booleans:{json:["--json"],skipUpdateCheck:["--skip-update-check"]}},I);if(In(V.errors))return null;return{json:V.flags.json,skipUpdateCheck:V.flags.skipUpdateCheck}}async function ed(I,V={}){let X=await ar(!V.json,()=>{let ee=Ny(I,V);return{ready:ee,finish:()=>ee}},()=>sr(),{loadingMessage:"Checking system status…"});if(V.json)console.log(JSON.stringify(X,null,2));else Ly(X);return X.engineSelfTest.failed>0||X.findings.some((ee)=>ee.severity==="error")?1:0}async function Ny(I,V){let X=V.cwd??process.cwd(),ee=await Mr((Me)=>Xt({environment:I,cwd:X,openCodeVersion:Me}).status!=="n/a",void 0,X),ne=Qt(I,X,{ampPluginListOutput:ee.ampPluginListOutput,codexPluginListOutput:ee.codexPluginListOutput,copilotCliVersion:ee.versions["copilot-cli"],openCodeVersion:ee.versions.opencode,openCodePluginListOutput:ee.openCodePluginListOutput}),te=wa(I,X),le=ka(I),de=w(I,{cwd:X}),be=de.policy,Se=O(be,I.env),Ie=Z(be,Se.capabilities),$e=Lr(I,7),Le=Xa(I,X),Ne=[Ut(X),Bt(I)].filter((Me)=>Dy(Me)),Fe=V.skipUpdateCheck?{currentVersion:un(),latestVersion:null,updateAvailable:!1}:await Hn(),Be={hooks:ne,engineSelfTest:Qc(I),userConfig:te.userConfig,projectConfig:te.projectConfig,configState:nt(de),effectiveRules:te.effectiveRules,environment:le,effectiveSafety:{selectedPreset:be.safety.level,level:Se.effectiveLevel,capabilities:Se.capabilities,ruleOverrides:be.destructiveCommandRuleOverrides,weakenedRuleOverrides:Object.entries(Ie).filter(([,Me])=>Me.source==="rule_override"&&Me.override==="off"&&Me.inheritedEnabled&&Me.changesInherited).map(([Me])=>Me),ruleCounts:{stored:Object.keys(be.destructiveCommandRuleOverrides).length,effective:Object.values(Ie).filter((Me)=>Me.changesInherited).length},...de.policyScopes?{policyScopes:de.policyScopes}:{}},...Le.length>0?{v2Leftovers:Le}:{},...Ne.length>0?{legacyConfigs:Ne}:{},posture:Na(I,te.userConfig.path),activity:$e,update:Fe,system:ee};return{...Be,findings:xa(Be)}}function Ly(I){console.log(),console.log(Sa(I.hooks)),console.log(),console.log(Ra(I.engineSelfTest)),console.log(),console.log(Ea(I)),console.log(),console.log(Ta(I.environment)),console.log(),console.log(Aa(I)),console.log(),console.log(_a(I.findings)),console.log(),console.log(Ia(I.activity)),console.log(),console.log($a(I.system)),console.log(),console.log(Oa(I.update)),console.log(Da(I))}import{existsSync as jy}from"node:fs";var Fy=/^[A-Za-z0-9_@%+=:,./-]+$/,ls="Usage: cc-safety-net explain [--json] [--cwd <path>] [--shell <auto|posix|powershell>] <command>",Hy=["auto","posix","powershell"];function cs(I){let V=fn({label:"explain",booleans:{json:["--json"]},values:{cwd:["--cwd"],shell:["--shell"]},positionals:"tail"},I);if(In(V.errors))return console.error(ls),console.error("Pass -- before a command that starts with dashes."),null;if(V.values.cwd!==void 0&&!jy(V.values.cwd))return console.error(`Error: --cwd path does not exist: ${V.values.cwd}`),null;let X=Hy.find((ne)=>ne===V.values.shell);if(V.values.shell!==void 0&&!X)return console.error(`Error: --shell must be auto, posix, or powershell, got: ${V.values.shell}`),console.error(ls),null;let ee=V.positionals.length===1?V.positionals[0]:V.positionals.map((ne)=>Fy.test(ne)?ne:`'${ne.replaceAll("'",X==="powershell"?"''":"'\\''")}'`).join(" ");if(!ee)return console.error("Error: No command provided"),console.error(ls),null;return{json:V.flags.json,cwd:V.values.cwd,shell:X,command:ee}}function nd(I){if(I)return{dh:"=",dv:"|",dtl:"+",dtr:"+",dbl:"+",dbr:"+",h:"-",v:"|",tl:"+",tr:"+",bl:"+",br:"+",sh:"="};return{dh:"═",dv:"║",dtl:"╔",dtr:"╗",dbl:"╚",dbr:"╝",h:"─",v:"│",tl:"┌",tr:"┐",bl:"└",br:"┘",sh:"━"}}function td(I,V){let ee=V-18;return[`${I.dtl}${I.dh.repeat(V)}${I.dtr}`,`${I.dv} Command Analysis${" ".repeat(ee)}${I.dv}`,`${I.dbl}${I.dh.repeat(V)}${I.dbr}`]}function ds(I){return JSON.stringify(I)}function rd(I,V=0){return`[${I.map((ee,ne)=>Pa(ee,ne,V)).join(",")}]`}function br(I,V,X=70){let ee=I.split(" "),ne=[],te="";for(let le of ee)if(te&&te.length+le.length+1>X)ne.push(te),te=le;else te=te?`${te} ${le}`:le;if(te)ne.push(te);return ne.map((le,de)=>de===0?le:`${V}${le}`)}function od(I,V,X){let ee=[];switch(I.type){case"parse":return null;case"env-strip":return ee.push(""),ee.push(`STEP ${V} ${X.h} Strip environment variables`),ee.push(` Removed: ${I.envVars.map((ne)=>`${ne}=<redacted>`).join(", ")}`),ee.push(` Tokens: ${ds(I.output)}`),{lines:ee,incrementStep:!0};case"leading-tokens-stripped":return ee.push(""),ee.push(`STEP ${V} ${X.h} Strip wrappers`),ee.push(` Removed: ${I.removed.join(", ")}`),ee.push(` Tokens: ${ds(I.output)}`),{lines:ee,incrementStep:!0};case"shell-wrapper":return ee.push(""),ee.push(`STEP ${V} ${X.h} Detect shell wrapper`),ee.push(` Wrapper: ${I.wrapper} -c`),ee.push(` Inner: ${I.innerCommand}`),{lines:ee,incrementStep:!0};case"interpreter":{if(ee.push(""),ee.push(`STEP ${V} ${X.h} Detect interpreter`),ee.push(` Interpreter: ${I.interpreter}`),ee.push(` Code: ${I.codeArg}`),I.paranoidBlocked)ee.push(" Result: ✗ BLOCKED (paranoid mode)");return{lines:ee,incrementStep:!0}}case"busybox":return ee.push(""),ee.push(`STEP ${V} ${X.h} Busybox wrapper`),ee.push(` Subcommand: ${I.subcommand}`),{lines:ee,incrementStep:!0};case"transparent-wrapper":return ee.push(""),ee.push(`STEP ${V} ${X.h} Transparent wrapper`),ee.push(` Wrapper: ${I.wrapper}`),ee.push(` Tokens: ${ds(I.output)}`),{lines:ee,incrementStep:!0};case"recurse":return{lines:[],incrementStep:!1};case"script-file":return ee.push(""),ee.push(`STEP ${V} ${X.h} Read script file`),ee.push(` Path: ${I.path}`),ee.push(` Size: ${I.bytes} bytes`),{lines:ee,incrementStep:!0};case"rule-check":{if(ee.push(""),ee.push(`STEP ${V} ${X.h} Match rules`),ee.push(` Rule: ${I.rule}()`),I.matched)ee.push(" Result: MATCHED");else ee.push(" Result: No match");return{lines:ee,incrementStep:!0}}case"worktree-relaxation":return ee.push(""),ee.push(`STEP ${V} ${X.h} Worktree relaxation`),ee.push(` Mode: ${r.worktree.name}`),ee.push(` Git cwd: ${I.gitCwd}`),ee.push(" Result: Allowed local discard in linked worktree"),{lines:ee,incrementStep:!0};case"temp-root-relaxation":return ee.push(""),ee.push(`STEP ${V} ${X.h} Temp-root relaxation`),ee.push(` Git cwd: ${I.gitCwd}`),ee.push(" Result: Allowed git discard in a temp-root repository"),{lines:ee,incrementStep:!0};case"tmpdir-check":return null;case"fallback-scan":{if(I.embeddedCommandFound)return ee.push(""),ee.push(`STEP ${V} ${X.h} Fallback scan`),ee.push(` Found: ${I.embeddedCommandFound}`),{lines:ee,incrementStep:!0};return null}case"custom-rules-check":{if(I.rulesChecked){if(ee.push(""),ee.push(`STEP ${V} ${X.h} Custom rules`),I.matched)ee.push(" Result: MATCHED");else ee.push(" Result: No match");return{lines:ee,incrementStep:!0}}return null}case"cwd-change":return null;case"dangerous-text":{if(I.matched)return ee.push(""),ee.push(`STEP ${V} ${X.h} Dangerous text check`),ee.push(` Token: ${I.token}`),ee.push(" Result: MATCHED"),{lines:ee,incrementStep:!0};return null}case"strict-unparseable":return ee.push(""),ee.push(`STEP ${V} ${X.h} Strict mode check`),ee.push(` Command: ${I.rawCommand}`),ee.push(" Result: ✗ UNPARSEABLE"),{lines:ee,incrementStep:!0};case"segment-skipped":return null;case"error":return ee.push(""),ee.push(`ERROR: ${I.message}`),{lines:ee,incrementStep:!1};default:return I}}function us(I,V){let X=nd(V?.asciiOnly??!1),ee=58,ne=[],te=1;ne.push(...td(X,58)),ne.push("");let le=I.trace.steps.find((Fe)=>Fe.type==="error");if(le&&le.type==="error"){ne.push("ERROR"),ne.push(` ${le.message}`),ne.push(""),ne.push("RESULT"),ne.push(` Status: ${I.result==="blocked"?qe.red("BLOCKED"):qe.green("ALLOWED")}`),ne.push(""),ne.push("CONFIG");let Fe=I.configSource??"none";return ne.push(` Path: ${Fe}`),ne.join(`
|
|
228
|
+
`)}let de=I.trace.steps.find((Fe)=>Fe.type==="parse");if(de&&de.type==="parse"){ne.push("INPUT"),ne.push(` ${de.input}`),ne.push(""),ne.push(`STEP ${te} ${X.h} Split shell commands`),te++;for(let Fe=0;Fe<de.segments.length;Fe++){let Be=de.segments[Fe];if(Be){let Me=Math.random();ne.push(` Segment ${Fe+1}: ${rd(Be,Me)}`)}}}let be=I.trace.segments,Se=be.length>1;for(let Fe of be){if(Se){ne.push("");let en="";if(de&&de.type==="parse"){let Ko=de.segments[Fe.index];if(Ko)en=Ko.join(" ")}let on=54,ln=en,nn=` Segment ${Fe.index+1}: `,sn=" ";if(en){if(nn.length+en.length+sn.length>on){let yf=on-nn.length-sn.length;ln=`${en.substring(0,yf-1)}…`}}let Sn=en?`${nn}${ln}${sn}`:` Segment ${Fe.index+1} `,jt=en?`${nn}${qe.cyan(ln)}${sn}`:Sn,zs=58-Sn.length,Ws=Math.floor(zs/2),hf=zs-Ws;ne.push(`${X.sh.repeat(Ws)}${jt}${X.sh.repeat(hf)}`)}if(Fe.steps.find((en)=>en.type==="segment-skipped")){ne.push(""),ne.push(" (skipped — prior segment blocked)");continue}let Me=!1,tn=!1;for(let en of Fe.steps){let on=od(en,te,X);if(on){if(tn=!0,en.type==="recurse"){ne.push("");let ln=" RECURSING ",nn=58-ln.length-4;ne.push(` ${X.tl}${X.h}${ln}${X.h.repeat(nn)}`),ne.push(` ${X.v}`),Me=!0;continue}for(let ln of on.lines)if(Me)ne.push(` ${X.v} ${ln}`);else ne.push(ln);if(on.incrementStep)te++}}if(Me)ne.push(` ${X.v}`),ne.push(` ${X.bl}${X.h.repeat(56)}`);if(!tn)ne.push(""),ne.push(` ${qe.green("✓")} Allowed (no matching rules)`)}if(ne.push(""),ne.push("RESULT"),I.result==="blocked"){if(ne.push(` Status: ${qe.red("BLOCKED")}`),I.customRule){if(ne.push(` Rule: ${I.customRule.id}`),I.customRule.rulebook)ne.push(` Rulebook: ${I.customRule.rulebook.name} ${I.customRule.rulebook.version}`);if(I.customRule.source)ne.push(` Source: ${I.customRule.source}`);if(I.customRule.override)ne.push(` Override: reason ${I.customRule.override.reason}`)}if(I.reason){let Fe=br(I.reason," ");ne.push(` Reason: ${Fe[0]}`);for(let Be=1;Be<Fe.length;Be++)ne.push(Fe[Be]??"")}}else ne.push(` Status: ${qe.green("ALLOWED")}`);ne.push(""),ne.push("CONFIG");let Ie=I.configSource??"none",$e=I.configValid?"":" (invalid)";ne.push(` Path: ${Ie}${$e}`);let Le=I.safetyPresetScope;ne.push(` Safety preset: ${I.selectedPreset??"standard"}${Le?` (${jr(Le)})`:""}`),ne.push(` Effective capabilities: ${I.effectiveLevel}`);let Ne=Object.entries(I.destructiveCommandRuleOverrides??{});if(ne.push(` Rule customizations: ${Ne.length}`),I.ruleActivation)ne.push(` Rule activation: ${I.ruleActivation.id} — ${I.ruleActivation.enabled?"on":"off"} via ${I.ruleActivation.source}`);return ne.join(`
|
|
229
|
+
`)}function ps(I){return JSON.stringify(I,null,2)}import{resolve as Gy}from"node:path";var id=512,sd={maxTextLength:2048,maxListLength:128,maxObjectProperties:128,maxDepth:16},My=["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 gs(I){let V=0,X={allocateSegment(){return V++},getNextSegmentIndex(){return V},branch(){let ee=I.fork(),ne=gs(ee);return{trace:ne,adopt(){I.replaceSegmentEvents(ee.finish().events),V=ne.getNextSegmentIndex()}}},recordGlobal(ee){I.record({scope:"global",step:ee})},recordSegment(ee,ne=X.currentSegmentIndex){if(ne===void 0)return;I.record({scope:"segment",segmentIndex:ne,step:ee})}};return X}function hs(I=new Set){let V=[];return{record(X){if(V.length>=id)return;ko(X.step,I,sd),V.push({...X,step:fs(X.step,sd,I)})},fork(){return hs(I)},replaceSegmentEvents(X){V.splice(0,V.length,...[...V.filter((ee)=>ee.scope==="global"),...X].slice(0,id))},finish(){return{events:V}}}}function ko(I,V,X,ee=0,ne=new WeakSet){if(typeof I==="string"){let de=I.slice(0,X.maxTextLength);if(!pt(de))return;for(let be of Pt(de))for(let Se of be.match(/[^\s"'()$]+/g)??[])V.add(ad(Se));return}if(!I||typeof I!=="object"||ee>=X.maxDepth||ne.has(I))return;if(ne.add(I),Array.isArray(I)){let de=Math.min(I.length,X.maxListLength);for(let be=0;be<de;be++)ko(I[be],V,X,ee+1,ne);return}let te=0,le=new Set;for(let de in I){if(!Object.hasOwn(I,de))continue;if(te>=X.maxObjectProperties)break;te++,ko(de,V,X);let be=ms(de,X,V);if(le.has(be))continue;le.add(be),ko(I[de],V,X,ee+1,ne)}}function fs(I,V,X,ee=0,ne=new WeakSet){if(typeof I==="string")return ms(I,V,X);if(!I||typeof I!=="object")return I;if(ee>=V.maxDepth)return;if(ne.has(I))return;if(ne.add(I),Array.isArray(I)){let de=[],be=Math.min(I.length,V.maxListLength);for(let Se=0;Se<be;Se++)de.push(fs(I[Se],V,X,ee+1,ne));return de}let te={},le=0;for(let de in I){if(!Object.hasOwn(I,de))continue;if(le>=V.maxObjectProperties)break;le++;let be=ms(de,V,X);if(Object.hasOwn(te,be))continue;Object.defineProperty(te,be,{value:fs(I[de],V,X,ee+1,ne),enumerable:!0,configurable:!0,writable:!0})}return te}function ms(I,V,X){let ee=I.slice(0,V.maxTextLength),ne=pt(ee)?dt(ee):ee,te=X.size>0?By(ne,X):ne;return(Uy(te)?Ve(te):te).slice(0,V.maxTextLength)}function Uy(I){return I.includes("PRIVATE KEY")||I.includes("://")||I.includes("eyJ")||I.includes(":")&&/(?:authorization|cookie|x-api-key|api-key|(?:^|\s)(?:-u|--user)(?:\s|=))/i.test(I)||I.length>=14&&My.some((V)=>I.includes(V))||I.length>=49&&/\b[a-f0-9]{32}\.[A-Za-z0-9]{16}\b/.test(I)}function By(I,V){return I.replace(/[^\s"'()$]+/g,(X)=>V.has(ad(X))?"<redacted>":X)}function ad(I){let V=2166136261,X=2166136261;for(let ee=0;ee<I.length;ee++)V=Math.imul(V^I.charCodeAt(ee),16777619),X=Math.imul(X^I.charCodeAt(I.length-ee-1),16777619);return`${V>>>0}:${X>>>0}:${I.length}`}function wr(I,V={},X){let ee=Gy(V.cwd??process.cwd()),ne=V.policySnapshot??w(X,{cwd:ee,userConfigDir:V.userConfigDir}),te=O(ne.policy,X.env),le=_e({policySnapshot:ne,effectiveCapabilities:te.capabilities,worktreeMode:te.worktreeMode}),de={effectiveLevel:le.effectiveLevel,selectedPreset:ne.policy.safety.level,...ne.policyScopes?{safetyPresetScope:ne.policyScopes.levelScope}:{},effectiveCapabilities:le.effectiveCapabilities,destructiveCommandRuleOverrides:ne.policy.destructiveCommandRuleOverrides},{configSource:be,configValid:Se}=Vy(X,{cwd:ee,userConfigDir:V.userConfigDir});if(!I||!I.trim())return{trace:{steps:[{type:"error",message:"No command provided"}],segments:[]},result:"allowed",configSource:be,configValid:Se,...de};let Ie=V.shell??"auto",$e=C(I,Ie);if($e.status==="limited")throw new E;let Le=$e.dialect==="powershell"?C(I,"posix"):$e,Ne=Mt(Le),Fe=hs(),Be=gs(Fe);Be.recordGlobal({type:"parse",input:I,segments:Ne.map((jt)=>[...jt])});let Me=d("Bash",{command:I},{kind:"command",shell:Ie},{configCwd:ee,executionCwd:ee},I),tn=G(Me,{environment:X,trace:Be,dependencies:{loadPolicySnapshot:()=>ne}}),en=tn.decision.kind==="deny"?tn.decision:null;if(en&&(tn.stage==="policy-protection"||tn.stage==="secret-protection"))return{trace:{steps:[],segments:[{index:0,steps:[{type:"rule-check",rule:qy(en),matched:!0,reason:en.reason}]}]},result:"blocked",reason:A(en.reason),segment:A(ld(en,I)),ruleId:A(en.ruleId),configSource:be,configValid:Se,...de};let on=Be.getNextSegmentIndex();if(en&&on>0&&on<Ne.length)Be.recordSegment({type:"segment-skipped",index:on,reason:"prior-segment-blocked"},on);let ln=Fe.finish(),nn=en?.ruleId??Ky(Me,ne,te,X),sn=Y.find((jt)=>jt.id===nn&&jt.activationCapability),Sn=sn?le.policy.effectiveDestructiveCommandRules[sn.id]:void 0;return{trace:zy(ln),result:en?"blocked":"allowed",reason:en?A(en.reason):void 0,segment:en?A(ld(en,I)):void 0,ruleId:en?A(en.ruleId):void 0,customRule:Jy(Wy(en?.ruleId,ne)),configSource:be,configValid:Se,...de,...sn&&Sn?{ruleActivation:{id:sn.id,...Sn}}:{}}}function ld(I,V){return I.evidence?.segment??V}function qy(I){if(I.reason===ot)return"policy-protection:findPolicyConfigMutationTargetInSemanticFacts";if(I.reason===rt)return"policy-apply-protection:findPolicyApplyInvocationInSemanticFacts";if(I.reason===y)return"git-metadata-protection:findGitMetadataMutationTargetInSemanticFacts";return"secret-protection:findSensitiveTargetInSemanticFacts"}function Vy(I,V){let X=D(V.cwd),ee=K(I,V),ne=oe(I,{cwd:V.cwd,userConfigDir:V.userConfigDir});try{if(o(ne.projectConfigTarget)!==null){if(Fn(ne.projectConfigTarget).errors.length===0)return{configSource:X,configValid:!0};return{configSource:X,configValid:!1}}}catch(te){if(te instanceof i)return{configSource:X,configValid:!1};throw te}try{if(o(ne.userConfigTarget)!==null){let te=Fn(ne.userConfigTarget);return{configSource:ee,configValid:te.errors.length===0}}return{configSource:null,configValid:!0}}catch(te){if(te instanceof i)return{configSource:ee,configValid:!1};throw te}}function Ky(I,V,X,ee){let ne=V.policy,te=Ge({...ne,destructiveCommandProtectionEnabled:!0,destructiveCommandRuleOverrides:{...ne.destructiveCommandRuleOverrides,...Object.fromEntries(Y.flatMap((de)=>de.activationCapability?[[de.id,"on"]]:[]))}},V.state==="degraded"?{diagnostics:V.diagnostics,reason:V.reason}:void 0),le=G(I,{environment:ee,dependencies:{loadPolicySnapshot:()=>te,getModes:()=>({...X,strict:!0,paranoidRm:!0,paranoidInterpreters:!0,capabilities:{fail_closed:{...X.capabilities.fail_closed,enabled:!0},paranoid_rm:{...X.capabilities.paranoid_rm,enabled:!0},paranoid_interpreters:{...X.capabilities.paranoid_interpreters,enabled:!0}}}),findSensitiveTarget:()=>null}});return le.decision.kind==="deny"?le.decision.ruleId:void 0}function Jy(I){if(!I)return;return{id:A(I.id),...I.rulebook?{rulebook:{name:A(I.rulebook.name),version:A(I.rulebook.version)}}:{},...I.source?{source:A(I.source)}:{},...I.override?{override:{type:"reason",reason:A(I.override.reason)}}:{}}}function zy(I){let V=I.events.flatMap((ee)=>ee.scope==="global"?[ee.step]:[]),X=new Map;for(let ee of I.events){if(ee.scope!=="segment")continue;let ne=X.get(ee.segmentIndex)??{index:ee.segmentIndex,steps:[]};ne.steps.push(ee.step),X.set(ee.segmentIndex,ne)}return{steps:V,segments:[...X.values()]}}function Wy(I,V){let X=I?.replace(/^custom\./,"");if(!X||!V.policy.rules.some((ee)=>ee.name===X))return;return V.ruleMetadata[X]??Object.freeze({id:X})}function cd(I){return new Promise((V)=>{process.stdout.write(`${I}
|
|
230
|
+
`,()=>V())})}async function dd(I,V){let X=cs(V);if(!X)return 1;try{let ee=wr(X.command,{cwd:X.cwd,shell:X.shell},I),ne=!!process.env.NO_COLOR||!process.stdout.isTTY;return await cd(X.json?ps(ee):us(ee,{asciiOnly:ne})),0}catch(ee){let ne=Yy(ee instanceof g?ee.cause:ee);if(ne===void 0)throw ee;if(X.json)return await cd(JSON.stringify({error:ne})),1;return console.error(ne),1}}function Yy(I){if(I instanceof E)return I.message;if(I instanceof H)return I.message;if(I instanceof h)return I.message;if(I instanceof a&&l[I.kind].errorCode==="path-canonicalization-limit")return"Path canonicalization work limit exceeded.";return}var ud="2.7.2",Pn=" ",mt="cc-safety-net";function pd(I){return I.argument?`${I.flags} ${I.argument}`:I.flags}function Zy(I){return Math.max(...I.map((V)=>pd(V).length))}function Xy(I){return Math.max(...I.map((V)=>V.usage.length))}function Qy(I){return Math.max(...I.map((V)=>`${mt} ${V.usage}`.length))}function ev(I,V){let X=`${mt} ${I.usage}`;return`${Pn}${X.padEnd(V+2)}${I.description}`}function An(I,V){return`${Pn}${I.padEnd(Math.max(40,I.length+2))}${V}`}function er(I,V=console.log){let X=[];if(X.push(`${mt} ${I.name}`),X.push(""),X.push(`${Pn}${I.description}`),X.push(""),X.push("USAGE:"),X.push(`${Pn}${mt} ${I.usage}`),X.push(""),I.subcommands&&I.subcommands.length>0){X.push("SUBCOMMANDS:");let ee=Xy(I.subcommands);for(let ne of I.subcommands)X.push(`${Pn}${ne.usage.padEnd(ee+2)}${ne.description}`);X.push("")}if(I.options.length>0){X.push("OPTIONS:");let ee=Zy(I.options);for(let ne of I.options){let te=pd(ne),le=ne.default?`${ne.description} (default: ${ne.default})`:ne.description;X.push(`${Pn}${te.padEnd(ee+2)}${le}`)}X.push("")}if(I.examples&&I.examples.length>0){X.push("EXAMPLES:");for(let ee of I.examples)X.push(`${Pn}${ee}`)}V(X.join(`
|
|
231
231
|
`))}function ys(){let I=Qy(Dr),V=[];V.push(`${mt} v${ud}`),V.push(""),V.push("Blocks destructive commands and secret access."),V.push(""),V.push("COMMANDS:");for(let X of Dr)V.push(ev(X,I));V.push(""),V.push("GLOBAL OPTIONS:"),V.push(`${Pn}-h, --help Show help (use with command for command-specific help)`),V.push(`${Pn}-V, --version Show version`),V.push(""),V.push("HELP:"),V.push(`${Pn}${mt} help <command> Show help for a specific command`),V.push(`${Pn}${mt} <command> --help Show help for a specific command`),V.push(""),V.push("ENVIRONMENT VARIABLES:"),V.push(An(`${r.level.name}=standard|strict|paranoid`,"Set session safety level")),V.push(An(`${r.worktree.name}=1`,"Allow local git discards in linked worktrees")),V.push(An(`${r.debug.name}=1`,"Print diagnostic messages to stderr")),V.push(An(`${r.auditScope.name}=all|blocked`,"Record all command decisions, or denials only")),V.push(An(`${r.projectTightenOnly.name}=1`,"Ignore project policy settings that weaken the user policy")),V.push(An("CC_SAFETY_NET_HOME","Override rule config home directory")),V.push(""),V.push("LEGACY ENVIRONMENT VARIABLES (STILL SUPPORTED):"),V.push(An(`${r.strict.name}=1`,"Force safety.overrides.fail_closed on")),V.push(An(`${r.paranoid.name}=1`,"Force paranoid_rm and paranoid_interpreters on")),V.push(An(`${r.paranoidRm.name}=1`,"Force safety.overrides.paranoid_rm on")),V.push(An(`${r.paranoidInterpreters.name}=1`,"Force safety.overrides.paranoid_interpreters on")),V.push(""),V.push("Documentation: https://ccsafetynet.com/docs"),console.log(V.join(`
|
|
232
|
-
`))}function fd(){console.log(ud)}function kr(I,V=console.log){let X=Nr(I);if(!X)return!1;if(X.name.toLowerCase()!==I.toLowerCase())return!1;return er(X,V),!0}import{existsSync as Ao,readFileSync as bu}from"node:fs";import{join as To}from"node:path";import*as Bn from"node:readline";function nv(I){return I==="install"?"Install":"Uninstall"}function tv(I){return I==="install"?"Installing":"Uninstalling"}function rv(I){return I==="install"?"into":"from"}function hd(I){return I?.available===!0}function ov(I,V){let X=new Set(V);return I.filter((ee)=>X.has(ee.target)).map((ee)=>ee.target)}function md(I,V,X){if(I.every((ee)=>!ee.available))return V;return Array.from({length:I.length},(ee,ne)=>ne+1).map((ee)=>(V+ee*X+I.length)%I.length).find((ee)=>hd(I[ee]))}function iv(I,V,X){if(X.ctrl&&X.name==="c")return"interrupt";if(X.name==="escape"||V==="q")return"abort";if(I==="install"&&(V==="u"||V==="U"))return"update";if(X.name==="up"||V==="k")return"up";if(X.name==="down"||V==="j")return"down";if(X.name==="space"||V===" ")return"toggle";if(X.name==="return"||X.name==="enter")return"confirm";return null}function sv(I){return{cursor:I.findIndex((V)=>V.available),selected:[]}}function av(I,V,X){if(X==="confirm"||X==="update"||X==="abort"||X==="interrupt")return{state:I,done:X};if(X==="up")return{state:{...I,cursor:md(V,I.cursor,-1)}};if(X==="down")return{state:{...I,cursor:md(V,I.cursor,1)}};let ee=V[I.cursor];if(!hd(ee))return{state:I};let ne=I.selected.includes(ee.target)?I.selected.filter((te)=>te!==ee.target):ov(V,[...I.selected,ee.target]);return{state:{...I,selected:ne}}}var yd="◉",vd="◯",bd=">",wd=" ";function lv(I,V,X){return["",`${nv(I)} CC Safety Net ${rv(I)}:`,"",...V.map((ee,ne)=>{let te=X.selected.includes(ee.target),le=ne===X.cursor,de=te?yd:vd,
|
|
233
|
-
`)}var gd=["global-hook","plugin"];function cv(I,V,X={}){let ee=X.color!==!1?qe.bold:(te)=>te;return["","Install the Kimi Code integration as:","",...[`Global hook — ${V?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((te,le)=>{let de=le===I,
|
|
232
|
+
`))}function fd(){console.log(ud)}function kr(I,V=console.log){let X=Nr(I);if(!X)return!1;if(X.name.toLowerCase()!==I.toLowerCase())return!1;return er(X,V),!0}import{existsSync as Ao,readFileSync as bu}from"node:fs";import{join as To}from"node:path";import*as Bn from"node:readline";function nv(I){return I==="install"?"Install":"Uninstall"}function tv(I){return I==="install"?"Installing":"Uninstalling"}function rv(I){return I==="install"?"into":"from"}function hd(I){return I?.available===!0}function ov(I,V){let X=new Set(V);return I.filter((ee)=>X.has(ee.target)).map((ee)=>ee.target)}function md(I,V,X){if(I.every((ee)=>!ee.available))return V;return Array.from({length:I.length},(ee,ne)=>ne+1).map((ee)=>(V+ee*X+I.length)%I.length).find((ee)=>hd(I[ee]))}function iv(I,V,X){if(X.ctrl&&X.name==="c")return"interrupt";if(X.name==="escape"||V==="q")return"abort";if(I==="install"&&(V==="u"||V==="U"))return"update";if(X.name==="up"||V==="k")return"up";if(X.name==="down"||V==="j")return"down";if(X.name==="space"||V===" ")return"toggle";if(X.name==="return"||X.name==="enter")return"confirm";return null}function sv(I){return{cursor:I.findIndex((V)=>V.available),selected:[]}}function av(I,V,X){if(X==="confirm"||X==="update"||X==="abort"||X==="interrupt")return{state:I,done:X};if(X==="up")return{state:{...I,cursor:md(V,I.cursor,-1)}};if(X==="down")return{state:{...I,cursor:md(V,I.cursor,1)}};let ee=V[I.cursor];if(!hd(ee))return{state:I};let ne=I.selected.includes(ee.target)?I.selected.filter((te)=>te!==ee.target):ov(V,[...I.selected,ee.target]);return{state:{...I,selected:ne}}}var yd="◉",vd="◯",bd=">",wd=" ";function lv(I,V,X){return["",`${nv(I)} CC Safety Net ${rv(I)}:`,"",...V.map((ee,ne)=>{let te=X.selected.includes(ee.target),le=ne===X.cursor,de=te?yd:vd,be=le?bd:wd,Se=ee.available?"":` (${ee.unavailableReason??"not installed"})`,Ie=`${de} ${ee.label}${Se}`,$e=!ee.available?qe.dim(Ie):te?qe.green(Ie):le?qe.bold(Ie):Ie;return`${be} ${$e}`}),"",I==="install"?"Space: select Enter: confirm u: update installed Up/Down: move q/Esc: cancel":V.some((ee)=>ee.available)?"Space: select Enter: confirm Up/Down: move q/Esc: cancel":`No selectable integrations found for ${I}. q/Esc: close`].join(`
|
|
233
|
+
`)}var gd=["global-hook","plugin"];function cv(I,V,X={}){let ee=X.color!==!1?qe.bold:(te)=>te;return["","Install the Kimi Code integration as:","",...[`Global hook — ${V?"already installed; selecting it reports the current state":"write the hook into ~/.kimi-code/config.toml now"}`,"Native Kimi plugin — print the steps to run inside Kimi Code"].map((te,le)=>{let de=le===I,be=`${de?yd:vd} ${te}`;return`${de?bd:wd} ${de?ee(be):be}`}),"","Enter: confirm Up/Down: move q/Esc: cancel"].join(`
|
|
234
234
|
`)}function kd(I){let{input:V,output:X}=I;Bn.emitKeypressEvents(V);let ee=V.isRaw===!0;V.setRawMode(!0),V.resume();let ne=0,te=()=>{if(ne===0)return;Bn.moveCursor(X,0,-ne),Bn.cursorTo(X,0),Bn.clearScreenDown(X)},le=()=>{te();let de=I.render();X.write(`${de}
|
|
235
235
|
`),ne=de.split(`
|
|
236
|
-
`).length};return new Promise((de)=>{let
|
|
237
|
-
`);return}de.draw()}})}import{existsSync as Pd,lstatSync as uv,mkdirSync as pv,mkdtempSync as fv,readdirSync as mv,readFileSync as tr,rmSync as xo}from"node:fs";import{basename as gv,dirname as hv,join as wn}from"node:path";import{fileURLToPath as yv}from"node:url";var bs="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",kt="cc-safety-net",Et="cc-safety-net/index.ts";import{spawn as dv}from"node:child_process";var ws=(I,V)=>{let X=Wn([...I],process.env);return new Promise((ee)=>{let ne=dv(X.cmd,X.args,{cwd:V,stdio:["ignore","pipe","pipe"]}),te=hi(ne),le=!1,de=setTimeout(()=>{le=!0,ne.kill()},120000);ne.on("error",(
|
|
238
|
-
`)})}),ne.on("close",(
|
|
236
|
+
`).length};return new Promise((de)=>{let be=(Ie)=>{V.off("keypress",Se),V.setRawMode(ee),V.pause(),te(),de(Ie)};function Se(Ie,$e){I.onKey(Ie,$e,{finish:be,draw:le})}V.on("keypress",Se),le()})}function Cd(I={}){let V=0;return kd({input:I.input??process.stdin,output:I.output??process.stdout,render:()=>cv(V,I.globalHookInstalled===!0),onKey:(X,ee,ne)=>{if(ee.ctrl&&ee.name==="c"){ne.finish(null),(I.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(ee.name==="escape"||X==="q")return ne.finish(null);if(ee.name==="return"||ee.name==="enter")return ne.finish(gd[V]);if(ee.name==="up"||ee.name==="down"||X==="k"||X==="j")V=(V+1)%gd.length,ne.draw()}})}function vs(I=process.stdin,V=process.stdout){return Boolean(I.isTTY&&V.isTTY&&typeof I.setRawMode==="function")}function xd(I,V,X={}){let ee=X.output??process.stdout,ne=sv(V);return kd({input:X.input??process.stdin,output:ee,render:()=>lv(I,V,ne),onKey:(te,le,de)=>{let be=iv(I,te,le);if(!be)return;let Se=av(ne,V,be);if(ne=Se.state,Se.done==="interrupt"){de.finish(null),(X.onInterrupt??(()=>process.kill(process.pid,"SIGINT")))();return}if(Se.done==="abort")return de.finish(null);if(Se.done==="update")return de.finish("update");if(Se.done==="confirm"){if(ne.selected.length===0){ee.write("\x07"),de.draw();return}de.finish([...ne.selected]),ee.write(`${tv(I)} selected integrations...
|
|
237
|
+
`);return}de.draw()}})}import{existsSync as Pd,lstatSync as uv,mkdirSync as pv,mkdtempSync as fv,readdirSync as mv,readFileSync as tr,rmSync as xo}from"node:fs";import{basename as gv,dirname as hv,join as wn}from"node:path";import{fileURLToPath as yv}from"node:url";var bs="// cc-safety-net managed Amp plugin. Do not edit. Reinstall with: npx -y cc-safety-net install --amp",kt="cc-safety-net",Et="cc-safety-net/index.ts";import{spawn as dv}from"node:child_process";var ws=(I,V)=>{let X=Wn([...I],process.env);return new Promise((ee)=>{let ne=dv(X.cmd,X.args,{cwd:V,stdio:["ignore","pipe","pipe"]}),te=hi(ne),le=!1,de=setTimeout(()=>{le=!0,ne.kill()},120000);ne.on("error",(be)=>{clearTimeout(de),ee({status:null,errorCode:be.code,stdout:te.stdout,stderr:[be.message,te.stderr].filter(Boolean).join(`
|
|
238
|
+
`)})}),ne.on("close",(be)=>{clearTimeout(de),ee({status:le?null:be,errorCode:le?"ETIMEDOUT":void 0,stdout:te.stdout,stderr:te.stderr})})})};var nr="cc-safety-net.ts",ks=wn("amp",Et);function vv(I){return wn(I.home,".config","amp","plugins","cc-safety-net.ts")}function bv(){let I=hv(yv(import.meta.url)),V=wn(I,ks),X=wn(I,"..",ks),ee=wn(I,"..","..","..","dist",ks);return[V,X,ee]}function wv(I=bv()){let V=I.find((X)=>Pd(X)&&uv(X).isFile());if(!V)throw Error("Packaged Amp plugin artifact not found. Reinstall cc-safety-net and try again.");return V}function Sd(I){try{return JSON.parse(I)}catch{return}}function Po(I){return I.subarray(0,Buffer.byteLength(bs)).toString("utf-8")===bs}async function Cr(I,V,X){let ee=await I(V,X);if(ee.status===0)return ee;throw Error([`Failed to run ${V.join(" ")}${ee.status===null?"":` (exit ${ee.status})`}.`,[ee.stdout,ee.stderr].filter(Boolean).join(`
|
|
239
239
|
`).trim()].filter(Boolean).join(`
|
|
240
240
|
`))}async function Rd(I){let V=await I(["amp","plugins","repositories","--json"]);if(V.status===null)throw Error(`${V.errorCode==="ENOENT"?'Amp CLI not found. Install the amp CLI, sign in with "amp login", and rerun install --amp.':`amp plugins repositories --json did not finish (${V.errorCode??"terminated"}). Check that the amp CLI responds and rerun install --amp.`}
|
|
241
241
|
${V.stderr}`.trim());if(V.status!==0)throw Error(`Failed to run amp plugins repositories --json (exit ${V.status}). Sign in with "amp login" and rerun install --amp.
|
|
242
242
|
${[V.stdout,V.stderr].filter(Boolean).join(`
|
|
243
243
|
`)}`.trim());let X=Sd(V.stdout),ee=(Array.isArray(X)?X:[]).filter((ne)=>n(ne,"scope")==="user"&&n(ne,"exists")===!0&&n(ne,"viewerCanWrite")===!0).map((ne)=>n(ne,"cloneRef")).find((ne)=>typeof ne==="string"&&ne.length>0);if(!ee)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 ee}async function Ed(I,V,X){let ee=fv(wn(V.tmpdir,"cc-safety-net-amp-"));try{return await Cr(I,["amp","clone","user-plugins",ee]),await X(ee)}finally{xo(ee,{recursive:!0,force:!0})}}function Cs(I){return`rerun ${I==="overwrite"?"install":"uninstall"} --amp`}function Td(I,V,X){let ee=wn(I,V),ne=u(ee);if(!ne)return;if(ne.isSymbolicLink()||!ne.isFile())throw Error(`Refusing to ${X} ${V} in your Amp personal plugins repository: not a regular file. Remove it there and ${Cs(X)}.`);let te=tr(ee);if(Po(te))return te;throw Error(`Refusing to ${X} unmanaged file ${V} in your Amp personal plugins repository. Remove it there and ${Cs(X)}.`)}function Ad(I,V){let X=wn(I,kt),ee=u(X);if(!ee)return;if(ee.isSymbolicLink()||!ee.isDirectory())throw Error(`Refusing to ${V} ${kt} in your Amp personal plugins repository: not a regular directory. Remove it there and ${Cs(V)}.`);return Td(I,Et,V)}function kv(I){let V=wn(I,nr),X=u(V);if(!X||X.isSymbolicLink()||!X.isFile())return;let ee=tr(V);return Po(ee)?ee:void 0}async function _d(I,V,X,ee){if(await Cr(I,X,V),(await Cr(I,["git","status","--porcelain"],V)).stdout.trim()==="")return!1;return await Cr(I,["git","-c","commit.gpgsign=false","-c","user.name=cc-safety-net","-c","user.email=cc-safety-net@localhost","commit","-m",ee],V),await Cr(I,["git","push","origin","HEAD"],V),!0}function Co(I,V){Cv(I,V),xv(I,V)}function Id(I,V){if(V==="keep")return;throw Error(`Local Amp plugin ${I} is not a managed copy and masks the personal plugin. Remove it and rerun install --amp.`)}function Cv(I,V){let X=vv(I),ee=u(X);if(!ee)return;if(!ee.isSymbolicLink()&&ee.isFile()&&Po(tr(X))){xo(X);return}Id(X,V)}function xv(I,V){let X=wn(I.home,".config","amp","plugins",kt),ee=u(X);if(!ee)return;if(!ee.isSymbolicLink()&&ee.isDirectory()&&Pv(X)){xo(X,{recursive:!0});return}Id(X,V)}function Pv(I){let V=gv(Et);if(mv(I).join("\x00")!==V)return!1;let X=wn(I,V),ee=u(X);return!!ee&&!ee.isSymbolicLink()&&ee.isFile()&&Po(tr(X))}function Sv(I){let V=p(I);if(!Pd(V))return"";let X=Sd(tr(V,"utf-8"));if(!X||typeof X!=="object"||Array.isArray(X))return"";return`;globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = ${JSON.stringify(_(X,I.home))};
|
|
244
|
-
`}async function Od(I,V=wv(),X=ws){let ee=Buffer.concat([tr(V),Buffer.from(Sv(I),"utf-8")]),ne=await Rd(X);return Ed(X,I,async(te)=>{let le=`${ne}/${kt}`,de=Ad(te,"overwrite"),
|
|
245
|
-
`)}function Fd(I){let V=lr(I.home);if(Rv(Tv(V),{recursive:!0}),!Dd(V))return So(V,{[Tt]:Ro()}),{path:V,alreadyInstalled:!1};let X=Nd(V);if(Av(X))return{path:V,alreadyInstalled:!0};if(_v(X))return So(V,X),{path:V,alreadyInstalled:!1};return Iv(X),So(V,X),{path:V,alreadyInstalled:!1}}function Hd(I){let V=lr(I.home);if(!Dd(V))return{path:V,alreadyInstalled:!1};let X=Nd(V);if(!Ov(X))return{path:V,alreadyInstalled:!1};return So(V,X),{path:V,alreadyInstalled:!0}}import{existsSync as Rs,readlinkSync as Nv}from"node:fs";import{join as Gn}from"node:path";import{spawn as $v}from"node:child_process";var _n=xn.map((I)=>({target:I.id,flag:I.flag,label:cn(I.id),probeCommand:I.probeCommand}));function Ps(I){let V=new Set(I);return _n.map((X)=>X.target).filter((X)=>V.has(X))}async function Md(I,V){for(let X of I)await V(X)}var Dv=5000;function xr(I,V=Dv){return new Promise((X)=>{let ee=Wn([...I],process.env),ne=$v(ee.cmd,ee.args,{env:process.env,stdio:"ignore"}),te=!1,le=(
|
|
244
|
+
`}async function Od(I,V=wv(),X=ws){let ee=Buffer.concat([tr(V),Buffer.from(Sv(I),"utf-8")]),ne=await Rd(X);return Ed(X,I,async(te)=>{let le=`${ne}/${kt}`,de=Ad(te,"overwrite"),be=Td(te,nr,"overwrite");if(de?.equals(ee)&&!be)return Co(I,"fail"),{path:le,alreadyInstalled:!0};if(pv(wn(te,kt),{recursive:!0}),an(wn(te,Et),ee),be)xo(wn(te,nr));let Se=await _d(X,te,["git","add","--",Et,...be?[nr]:[]],`chore: update cc-safety-net plugin to v${un()}`);return Co(I,"fail"),{path:le,alreadyInstalled:!Se}})}async function $d(I,V=ws){let X=await Rd(V);return Ed(V,I,async(ee)=>{let ne=Ad(ee,"remove"),te=kv(ee),le=`${X}/${te&&!ne?nr:kt}`;if(!ne&&!te)return Co(I,"keep"),{path:le,alreadyInstalled:!1};return await _d(V,ee,["git","rm","--",...ne?[Et]:[],...te?[nr]:[]],`chore: remove cc-safety-net plugin v${un()}`),Co(I,"keep"),{path:le,alreadyInstalled:!0}})}import{existsSync as Dd,mkdirSync as Rv,readFileSync as Ev}from"node:fs";import{dirname as Tv}from"node:path";var xs=bn["antigravity-cli"],Tt="cc-safety-net";function _t(I){return Boolean(I)&&typeof I==="object"&&!Array.isArray(I)}function Ro(){return{PreToolUse:[{hooks:[{type:"command",command:xs,timeout:30}]}]}}function Nd(I){try{let V=JSON.parse(Ev(I,"utf-8"));if(!V||typeof V!=="object"||Array.isArray(V))throw Error("Antigravity hooks config must be a JSON object");return V}catch(V){if(V instanceof SyntaxError)throw Error(`Failed to parse Antigravity hooks config ${I}: ${V.message}`);throw V}}function Ld(I){let V=I[Tt];if(V===void 0){let ee=Ro();return I[Tt]=ee,{definition:ee,preToolUse:ee.PreToolUse??[]}}if(!_t(V))throw Error(`Antigravity hooks config entry "${Tt}" must be an object`);let X=Array.isArray(V.PreToolUse)?V.PreToolUse:[];return V.PreToolUse=X,{definition:V,preToolUse:X}}function jd(I){if(!Array.isArray(I.PreToolUse))return!1;return I.PreToolUse.some((V)=>_t(V)&&Array.isArray(V.hooks)&&V.hooks.some((X)=>_t(X)&&X.command===xs))}function Av(I){return Object.values(I).some((V)=>_t(V)&&V.enabled!==!1&&jd(V))}function _v(I){if(I[Tt]===void 0)return!1;let V=Ld(I);if(V.definition.enabled!==!1||!jd(V.definition))return!1;return V.definition.enabled=!0,!0}function Iv(I){if(I[Tt]===void 0){I[Tt]=Ro();return}let V=Ld(I);V.definition.enabled=!0,V.preToolUse.push(Ro().PreToolUse?.[0]??{hooks:[]})}function Ov(I){let V=!1;for(let X of Object.values(I)){if(!_t(X)||!Array.isArray(X.PreToolUse))continue;X.PreToolUse=X.PreToolUse.flatMap((ee)=>{if(!_t(ee)||!Array.isArray(ee.hooks))return[ee];let ne=ee.hooks.filter((te)=>!_t(te)||te.command!==xs);if(ne.length!==ee.hooks.length)V=!0;return ne.length===0?[]:[{...ee,hooks:ne}]})}return V}function So(I,V){an(I,`${JSON.stringify(V,null,2)}
|
|
245
|
+
`)}function Fd(I){let V=lr(I.home);if(Rv(Tv(V),{recursive:!0}),!Dd(V))return So(V,{[Tt]:Ro()}),{path:V,alreadyInstalled:!1};let X=Nd(V);if(Av(X))return{path:V,alreadyInstalled:!0};if(_v(X))return So(V,X),{path:V,alreadyInstalled:!1};return Iv(X),So(V,X),{path:V,alreadyInstalled:!1}}function Hd(I){let V=lr(I.home);if(!Dd(V))return{path:V,alreadyInstalled:!1};let X=Nd(V);if(!Ov(X))return{path:V,alreadyInstalled:!1};return So(V,X),{path:V,alreadyInstalled:!0}}import{existsSync as Rs,readlinkSync as Nv}from"node:fs";import{join as Gn}from"node:path";import{spawn as $v}from"node:child_process";var _n=xn.map((I)=>({target:I.id,flag:I.flag,label:cn(I.id),probeCommand:I.probeCommand}));function Ps(I){let V=new Set(I);return _n.map((X)=>X.target).filter((X)=>V.has(X))}async function Md(I,V){for(let X of I)await V(X)}var Dv=5000;function xr(I,V=Dv){return new Promise((X)=>{let ee=Wn([...I],process.env),ne=$v(ee.cmd,ee.args,{env:process.env,stdio:"ignore"}),te=!1,le=(be)=>{if(te)return;te=!0,clearTimeout(de),X(be)},de=setTimeout(()=>{ne.kill(),le(!1)},V);ne.on("error",()=>le(!1)),ne.on("close",(be)=>le(be===0))})}function Ud(I=xr,V={}){let X=new Set(V.configuredTargets??[]);return Promise.all(_n.map(async(ee)=>({target:ee.target,flag:ee.flag,label:ee.label,...Gd(V.action,await I(ee.probeCommand)||ee.target==="cursor"&&await I(aa),X.has(ee.target))})))}function Bd(I,V){let X=new Set(V.configuredTargets??[]);return I.map((ee)=>({...ee,...Gd(V.action,ee.available,X.has(ee.target))}))}function Gd(I,V,X){if(I==="uninstall")return X?{available:!0}:{available:!1,unavailableReason:"not installed"};if(I==="install"&&X)return{available:!1,unavailableReason:"already installed"};if(!V)return{available:!1,unavailableReason:"CLI not installed"};return{available:!0}}var qn="cc-safety-net",Jd=["npx","-y","@deepseek-ai/dsh"],qd="DeepSeek Harness",Vd=["@deepseek-ai","dsh-desktop"],zd="Quit DeepSeek Harness Desktop, then run this command again: Desktop plugins can only change while it is closed.",Ss=(I)=>`DeepSeek Harness Desktop is not in its default location, so ${I} ${qn} from its Plugins page.`,Wd=(I,V)=>Rs(Gn(De(I),V,"package.json"));function Es(I,V){let X=V.platform??process.platform,ee=Wd(I,"desktop"),ne=X==="darwin"?[Gn(I.home,"Applications"),V.systemApplications??"/Applications"].map((te)=>Gn(te,`${qd}.app`,"Contents","Resources","runtime","cli","bin","dsh")):X==="win32"?[Gn(I.env.get("LOCALAPPDATA")||Gn(I.home,"AppData","Local"),"Programs",qd,"resources","runtime","cli","bin","dsh.cmd")]:[];return{profile:ee,cli:ee?ne.find((te)=>Rs(te)):void 0}}function Yd(I,V=process.platform){if(V==="win32")return Rs(Gn(I.env.get("APPDATA")||Gn(I.home,"AppData","Roaming"),...Vd,"lockfile"));let X=Lv(Gn(I.home,"Library","Application Support",...Vd,"SingletonLock")),ee=Number(/-(\d+)$/.exec(X??"")?.[1]);return Number.isInteger(ee)&&ee>0&&jv(ee)}function Lv(I){try{return Nv(I)}catch{return}}function jv(I){try{return process.kill(I,0),!0}catch(V){return V.code==="EPERM"}}async function Zd(I,V={}){let X=Es(I,V);if(X.cli&&Yd(I,V.platform))throw Error(zd);let ee=!X.cli||Wd(I,"web")||await(V.probe??xr)(zo),ne=[...X.cli?[{profile:"desktop",label:"Desktop",dsh:[X.cli]}]:[],...ee?[{profile:"web",label:"web",dsh:Jd}]:[]];return{commands:ne.map((te)=>[...te.dsh,"plugin","--profile",te.profile,"add",`${qn}@${un()}`]),afterInstall:async()=>{let te=new Set(lt(I).filter((de)=>de.enabled).map((de)=>de.name)),le=ne.filter((de)=>!te.has(de.profile));if(le.length>0)throw Error(`DeepSeek Harness installed ${qn} in the ${Kd(le)} but did not enable it. Enable it from the Plugins page.`)},message:[`Added ${qn} to the DeepSeek Harness ${Kd(ne)}.`,...X.profile&&!X.cli?[Ss("add")]:[]].join(`
|
|
246
246
|
`)}}function Kd(I){return`${I.map((V)=>V.label).join(" and ")} profile${I.length>1?"s":""}`}function Xd(I,V={}){let X=new Set(lt(I).map((te)=>te.name));if(!X.has("desktop")&&!X.has("web"))throw Error(`${qn} is not installed in the DeepSeek Harness web or Desktop profile`);let ee=X.has("desktop")?Es(I,V).cli:void 0,ne=X.has("desktop")&&!ee;if(ne&&!X.has("web"))throw Error(Ss("remove"));if(ee&&Yd(I,V.platform))throw Error(zd);return{commands:[...ee?[[ee,"plugin","--profile","desktop","remove",qn]]:[],...X.has("web")?[[...Jd,"plugin","--profile","web","remove",qn]]:[]],...ne?{afterUninstall:()=>{throw Error(`Removed ${qn} from the DeepSeek Harness web profile, but ${Ss("remove")}`)}}:{}}}function Qd(I,V,X={}){let ee=Es(V,X).cli!==void 0;return I.map((ne)=>ne.target==="deepseek-harness"&&ee?{...ne,available:!0,unavailableReason:void 0}:ne)}import{existsSync as Fv,readdirSync as Hv,rmSync as Mv}from"node:fs";import{join as Uv}from"node:path";function eu(I,V=process.platform,X){if(!Fv(I))return;let ee=V==="win32"?/^bunx-\d+-cc-safety-net@/:new RegExp(`^bunx-${process.getuid?.()??0}-cc-safety-net@`);Hv(I).filter((ne)=>ne!==X&&ee.test(ne)).forEach((ne)=>{Mv(Uv(I,ne),{recursive:!0,force:!0})})}import{existsSync as nu,readdirSync as Bv,rmSync as Gv}from"node:fs";import{join as rr}from"node:path";function Eo(I,V=process.platform){let X=rr(I.env.get("npm_config_cache")||(V==="win32"?rr(I.env.get("LOCALAPPDATA")||rr(I.home,"AppData","Local"),"npm-cache"):rr(I.home,".npm")),"_npx");if(!nu(X))return;Bv(X).filter((ee)=>nu(rr(X,ee,"node_modules","cc-safety-net"))).forEach((ee)=>{Gv(rr(X,ee),{recursive:!0,force:!0})})}import{existsSync as au,mkdirSync as Vv,readFileSync as lu}from"node:fs";import{dirname as Kv,join as su}from"node:path";function qv(I,V){if(I[V]!=="#")return V;let X=I.indexOf(`
|
|
247
247
|
`,V+1);return X===-1?I.length:X+1}function Ts(I,V,X){let ee=new RegExp(`^(\\s*)${V}\\s*=\\s*\\[`),ne=0;for(let te of I.split(`
|
|
248
248
|
`)){if(/^\s*\[/.test(te))return;let le=ee.exec(te);if(le){let de=ne+le[0].lastIndexOf("[");return{start:de,end:fi(I,de,{skipComment:qv,...X})}}ne+=te.length+1}return}function tu(I,V,X){let ee=I.slice(0,V.end).trimEnd(),ne=yl(I,V.end),te=ne===""?" ":`${ne} `,le=!ee.endsWith("[")&&!ee.endsWith(",");return`${ee}${le?",":""}
|
|
@@ -259,9 +259,9 @@ ${As}
|
|
|
259
259
|
`;return an(V,ne),{path:V,alreadyInstalled:!0}}var _s="safety-net@cc-marketplace",mu=new Set(["claude-code","codex","copilot-cli","gemini-cli","hermes-agent","openclaw","opencode","pi"]),gu=new Set(["antigravity-cli","cursor","devin","droid","grok-build","hermes-agent","kimi-code"]);function Is(I){return/^\s*safety-net@cc-marketplace[^a-z0-9-][^\n]*installed,/m.test(I??"")}function wu(I){return/^\s*cc-safety-net[^a-z0-9-][^\n]*installed,/m.test(I??"")}function zv(I){return/^Marketplace `cc-marketplace`\s*$/m.test(I??"")}var ku={"claude-code":{installCommands:(I)=>{let V=Yr(I,"cc-safety-net@cc-marketplace");return{commands:[...V?[["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","update","cc-safety-net@cc-marketplace"]]:[["claude","plugin","marketplace","add","kenryu42/cc-marketplace"],["claude","plugin","marketplace","update","cc-marketplace"],["claude","plugin","install","cc-safety-net@cc-marketplace"]],...ui(I).status==="disabled"?[["claude","plugin","enable","cc-safety-net@cc-marketplace"]]:[]],cleanupCommands:Yr(I,_s)?[["claude","plugin","uninstall",_s]]:[],update:V}},uninstallCommands:[["claude","plugin","uninstall","cc-safety-net@cc-marketplace"],["claude","plugin","marketplace","remove","cc-marketplace"]]},codex:{installCommands:async(I,V)=>{let X=V??await pn(["codex","plugin","list"]),ee=wu(X);return{commands:[ee||zv(X)?["codex","plugin","marketplace","upgrade","cc-marketplace"]:["codex","plugin","marketplace","add","kenryu42/cc-marketplace"],["codex","plugin","add","cc-safety-net@cc-marketplace"]],cleanupCommands:Is(X)?[["codex","plugin","remove","safety-net@cc-marketplace"]]:[],update:ee}},uninstallCommands:[["codex","plugin","remove","cc-safety-net@cc-marketplace"],["codex","plugin","marketplace","remove","cc-marketplace"]],postInstallMessage:fl},"copilot-cli":{installCommands:async()=>{let I=await pn(["copilot","plugin","list"]),V=[...Sl(I)?[["copilot","plugin","uninstall","copilot-safety-net"]]:[],...Rl(I)?[["copilot","plugin","uninstall",Cl]]:[]];if(xl(I))return{commands:[["copilot","plugin","marketplace","update","cc-marketplace"],["copilot","plugin","update",En]],cleanupCommands:V,update:!0};return{commands:[Pl(await pn(["copilot","plugin","marketplace","list"]))?["copilot","plugin","marketplace","update","cc-marketplace"]:["copilot","plugin","marketplace","add","kenryu42/cc-marketplace"],["copilot","plugin","install",En]],cleanupCommands:V}},uninstallCommands:[["copilot","plugin","uninstall","cc-safety-net@cc-marketplace"],["copilot","plugin","marketplace","remove","cc-marketplace"]]},"gemini-cli":{installCommands:(I)=>{let V=$i(I);if(V.status==="configured")return{commands:[["gemini","extensions","update","gemini-safety-net"]],update:!0};if(V.status==="disabled")return{commands:[["gemini","extensions","update","gemini-safety-net"],["gemini","extensions","enable","gemini-safety-net"]],update:!0};return{commands:[["gemini","extensions","install","https://github.com/kenryu42/gemini-safety-net","--consent"]]}},uninstallCommands:[["gemini","extensions","uninstall","gemini-safety-net"]]},openclaw:{beforeInstall:zi,installCommands:(I)=>{let V=!Ao(To(hr(I),kn));return{commands:Dc(),afterInstall:()=>Nc(V)}},uninstallCommands:[["openclaw","plugins","uninstall",dn,"--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
260
|
`)},opencode:{installCommands:Vc},pi:{installCommands:[["pi","install","npm:cc-safety-net"]],uninstallCommands:[["pi","uninstall","npm:cc-safety-net"]]},"deepseek-harness":{installCommands:(I)=>Zd(I),uninstallCommands:(I)=>Xd(I)}};function Cu(I,V=(X)=>X){try{let X=JSON.parse(V(bu(I,"utf-8")));if(!X||typeof X!=="object"||Array.isArray(X))throw Error(`Settings file ${I} must be a JSON object`);return X}catch(X){if(X instanceof SyntaxError)throw Error(`Failed to parse ${I}: ${X.message}`);throw X}}function Wv(I){let V=To(ur(I),"settings.json");if(!Ao(V))return;let X=Cu(V,gn),ee=X.enabledPlugins;if(!ee||typeof ee!=="object"||Array.isArray(ee))return;if(ee[En]!==!1)return;let ne=bu(V,"utf-8"),te=ne.replace(new RegExp(`("${En}"\\s*:\\s*)false`),"$1true");return ee[En]=!0,an(V,te!==ne?te:`${JSON.stringify(X,null,2)}
|
|
261
261
|
`),`Enabled ${En} plugin in ${V}`}function Yv(I){let V=is(I);if(!Ao(V))return;let X=Cu(V);if(!Array.isArray(X.packages))return;let ee=X.packages.find((ne)=>!!ne&&typeof ne==="object"&&!Array.isArray(ne)&&ss(ne.source)&&("extensions"in ne));if(!ee)return;return delete ee.extensions,an(V,`${JSON.stringify(X,null,2)}
|
|
262
|
-
`),`Enabled npm:cc-safety-net extensions in ${V}`}function hu(I,V){let X=fn({label:V,booleans:Object.fromEntries(_n.map((te)=>[te.target,[te.flag]]))},I),ee=X.errors[0];if(ee)throw Error(ee);let ne=_n.filter((te)=>X.flags[te.target]).map((te)=>te.target);if(ne.length!==1)throw Error(`Choose exactly one ${V} target: ${_n.map((te)=>te.flag).join(", ")}`);return ne[0]}async function xu(I,V=Gt){let[X,ee,ne]=await Promise.all([V(["amp","plugins","list"],30000),V(["codex","plugin","list"],30000),V(["copilot","--binary-version"])]);return{codexPluginListOutput:ee,hooks:Qt(I,process.cwd(),{ampPluginListOutput:X,codexPluginListOutput:ee,copilotCliVersion:ne})}}async function Zv(I,V,X=Gt){let ee=await xu(I,X);return ee.hooks.filter((ne)=>V==="install"?ne.configured:ne.detected&&ne.method!==oo||ne.inspectionStatus==="not-inspected").filter((ne)=>!Ru(ne)).filter((ne)=>ne.platform!=="codex"||!Is(ee.codexPluginListOutput)||wu(ee.codexPluginListOutput)).map((ne)=>ne.platform)}function Xv(I,V,X,ee){if(X.length>0)return{finish:async()=>[hu(X,V)]};if(!ee.selectTargets&&!vs(ee.input,ee.output))return{finish:async()=>[hu(X,V)]};let ne=ee.detectConfiguredTargets??(()=>Zv(I,V,ee.fetchVersion)),te=Promise.all([Ud(ee.probeTargets).then((le)=>Qd(le,I)),ne()]);return{ready:te,finish:async()=>{let[le,de]=await te,
|
|
262
|
+
`),`Enabled npm:cc-safety-net extensions in ${V}`}function hu(I,V){let X=fn({label:V,booleans:Object.fromEntries(_n.map((te)=>[te.target,[te.flag]]))},I),ee=X.errors[0];if(ee)throw Error(ee);let ne=_n.filter((te)=>X.flags[te.target]).map((te)=>te.target);if(ne.length!==1)throw Error(`Choose exactly one ${V} target: ${_n.map((te)=>te.flag).join(", ")}`);return ne[0]}async function xu(I,V=Gt){let[X,ee,ne]=await Promise.all([V(["amp","plugins","list"],30000),V(["codex","plugin","list"],30000),V(["copilot","--binary-version"])]);return{codexPluginListOutput:ee,hooks:Qt(I,process.cwd(),{ampPluginListOutput:X,codexPluginListOutput:ee,copilotCliVersion:ne})}}async function Zv(I,V,X=Gt){let ee=await xu(I,X);return ee.hooks.filter((ne)=>V==="install"?ne.configured:ne.detected&&ne.method!==oo||ne.inspectionStatus==="not-inspected").filter((ne)=>!Ru(ne)).filter((ne)=>ne.platform!=="codex"||!Is(ee.codexPluginListOutput)||wu(ee.codexPluginListOutput)).map((ne)=>ne.platform)}function Xv(I,V,X,ee){if(X.length>0)return{finish:async()=>[hu(X,V)]};if(!ee.selectTargets&&!vs(ee.input,ee.output))return{finish:async()=>[hu(X,V)]};let ne=ee.detectConfiguredTargets??(()=>Zv(I,V,ee.fetchVersion)),te=Promise.all([Ud(ee.probeTargets).then((le)=>Qd(le,I)),ne()]);return{ready:te,finish:async()=>{let[le,de]=await te,be=Bd(le,{action:V,configuredTargets:de}),Se=ee.selectTargets?await ee.selectTargets(V,vu(V,be)):await xd(V,vu(V,be),{input:ee.input,output:ee.output});if(Se==="update")return Se;if(!Se||Se.length===0)return null;return Ps(Se)}}}async function Qv(I,V,X=!1,ee){let ne=ku[I];ne.beforeInstall?.(V);let te=typeof ne.installCommands==="function"?await ne.installCommands(V,ee):{commands:ne.installCommands};return await yi(te.commands),await $l(te.cleanupCommands??[]),await te.afterInstall?.(),[`${te.update||X?"Updated":"Installed"} ${cn(I)} integration`,te.message??ne.postInstallMessage].filter(Boolean).join(`
|
|
263
263
|
`)}async function eb(I,V){let X=ku[I];if(!X.uninstallCommands)throw Error(`${cn(I)} uninstall is not supported`);let ee=typeof X.uninstallCommands==="function"?X.uninstallCommands(V):{commands:X.uninstallCommands};return await yi(ee.commands),ee.afterUninstall?.(),`Uninstalled ${cn(I)} integration`}function nb(I){let V=zc(I);return V.alreadyInstalled?`Uninstalled OpenCode plugin from ${V.path}`:`OpenCode plugin not installed in ${V.path}`}var Pu={"antigravity-cli":{install:Fd,uninstall:Hd},cursor:{install:Hl,uninstall:Ml},devin:{install:Jl,uninstall:zl},droid:{install:nc,uninstall:tc},"grok-build":{install:dc,uninstall:uc},"kimi-code":{install:pu,uninstall:fu}};function tb(I,V,X,ee=!1){if(I==="install"&&!ee)Eo(X);let ne=Pu[V][I](X),te=cn(V),le=I!=="install"?"Uninstalled":ee?"Updated":"Installed";return I==="install"&&ne.alreadyInstalled?ee?`${te} hook up to date in ${ne.path}`:`${te} hook already installed in ${ne.path}`:I==="uninstall"&&!ne.alreadyInstalled?`${te} hook not installed in ${ne.path}`:`${le} ${te} hook ${I==="install"?"in":"from"} ${ne.path}`}var Su={amp:{install:Od,uninstall:$d,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:vc,uninstall:bc,afterInstall:async(I)=>{let V=Gi(I);return await pn(["hermes","plugins","enable",Cn,"--no-allow-tool-override"]),!V},beforeUninstall:async(I)=>{Bi(I);try{await pn(["hermes","plugins","disable",Cn])}catch(V){console.warn(`${V instanceof Error?V.message:String(V)}
|
|
264
|
-
Removing the plugin files anyway; ${Cn} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function rb(I,V,X,ee=!1){let ne=Su[V];if(I==="uninstall")await ne.beforeUninstall?.(X);let te=I==="install"?await ne.install(X):await ne.uninstall(X),le=I==="install"&&await ne.afterInstall?.(X),de=cn(V),
|
|
264
|
+
Removing the plugin files anyway; ${Cn} may still be listed in the Hermes config.`)}},restartNote:"Restart Hermes to apply the change."}};async function rb(I,V,X,ee=!1){let ne=Su[V];if(I==="uninstall")await ne.beforeUninstall?.(X);let te=I==="install"?await ne.install(X):await ne.uninstall(X),le=I==="install"&&await ne.afterInstall?.(X),de=cn(V),be=!le&&(I==="install"&&te.alreadyInstalled||I==="uninstall"&&!te.alreadyInstalled);return[be?I==="install"?`${de} plugin ${ee?"up to date":"already installed"} at ${te.path}`:`${de} plugin not installed at ${te.path}`:`${I!=="install"?"Uninstalled":ee?"Updated":"Installed"} ${de} plugin ${I==="install"?"at":"from"} ${te.path}`,be?void 0:ne.restartNote].filter(Boolean).join(`
|
|
265
265
|
`)}var ob={"copilot-cli":{afterInstall:Wv},cursor:{afterUninstall:Nl},"hermes-agent":{beforeInstall:(I,V)=>{if(!V)Eo(I)}},openclaw:{beforeUninstall:zi},pi:{afterInstall:Yv}};function ib(I){return I in Pu}function sb(I){return I in Su}var yu=["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
266
|
`);function Ru(I){return I.platform==="kimi-code"&&I.method===go}function Eu(I){return ho({environment:I,cwd:process.cwd()}).method==="hook config"}function ab(I){if(!Eu(I))return yu;return[yu,"",qe.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(`
|
|
267
267
|
`))].join(`
|
|
@@ -269,35 +269,35 @@ Removing the plugin files anyway; ${Cn} may still be listed in the Hermes config
|
|
|
269
269
|
`);if(sb(V))return rb(I,V,X,ee);if(I==="uninstall")return V==="opencode"?nb(X):eb(V,X);return[await Qv(V,X,ee,ne),await te?.afterInstall?.(X)].filter(Boolean).join(`
|
|
270
270
|
`)}function cb(I){let V=fn({label:"update"},I).errors[0];if(V)throw Error(V)}async function db(I,V=Gt){let X=await xu(I,V),ee=To(ur(I),"installed-plugins");return{targets:Ps([...X.hooks.filter((te)=>te.platform!=="copilot-cli"&&te.detected&&te.method!==oo&&te.method!==xi).map((te)=>te.platform),...[Zr,kl,wl].flatMap((te)=>Ao(To(ee,...te))?["copilot-cli"]:[]),...Yr(I,_s)?["claude-code"]:[],...Is(X.codexPluginListOutput)?["codex"]:[]]),codexPluginListOutput:X.codexPluginListOutput,kimiPlugin:X.hooks.some(Ru)}}async function ub(I){let V=c(),X=I.output??process.stdout,ee=(I.scriptPath??process.argv[1]??"").split(/[\\/]/),ne=ee.find((Ne)=>/^bunx-\d+-/.test(Ne)),te=ne!==void 0||ee.includes("_npx")?null:(I.checkLatestVersion??Hn)(),le=async()=>{let Ne=te&&await te;if(Ne?.updateAvailable)X.write(`
|
|
271
271
|
Update available: cc-safety-net ${Ne.currentVersion} → ${Ne.latestVersion}. Update this CLI with your package manager, e.g. \`npm i -g cc-safety-net@latest\` for a global install.
|
|
272
|
-
`)},de=db(V,I.fetchVersion??Gt).then(async(Ne)=>{let Fe=new Set(Ne.targets);return{targets:Ne.targets,codexPluginListOutput:Ne.codexPluginListOutput,kimiPlugin:Ne.kimiPlugin,available:new Map(await Promise.all(_n.filter((Be)=>Fe.has(Be.target)&&mu.has(Be.target)).map(async(Be)=>[Be.target,await xr(Be.probeCommand)])))}}),
|
|
272
|
+
`)},de=db(V,I.fetchVersion??Gt).then(async(Ne)=>{let Fe=new Set(Ne.targets);return{targets:Ne.targets,codexPluginListOutput:Ne.codexPluginListOutput,kimiPlugin:Ne.kimiPlugin,available:new Map(await Promise.all(_n.filter((Be)=>Fe.has(Be.target)&&mu.has(Be.target)).map(async(Be)=>[Be.target,await xr(Be.probeCommand)])))}}),be=await ar(I.showBanner??!0,()=>({ready:de,finish:()=>de}),()=>sr({input:I.input??process.stdin,output:X}),{loadingMessage:"Checking installed integrations…",output:X}),Se=await Promise.resolve().then(()=>(eu(V.tmpdir,process.platform,ne),null)).catch((Ne)=>Sr(Ne));if(be.targets.length===0){if(X.write("No installed integrations found. Run `cc-safety-net install` to set one up.\n"),Se!==null)console.error(Se);return await le(),Se===null?0:1}let Ie=be.targets.some((Ne)=>gu.has(Ne))?await Promise.resolve().then(()=>(Eo(V),null)).catch((Ne)=>Sr(Ne)):null,$e=await Gr(Promise.all(be.targets.map((Ne)=>{if(Ne==="kimi-code"&&be.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(mu.has(Ne)&&!be.available.get(Ne))return Promise.resolve({message:`${cn(Ne)} not found; skipped`,failed:!1});if(Ie!==null&&gu.has(Ne))return Promise.resolve({message:Ie,failed:!0});return Tu("install",Ne,V,!0,be.codexPluginListOutput).then((Fe)=>({message:Fe,failed:!1}),(Fe)=>({message:Sr(Fe),failed:!0}))})),{loadingMessage:`Updating ${be.targets.length} integration${be.targets.length===1?"":"s"}…`,output:X}),Le=Se===null?$e:[...$e,{message:Se,failed:!0}];return Le.forEach((Ne)=>Ne.failed?console.error(Ne.message):X.write(`${Ne.message}
|
|
273
273
|
`)),await le(),Le.some((Ne)=>Ne.failed)?1:0}function Os(I,V={}){return Promise.resolve().then(()=>cb(I)).then(()=>ub(V)).catch((X)=>(console.error(Sr(X)),1))}async function Rr(I,V,X={}){try{let ee=c(),ne=await ar(!0,()=>Xv(ee,I,V,X),()=>sr({input:X.input??process.stdin,output:X.output??process.stdout}),{loadingMessage:I==="install"?"Checking available integrations…":"Checking installed integrations…",output:X.output??process.stdout});if(!ne)return(X.output??process.stdout).write(`Cancelled: nothing was ${I}ed.
|
|
274
|
-
`),0;if(ne==="update")return(X.runUpdate??(()=>Os([],{fetchVersion:X.fetchVersion,input:X.input,output:X.output,showBanner:!1})))();let te=X.output??process.stdout;return await Md(ne,async(le)=>{if(le==="kimi-code"&&I==="install"){let
|
|
275
|
-
`);return}if(
|
|
274
|
+
`),0;if(ne==="update")return(X.runUpdate??(()=>Os([],{fetchVersion:X.fetchVersion,input:X.input,output:X.output,showBanner:!1})))();let te=X.output??process.stdout;return await Md(ne,async(le)=>{if(le==="kimi-code"&&I==="install"){let be=await lb(X,ee);if(be===null){te.write(`Cancelled: Kimi Code integration was not installed.
|
|
275
|
+
`);return}if(be==="plugin"){te.write(`${ab(ee)}
|
|
276
276
|
`);return}}let de=await Gr(Tu(I,le,ee),{loadingMessage:`${I==="install"?"Installing":"Uninstalling"} ${cn(le)} integration…`,output:te});te.write(`${de}
|
|
277
277
|
`)}),0}catch(ee){return console.error(Sr(ee)),1}}function Sr(I){let V=I instanceof Error?I.message:String(I),X=typeof I==="object"&&I!==null&&"code"in I?I.code:null;if(X==="EACCES"||X==="EPERM")return`${V}
|
|
278
278
|
Check file permissions for the target config file and parent directory.`;if(X==="ENOENT")return`${V}
|
|
279
279
|
Check that the target config path and parent directory exist.`;if(X==="ENOTDIR")return`${V}
|
|
280
|
-
Check that every parent path component is a directory.`;return V}import{mkdirSync as yb}from"node:fs";import{dirname as vb}from"node:path";import{createInterface as bb}from"node:readline";import{existsSync as _u,readFileSync as pb}from"node:fs";function It(I,V){let X=wt(I,V);return{policy:X.policy,errors:he(
|
|
281
|
-
`,384),mb(ee,384),{path:ee,policy:te,errors:[]}}function Du(I,V){let X=It(V,I.home);if(X.errors.length>0)return{errors:X.errors};return{preview:Qe(X.policy,I.env),errors:[]}}function Nu(I,V={}){let X=p(I,V);if(!Iu(X))return Ln(I,ae,V);let ee=Ou(X,"utf-8");if(!ee.trim())return Ln(I,ae,V);try{return Ln(I,_(JSON.parse(ee),I.home),V)}catch{return Ln(I,ae,V)}}var Lu=new Set(["check","apply"]),ju="(unset)";async function Hu(I,V,X={}){let ee=fn({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},V),ne=ee.positionals[0],te=[...ee.errors,...ne&&!Lu.has(ne)?[`Unknown policy subcommand: ${ne}`]:[],...ne&&Lu.has(ne)&&!ee.positionals[1]?[`policy ${ne} requires a file`]:[],...ee.positionals.slice(2).map((Be)=>`Unexpected policy argument: ${Be}`)];if(te.length>0){for(let Be of te)console.error(Be);return 1}let le=ee.positionals[1];if(!ne||!le)return er($r,console.error),1;let de=X.cwd??process.cwd(),ve=ee.flags.global?p(I):S(de);if(!ee.flags.global&&L(I,{cwd:de}))return console.error(`${ve} is the user policy, not a project policy; use --global for the user scope, or run from a project directory`),1;let Se=$t(le),Ie=[...Se.errors,...Er(Se.value,I.home).map((Be)=>`${le}: ${Be}`),...!ee.flags.global&&Cb(Se.value)&&Se.value.audit!==void 0?[`${le}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(Ie.length>0){for(let Be of Ie)console.error(Be);return 1}let $e=_(Se.value,I.home);if(console.log(`Scope: ${ee.flags.global?"user":"project"} (${ve})`),console.log(`Proposal: ${le}`),ee.flags.global)Fu(_($t(ve).value,I.home),$e,!0);if(!ee.flags.global){let Be=Tr(I).baseline;console.log("Effective policy (user + project merged):"),Fu(se(Be,be($t(ve).value,I.home).policy).policy,se(Be,be(Se.value,I.home).policy).policy,!1)}if(ne==="check")return 0;let Le=X.input??process.stdin,Ne=X.output??process.stdout;if(!Le.isTTY||!Ne.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${le}${ee.flags.global?" --global":""}`),1;if(!await wb(`Apply this policy to ${ve}? [y/N] `,Le,Ne))return console.log("Cancelled; nothing was written."),0;return kb(I,ve,Se.value,$e,ee.flags.global),console.log(`Policy applied: ${ve}`),0}function wb(I,V,X){let ee=bb({input:V,output:X,terminal:!1});return new Promise((ne)=>{ee.once("close",()=>ne(!1)),ee.question(I,(te)=>{ne(/^y(es)?$/i.test(te.trim())),ee.close()})})}function kb(I,V,X,ee,ne){if(ne){Ln(I,ee);return}yb(vb(V),{recursive:!0}),yn(V,Io(X,ee))}function Fu(I,V,X){let ee=_o(I,V,X);if(ee.length===0){console.log("No changes.");return}console.log(`Changes (${ee.length}):`);for(let ne of ee)console.log(` ${ne.field}: ${ne.before??ju} -> ${ne.after??ju}`)}function Cb(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}import{join as Lw}from"node:path";var Mu="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- `caffeinate`, `exec`, `nice`, `nohup`, `setsid`, `stdbuf`, `time`, and `timeout` are built-in transparent wrappers and need no configuration. Configure only other wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n- `command_tools`: Optional array of shell tools that a plugin adds to an agent and that CC Safety Net does not know. Each entry is a tool name such as `\"ops_bash\"`, or `{ \"name\": \"ops_run_background\", \"cwd\": \"cwd\" }` when the tool takes its working directory in a named argument (otherwise `workdir`, `cwd`, or `working_directory` is read). A call to a declared tool with a non-empty string `command` is analyzed like a built-in shell command. User and project lists merge; the user entry wins a name declared in both.\n- Built-in shell and file tools are already analyzed and cannot be declared; `rule verify` reports one declared by hand.\n- Use `cc-safety-net rule tool add ops_bash ops_run_background` to declare tools in the user config, or add `--project` for the project config.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Oo(I,V){if(!I.ok){Ku(I);return}Gu(I,V)}function Bu(I,V,X){if(I.ok)console.log(X);if(!I.add){Oo(I,`Added rulebook source: ${V}`);return}if(!I.ok){Ku(I);return}if(I.add.added.length>0)console.log(`Added ${I.add.added.length} ${I.add.added.length===1?"rulebook":"rulebooks"} from ${I.add.source} at ${I.add.ref}:`),I.add.added.forEach((ee)=>{console.log(` - ${ee}`)});if(I.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${I.add.source} at ${I.add.ref}: ${I.add.alreadyConfigured.join(", ")}`);if(I.add.commits.length>0)console.log(`Vendored at ${I.add.commits.map((ee)=>ee.slice(0,7)).join(", ")}.`);Gu(I,"Rule config updated.")}function Gu(I,V){for(let X of I.changes??[])console.log(X);console.log(V),console.log(""),xb(I.entries)}function xb(I){if(I.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${I.length}):`);for(let V of I)console.log(` - ${V.name} ${V.version} (${Pb(V.ruleCount)})`),console.log(` Source: ${V.spec}`)}function Pb(I){return`${I} ${I===1?"rule":"rules"}`}function qu(I){Vn("Active sources",I.rulebooks,(V)=>[`[${V.source}] ${V.name} ${V.version}`,` Source: ${V.spec}`]),Vn("Active rules",I.rules,(V)=>[`[${Rb(I,V.name)}] ${V.name}`,...Sb(V),` Reason: ${V.reason}`]),Vn("Disabled rules",Uu(I,"off"),(V)=>[V.key]),Vn("Reason overrides",Uu(I,"reason"),(V)=>[V.key,` Reason: ${V.value.reason}`]),Vn("Transparent wrappers",I.transparent_wrappers,(V)=>[V]),Vn("Issues",I.errors,(V)=>[V]),Vn("Warnings",I.warnings,(V)=>[V])}function Vu(I){Vn("Command tools",I,(V)=>typeof V.tool==="string"?[`[${V.scope}] ${V.tool}`]:[`[${V.scope}] ${V.tool.name}`,...V.tool.cwd===void 0?[]:[` Cwd argument: ${V.tool.cwd}`]])}function Vn(I,V,X){if(V.length===0){console.log(`${I}: (none)`);return}console.log(`${I} (${V.length}):`);for(let ee of V){let[ne,...te]=X(ee);console.log(` - ${ne}`);for(let le of te)console.log(` ${le}`)}}function Sb(I){if(!I.match)return[` Command: ${I.subcommand?`${I.command} ${I.subcommand}`:I.command}`,` Block args: ${I.block_args.join(", ")}`];return[` Command: ${[I.command,...I.match.command_path].join(" ")}`,...I.match.any_args?[` Any args: ${I.match.any_args.join(", ")}`]:[],...I.match.exclude_args?[` Exclude args: ${I.match.exclude_args.join(", ")}`]:[]]}function Rb(I,V){return I.rulebooks.find((X)=>X.rules.includes(V))?.source??"project"}function Uu(I,V){return Object.entries({...I.userConfig?.overrides,...I.projectConfig?.overrides}).filter((X)=>{if(V==="off")return X[1]==="off";return!!X[1]&&typeof X[1]==="object"}).map(([X,ee])=>({key:X,value:ee}))}function Ku(I){for(let V of I.errors)console.error(V)}import{dirname as gp,join as Mo}from"node:path";import{join as Fs,resolve as Fb}from"node:path";function Ar(I){let V=f(I);if(V.errors.length>0)return{ok:!1,result:{ok:!1,errors:V.errors,entries:[]}};return{ok:!0,config:V.config??ge}}function Ju(I){yn(I,ge)}function zu(I){yn(I,{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 Lo}from"node:path";var Eb="custom.";function $o(I){if(I.rulebook_version!==2)return[];let V=I.rules.map((X)=>({name:X.name,command:X.command,block_args:[],match:X.match,reason:X.reason,intent:X.intent}));return(I.tests??[]).flatMap((X,ee)=>{let ne=Ns(C(X.command));if(ne.length===0)return[`tests[${ee}]: could not parse fixture command: ${X.command}`];let te=ne.reduce((le,de)=>le??F(de,V)?.id.slice(Eb.length),void 0);if(X.expect==="blocked"){if(te===X.rule)return[];let le=te?`"${te}" matched first`:"no rule matched";return[`tests[${ee}]: expected "${X.rule}" to block "${X.command}" but ${le}`]}return te?[`tests[${ee}]: expected "${X.command}" to be allowed but "${te}" matched`]:[]})}function Ns(I){return I.nodes.flatMap((V)=>{if(V.kind==="group"||V.kind==="function")return Ns(V.body);if(V.kind!=="command")return[];let X=Ae(ce(V.dialect,V.words)).words.map(t);return[...X.length>0?[X]:[],...V.nested.flatMap((ee)=>Ns(ee))]})}var Do=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function No(I={}){return{requests:0,responseBytes:0,maxRequests:I.maxRequests??Do.maxRequests,maxResponseBytes:I.maxResponseBytes??Do.maxResponseBytes}}function jn(I){return{controller:new AbortController,budget:No(),resolveUrl:I}}function Wu(I){return I instanceof Error&&I.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Yu(I){if(I.requests>=I.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");I.requests++}function Zu(I,V){if(V>I.maxResponseBytes-I.responseBytes)throw I.responseBytes+=V,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");I.responseBytes+=V}var ep=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Xu(I,V,X=R(Lo(Lo(V)),"rules policy"),ee=jn()){if(T(I))return Ib(I,ee);return _b(I,V,X)}async function np(I,V,X,ee,ne,te){if(!T(I))return Xu(I,V,X,ee);let le=ne?null:Tb(I,V,X);if(le)return le;if(!ne&&!te)throw Error(`${I} is not vendored; run rule update ${I} to vendor it`);return Xu(I,V,X,ee)}function Tb(I,V,X=R(Lo(Lo(V)),"rules policy")){let ee=j(I),ne=U(V,ee.name),te=o(s(X,ne));if(te===null)return null;let le=ye(Ls(te,`Invalid rulebook ${ne}.`));if(le.name!==ee.name)throw Error(`rulebook name "${le.name}" in ${ne} must match "${ee.name}"`);return{spec:I,rulebook:le,content:te}}async function tp(I,V={}){if(!re(I))throw Error(`Invalid GitHub repository source: ${I}`);let[X,ee]=I.split("/");if(!X||!ee)throw Error(`Invalid GitHub repository source: ${I}`);if(V.ref!==void 0&&!fe(V.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${V.ref}`);let ne=V.operation??jn(),te=V.ref??await Ab(X,ee,I,ne),le=await op(X,ee,te,I,ne),de=await jo(`https://api.github.com/repos/${X}/${ee}/git/trees/${le}?recursive=1`,"tree",ne),ve=de.response;if(!ve.ok)throw Error(`Failed to inspect ${I}: GitHub tree returned ${ve.status}`);let Se=JSON.parse(de.content);if(!Array.isArray(Se?.tree))throw Error(`Failed to inspect ${I}: unexpected GitHub tree response`);let Ie=Se.tree,$e=[...new Set(Ie.flatMap((Le)=>{if(!Le||typeof Le!=="object")return[];let Ne=Le;if(Ne.type!=="blob"||typeof Ne.path!=="string")return[];let Fe=Ne.path.match(Nt);return Fe?.[1]?[Fe[1]]:[]}))].sort();if($e.length===0)throw Error(`No rulebooks found in ${I} under ${Ee}/`);return{source:I,owner:X,repo:ee,ref:te,commit:le,names:$e}}async function Ab(I,V,X,ee){let ne=await jo(`https://api.github.com/repos/${I}/${V}`,"metadata",ee),te=ne.response;if(!te.ok)throw Error(`Failed to inspect ${X}: GitHub returned ${te.status}`);let de=JSON.parse(ne.content)?.default_branch;if(typeof de!=="string"||de==="")throw Error(`Failed to inspect ${X}: missing default branch`);if(!fe(de))throw Error(`GitHub returned an invalid default branch: ${de}`);return de}function _b(I,V,X){Lt(I);let ee=U(V,I),ne=o(s(X,ee));if(ne===null)throw Error(`Rulebook source not found: ${I}`);let te=rp(Ls(ne,"Invalid local rulebook source."));if(te.name!==I)throw Error(`rulebook name "${te.name}" must match local source "${I}"`);return{spec:I,rulebook:te,content:ne}}async function Ib(I,V){let X=j(I),ee=await op(X.owner,X.repo,X.ref,I,V),ne=await jo(`https://raw.githubusercontent.com/${X.owner}/${X.repo}/${ee}/${X.path}`,"raw",V),te=ne.response;if(!te.ok)throw Error(`Failed to fetch ${I}: GitHub raw returned ${te.status}`);let le=ne.content,de=rp(Ls(le,"Invalid GitHub rulebook response."));if(de.name!==X.name)throw Error(`rulebook name "${de.name}" must match GitHub source "${X.name}"`);return{spec:I,rulebook:de,content:le}}function rp(I){let V=ye(I),X=$o(V);if(X.length>0)throw Error(X.join("; "));return V}function Ls(I,V){try{return JSON.parse(I)}catch{throw Error(V)}}async function op(I,V,X,ee,ne){let te=await jo(`https://api.github.com/repos/${I}/${V}/commits/${encodeURIComponent(X)}`,"commit",ne),le=te.response;if(!le.ok)throw Error(`Failed to resolve ${ee}: GitHub returned ${le.status}`);let de=JSON.parse(te.content);if(typeof de?.sha!=="string"||de.sha==="")throw Error(`Failed to resolve commit for ${ee}`);return de.sha}async function Ob(I,V,X={}){if(X.signal?.aborted)throw X.signal.reason;let ee=X.budget??No(),ne=new AbortController,te=()=>ne.abort(X.signal?.reason);X.signal?.addEventListener("abort",te,{once:!0});let le=!1,de=setTimeout(()=>{if(ne.signal.aborted)return;le=!0,ne.abort()},X.timeoutMs??ep.timeoutMs);try{if(X.signal?.aborted)throw X.signal.reason;Yu(ee);let ve=await fetch(I,{signal:ne.signal,redirect:"error"});if(!ve.ok)return ip(ve),{response:ve,content:""};return{response:ve,content:await $b(ve,V,ee,()=>ne.abort())}}catch(ve){if(le)throw Error("GitHub request timed out",{cause:ve});if(X.signal?.aborted)throw X.signal.reason;throw ve}finally{clearTimeout(de),X.signal?.removeEventListener("abort",te)}}function jo(I,V,X){return Ob(X.resolveUrl?.(I)??I,V,{budget:X.budget,signal:X.controller.signal})}async function $b(I,V,X=No(),ee){let ne=ep[`${V}Bytes`],te=Number(I.headers.get("content-length"));if(Number.isFinite(te)&&te>ne)throw ip(I),Error(`GitHub ${V} response exceeds ${ne} bytes`);if(!I.body)return"";let le=I.body.getReader(),de=[],ve=0;while(!0){let Se=await le.read();if(Se.done)break;try{Zu(X,Se.value.byteLength)}catch(Ie){throw ee?.(),Qu(le),Ie}if(ve+=Se.value.byteLength,ve>ne)throw ee?.(),Qu(le),Error(`GitHub ${V} response exceeds ${ne} bytes`);de.push(Buffer.from(Se.value))}return Buffer.concat(de,ve).toString("utf-8")}function ip(I){if(!I.body)return;sp(()=>I.body?.cancel())}function Qu(I){sp(()=>I.cancel())}function sp(I){try{Promise.resolve(I()).catch(()=>{})}catch{}}var Db=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function ap(I,V){let X=dp(I.rules,V);if(X.length>0)return{ok:!0,specs:X};return cp(I.rules,V)}function lp(I,V){let X=dp(I,V);if(X.length>0)return{ok:!0,specs:X};let ee=Lb(I,V);if(ee.length>0)return{ok:!0,specs:ee};let ne=jb(I,V);if(!ne.ok)return ne;if(ne.specs.length>0)return{ok:!0,specs:ne.specs};return cp(I,V)}function cp(I,V){let X=I.filter((ee)=>js(ee)?.name===V);if(X.length===1)return{ok:!0,specs:X};return Nb(V,X)}function Nb(I,V){return{ok:!1,result:{ok:!1,errors:V.length===0?[`No configured rulebook matches ${I}`]:[`Ambiguous rulebook match ${I}: ${V.join(", ")}`],entries:[]}}}function dp(I,V){return I.filter((X)=>X===V)}function Lb(I,V){let X=V.match(Db),ee=X?.[1],ne=X?.[2],te=X?.[3];if(!ee||!ne||!te||!fe(te))return[];return up(I,(le)=>le.owner===ee&&le.repo===ne&&le.ref===te)}function jb(I,V){if(!re(V))return{ok:!0,specs:[]};let[X,ee]=V.split("/"),ne=up(I,(le)=>le.owner===X&&le.repo===ee);if(new Set(ne.map((le)=>js(le)?.ref).filter((le)=>!!le)).size<2)return{ok:!0,specs:ne};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${V}. Use an explicit ref:`,` cc-safety-net rule remove ${V}#<ref>`],entries:[]}}}function js(I){try{return j(I)}catch{return null}}function up(I,V){return I.filter((X)=>{let ee=js(X);return ee?V(ee):!1})}async function Ho(I,V={}){return Hb(I,V,await Fo(I,V,jn()))}function Hb(I,V,X){if(!X.ok)return X;let ee=hn(I,V),ne=[...new Set(J(ee.configPath,ee.filesystemScope))];if(ne.length===0)return X;return{ok:!1,errors:ne,entries:X.entries}}async function Fo(I,V,X,ee={},ne=new Set,te=new Set){try{let le=hn(I,V),de=Ar(le.configTarget);if(!de.ok)return de.result;let ve=de.config,Se=V.only?ap(ve,V.only):{ok:!0,specs:ve.rules};if(!Se.ok)return Se.result;let Ie=new Set([...V.refresh?Se.specs:[],...ne]),$e=(nn)=>np(nn,le.configDir,le.filesystemScope,X,Ie.has(nn),!V.refresh||Ie.has(nn)),Le=await Wb(ve.rules,V.refresh?(nn)=>$e(nn).then((sn)=>({ok:!0,item:sn})).catch((sn)=>{if(Wu(sn))throw sn;return{ok:!1,spec:nn,message:sn instanceof Error?sn.message:String(sn)}}):async(nn)=>({ok:!0,item:await $e(nn)}),X),Ne=Le.filter((nn)=>!nn.ok),Fe=Le.filter((nn)=>nn.ok).map((nn)=>nn.item),Be=Fe.flatMap((nn)=>Mb(nn,ve.rules)),Me=Fe.flatMap((nn)=>Ub(nn,te,le)),tn=new Set([...Be,...Me].map((nn)=>nn.spec)),en=[...Ne,...Be,...Me],on=[],ln=Gb(on,()=>Fe.flatMap((nn)=>tn.has(nn.spec)||en.length>0&&te.has(nn.spec)?[]:Bb(nn,le,ee,on)));return{ok:en.length===0,errors:en.map((nn)=>`Failed to update ${nn.spec}: ${nn.message}`),entries:Fe.map(Vb),changes:ln}}catch(le){return Ir(le)}}function Mb(I,V){if(!T(I.spec))return[];let X=Xe(I.spec),ee=V.filter((ne)=>ne!==I.spec&&Xe(ne).toLowerCase()===X.toLowerCase());if(ee.length===0)return[];return[{ok:!1,spec:I.spec,message:`rulebook name "${X}" is also claimed by ${ee.join(", ")}; rename one of them`}]}function Ub(I,V,X){if(!V.has(I.spec)||!T(I.spec))return[];let ee=U(X.configDir,I.rulebook.name),ne=o(s(X.filesystemScope,ee));if(ne===null||ne===I.content)return[];return[{ok:!1,spec:I.spec,message:`${ee} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Bb(I,V,X,ee){if(!T(I.spec))return[];let ne=U(V.configDir,I.rulebook.name),te=s(V.filesystemScope,ne),le=o(te);if(le===I.content)return[];return ee?.push({target:te,previous:le}),x(te,I.content,void 0,X._testAfterPolicyRename),qb(I,le)}function Gb(I,V){try{return V()}catch(X){for(let ee of[...I].reverse()){if(ee.previous===null){q(ee.target);continue}x(ee.target,ee.previous)}throw X}}function qb(I,V){if(V===null)return[`Vendored ${I.spec} (${I.rulebook.version})`];let X=Pe(V),ee="problem"in X?null:X.rulebook,ne=new Map(ee?.rules.map((le)=>[le.name,JSON.stringify(le)])??[]),te=new Set(I.rulebook.rules.map((le)=>le.name));return[`Updated ${I.spec} (${ee?.version??"unreadable"} -> ${I.rulebook.version})`,...[...te].filter((le)=>!ne.has(le)).map((le)=>` + ${le}`),...[...ne.keys()].filter((le)=>!te.has(le)).map((le)=>` - ${le}`),...I.rulebook.rules.filter((le)=>{let de=ne.get(le.name);return de!==void 0&&de!==JSON.stringify(le)}).map((le)=>` ~ ${le.name}`)]}function Vb(I){return{spec:I.spec,name:I.rulebook.name,version:I.rulebook.version,ruleCount:I.rulebook.rules.length}}async function pp(I,V,X={}){return Kb(I,V,X,jn())}async function Kb(I,V,X,ee,ne={}){let te=null,le=!1;try{let de=hn(I,X),ve=o(de.configTarget);te={target:de.configTarget,content:ve};let Se=Ar(de.configTarget);if(!Se.ok)return Se.result;let Ie=Se.config,$e=re(V)?await tp(V,{ref:X.ref,operation:ee}):null,Le=$e?Jb($e,X.rulebooks):[],Ne=$e?Le.map((en)=>zb(Ie.rules,$e,en)??`${V}#${$e.ref}/${en}`):[V],Fe=Ne.filter((en)=>!Ie.rules.includes(en)),Be=[...Ie.rules,...Fe];if(Be.length>ke)return Yb();if(Be.length!==Ie.rules.length)le=!0,yn(de.configTarget,{...Ie,rules:Be},void 0,ne._testAfterPolicyRename);let Me=await Fo(I,X,ee,ne,new Set(Fe),new Set(Fe));if(!Me.ok)_r(de.configTarget,ve);if(!Me.ok||!$e)return Me;let tn=Le.filter((en,on)=>Fe.includes(Ne[on]??""));return{...Me,add:{source:V,ref:$e.ref,selected:Le,added:tn,alreadyConfigured:Le.filter((en)=>!tn.includes(en)),commits:Fe.length>0?[$e.commit]:[]}}}catch(de){if(le&&te)try{_r(te.target,te.content)}catch(ve){return Ir(ve)}return Ir(de)}}function Jb(I,V){let X=V?[...new Set(V)]:I.names,ee=X.filter((ne)=>!I.names.includes(ne));if(ee.length>0)throw Error(`Rulebooks not found in ${I.source} at ${I.ref}: ${ee.join(", ")}
|
|
282
|
-
Available rulebooks: ${I.names.join(", ")}`);return X}function zb(I,V,X){let ee=`${V.source}#${V.ref}/${X}`;if(I.includes(ee))return ee;let ne=`${V.source}#${V.commit}/${X}`;return I.find((te)=>te===ne)}async function Wb(I,V,X=jn()){if(I.length>ke)throw Error(Re);let ee=[],ne=0,te,le=Array.from({length:Math.min(I.length,Do.concurrency)},async()=>{while(!te){let de=ne;if(de>=I.length)return;ne++;try{ee[de]=await V(I[de],de,X.controller.signal)}catch(ve){if(!te)te={value:ve},ne=I.length,X.controller.abort(ve);return}}});if(await Promise.all(le),te)throw te.value;return ee}function Yb(){return{ok:!1,errors:[Re],entries:[]}}async function fp(I,V,X={}){try{return await Zb(I,V,X,{})}catch(ee){return Ir(ee)}}async function Zb(I,V,X,ee){let ne=hn(I,X),te=f(ne.configTarget);if(te.errors.length>0)return{ok:!1,errors:te.errors,entries:[]};if(!te.config)return{ok:!1,errors:[`No config found at ${ne.configPath}`],entries:[]};let le=lp(te.config.rules,V);if(!le.ok)return le.result;let de=X.deleteSource?Xb(ne.configDir,le.specs,ne.filesystemScope):{ok:!0,dirs:[]};if(!de.ok)return de.result;let ve=o(ne.configTarget);if(ve===null)return Ir(Error("Rules config is unavailable."));try{yn(ne.configTarget,{...te.config,rules:te.config.rules.filter(($e)=>!le.specs.includes($e))},void 0,ee._testAfterPolicyRename)}catch($e){throw _r(ne.configTarget,ve),$e}let Se=await Fo(I,X,jn(),ee);if(!Se.ok)return _r(ne.configTarget,ve),Se;let Ie=Qb(de.dirs,ee,ne.filesystemScope);if(!Ie.ok){_r(ne.configTarget,ve);let $e=await Fo(I,X,jn(),ee);if(!$e.ok)return{ok:!1,errors:[...Ie.result.errors,...$e.errors],entries:$e.entries};return Ie.result}return Se}function Xb(I,V,X){let ee=V.flatMap((de)=>m.test(de)?[]:["--delete-source can only delete local rulebook sources"]),ne=V.map((de)=>Fs(I,de)),te=ee.length>0?[]:ne.flatMap((de)=>mp(de,X)),le=[...ee,...te];return le.length>0?{ok:!1,result:{ok:!1,errors:le,entries:[]}}:{ok:!0,dirs:ne}}function mp(I,V){let X=Fb(I),ee=s(V,X),ne=we(ee);if(!ne)return[`Local rulebook source directory not found: ${I}`];let te=ne.find((le)=>le.name==="rulebook.json");if(!te)return[`Local rulebook source directory is missing rulebook.json: ${I}`];if(te.kind!=="file")throw new i(V.label);if(o(s(V,Fs(X,"rulebook.json"))),ne.length>1)return[`Local rulebook source directory contains extra files: ${I}. delete manually if you really want to remove the directory.`];return[]}function Qb(I,V,X){let ee=I.flatMap((ne)=>{try{if(!we(s(X,ne)))return[];let te=mp(ne,X);if(te.length>0)return te;return ew(ne,V,X),[]}catch(te){return[`Failed to delete local rulebook source ${ne}: ${te instanceof Error?te.message:String(te)}`]}});return ee.length>0?{ok:!1,result:{ok:!1,errors:ee,entries:[]}}:{ok:!0}}function ew(I,V,X){if(V._testDeleteLocalSourceDir){V._testDeleteLocalSourceDir(I);return}q(s(X,Fs(I,Ce))),Dt(s(X,I))}function _r(I,V){if(V===null){q(I);return}x(I,V)}function Ir(I){return{ok:!1,errors:[I instanceof Error?I.message:String(I)],entries:[]}}var nw=".safety-net.json",tw="~/.cc-safety-net/config.json";async function vp(I,V){let X=L(I,{cwd:V.cwd});if(X)console.log(`Skipped the project scope: ${D(V.cwd)} is the user rule config, not a project rule config`);return[X||await hp(I,{legacyPath:Ut(V.cwd),configPath:D(V.cwd),defaultRulebookName:"project-rules",migratedFrom:nw,cleanup:V.cleanup,syncOptions:{cwd:V.cwd}}),await hp(I,{legacyPath:Bt(I),configPath:K(I),defaultRulebookName:"user-rules",migratedFrom:tw,cleanup:V.cleanup,syncOptions:{cwd:V.cwd,global:!0}})].every((ne)=>ne)?0:1}async function hp(I,V){let X=hn(I,V.syncOptions),ee=s(X.filesystemScope,V.legacyPath),ne=o(ee);if(ne===null)return console.log(`No legacy config found at ${V.legacyPath}`),!0;let te=ow(ne);if(!te.ok){for(let Ne of te.errors)console.error(Ne);return!1}let le=f(X.configTarget);if(le.errors.length>0){for(let Ne of le.errors)console.error(Ne);return!1}let de=le.config??ge,ve=iw(gp(V.configPath),de.rules,V.defaultRulebookName,V.migratedFrom,X.filesystemScope),Se=Mo(gp(V.configPath),ve,"rulebook.json"),Ie=s(X.filesystemScope,Se),$e=[yp(X.configTarget),yp(Ie)],Le=await rw(I,V,X.configTarget,Ie,ve,te.config.rules,{...de,rules:de.rules.includes(ve)?de.rules:[...de.rules,ve]});if(!Le.ok){lw($e);for(let Ne of Le.errors)console.error(Ne);return!1}if(!V.cleanup)return console.log(`Migrated legacy config at ${V.legacyPath}. Legacy file is no longer used.`),!0;if(!aw(X.configTarget,Ie,ve,V.migratedFrom,te.config.rules))return console.error(`Migration cleanup verification failed for ${V.legacyPath}`),!1;return q(ee),console.log(`Deleted legacy config at ${V.legacyPath}`),!0}async function rw(I,V,X,ee,ne,te,le){try{return yn(X,le),yn(ee,sw(ne,V.migratedFrom,te)),await Ho(I,V.syncOptions)}catch(de){return{ok:!1,errors:[de instanceof Error?de.message:String(de)]}}}function ow(I){try{let V=JSON.parse(I),X=Qo(V);if(X.errors.length>0)return{ok:!1,errors:X.errors};return{ok:!0,config:{version:1,rules:V.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function iw(I,V,X,ee,ne){let te=V.find((le)=>cw(s(ne,Mo(I,le,"rulebook.json")))===ee);if(te)return te;if(o(s(ne,Mo(I,X,"rulebook.json")))===null)return X;for(let le=2;;le++){let de=`${X}-${le}`;if(o(s(ne,Mo(I,de,"rulebook.json")))===null)return de}}function sw(I,V,X){return{rulebook_version:1,name:I,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:V,allowed_commands:[...new Set(X.map((ee)=>ee.command))],rules:X,tests:X.map((ee)=>({command:[ee.command,ee.subcommand,ee.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:ee.name}))}}function aw(I,V,X,ee,ne){if(!f(I).config?.rules.includes(X))return!1;try{let le=o(V);if(le===null)return!1;let de=JSON.parse(le);return de.migrated_from===ee&&JSON.stringify(de.rules)===JSON.stringify(ne)}catch{return!1}}function yp(I){return{target:I,content:o(I)}}function lw(I){for(let V of I){if(V.content===null){q(V.target);continue}x(V.target,V.content)}}function cw(I){let V=o(I);if(V===null)return null;try{let X=JSON.parse(V);return typeof X.migrated_from==="string"?X.migrated_from:null}catch{return null}}import{mkdir as dw,readFile as uw,writeFile as pw}from"node:fs/promises";import{dirname as fw,join as mw}from"node:path";var gw=86400000,hw=604800000;async function wp(I,V=Date.now()){if(I.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let X=ut(I);if(!X)return null;let ee=mw(X,".cc-safety-net","update-check.json"),ne=await yw(ee,V);if(!ne.lastCheck||V-ne.lastCheck>gw){let de=await Hn();if(ne.lastCheck=V,de.latestVersion)ne.latestVersion=de.latestVersion;if(!await bp(ee,ne))return null;if(de.error)return null}let te=ne.latestVersion,le=un();if(!te||!ii(te,le))return null;if(ne.notifiedVersion===te&&ne.notifiedAt!==void 0&&V-ne.notifiedAt<hw)return null;if(ne.notifiedVersion=te,ne.notifiedAt=V,!await bp(ee,ne))return null;return`UPDATE_AVAILABLE: cc-safety-net v${te} is available (running v${le}). 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 yw(I,V){let X=await uw(I,"utf8").then((te)=>JSON.parse(te)).catch(()=>{return});if(!X||typeof X!=="object"||Array.isArray(X))return{};let ee=X,ne=(te)=>typeof te==="number"&&Number.isFinite(te)&&te<=V?te:void 0;return{lastCheck:ne(ee.lastCheck),latestVersion:typeof ee.latestVersion==="string"?ee.latestVersion:void 0,notifiedVersion:typeof ee.notifiedVersion==="string"?ee.notifiedVersion:void 0,notifiedAt:ne(ee.notifiedAt)}}async function bp(I,V){return dw(fw(I),{recursive:!0,mode:448}).then(()=>pw(I,JSON.stringify(V),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as Cw,resolve as Us}from"node:path";var kp=new Map([["Bash","posix"],["PowerShell","powershell"],["Monitor","posix"]]);var Cp=new Map([["Bash","auto"]]);var xp=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);var Pp=new Map([["Shell","auto"]]);var Sp=new Map([["exec","auto"]]),Rp="write_to_process";var Ep=new Map([["Execute","auto"]]);var Tp=new Map([["run_shell_command","auto"]]);var Ap=new Map([["run_terminal_command","auto"],["run_terminal_cmd","auto"],["monitor","auto"],["bash","auto"],["Shell","auto"]]);var _p=new Map([["terminal","posix"]]);var Ip=new Map([["Bash","posix"]]);var Op="exec";var ww=[["antigravity-cli",[...il.keys(),sl]],["claude-code",[...kp.keys()]],["codex",[...Cp.keys()]],["copilot-cli",[...xp.keys()]],["cursor",[...Pp.keys()]],["deepseek-harness",[...ze.keys()]],["devin",[...Sp.keys(),Rp]],["droid",[...Ep.keys()]],["gemini-cli",[...Tp.keys()]],["grok-build",[...Ap.keys()]],["hermes-agent",[..._p.keys()]],["kimi-code",[...Ip.keys()]],["openclaw",[Op]],["opencode",[it,Oe]],["pi",[...ct.keys()]]].flatMap(([I,V])=>V.map((X)=>({name:X,integration:cn(I)}))),$p="and is already analyzed. Built-in tools cannot be declared.";function Uo(I){let V=je(I),X=[...new Set(ww.filter((ee)=>je(ee.name)===V).map((ee)=>ee.integration))].sort((ee,ne)=>ee.localeCompare(ne));if(X.length>0)return`"${I}" is a built-in shell tool of ${kw(X)}, ${$p}`;if(v(I)!=="unknown")return`"${I}" is a built-in file tool, ${$p}`;return}function kw(I){return I.length===1?I[0]??"":`${I.slice(0,-1).join(", ")} and ${I.at(-1)}`}var Np="CC Safety Net Config",xw="═".repeat(Np.length),Pw="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Sw=new Set(["rule.json","rule.lock","cache"]);function Lp(I,V={}){try{return Rw(I,V)}catch(X){if(X instanceof i)return console.error(X.message),1;throw X}}function Rw(I,V){let X=V.cwd??process.cwd(),ee=oe(I,{cwd:X}),ne=Bt(I),te=Ut(X),le=Us(X,Ee),de=s(ee.userScope,ne),ve=s(ee.projectScope,te),Se=!1,Ie=!1,$e=[],Le=[],Ne=Ew(s(ee.projectScope,le));if(Aw(),o(ee.userConfigTarget)!==null){let Fe=Fn(ee.userConfigTarget);if(Fe.errors.push(...J(ee.userConfigPath,ee.userScope),...Dp(ee.userConfigTarget)),$e.push({scope:"User",path:ee.userConfigPath,result:Fe,schema:"rules",target:ee.userConfigTarget}),Fe.errors.length>0)Se=!0}if(o(de)!==null)if(Ie=!0,o(ee.userConfigTarget)!==null)Le.push(Bo("user","cleanup"));else{let Fe=ei(de);if($e.push({scope:"User",path:ne,result:Fe,schema:"legacy",inactive:!0,target:de}),Le.push(Bo("user",Fe.errors.length>0?"fix-or-delete":"migrate")),Fe.errors.length>0)Se=!0}if(o(ee.projectConfigTarget)!==null){let Fe=Fn(ee.projectConfigTarget);if(Fe.errors.push(...J(ee.projectConfigPath,ee.projectScope),...Dp(ee.projectConfigTarget)),$e.push({scope:"Project",path:Us(ee.projectConfigPath),result:Fe,schema:"rules",target:ee.projectConfigTarget}),Fe.errors.length>0)Se=!0;if(o(ve)!==null)Ie=!0,Le.push(Bo("project","cleanup"))}else if(o(ve)!==null){Ie=!0,Se=!0;let Fe=ei(ve);$e.push({scope:"Project",path:Us(te),result:Fe,schema:"legacy",inactive:!0,target:ve}),Le.push(Bo("project",Fe.errors.length>0?"fix-or-delete":"migrate"))}if(Ne?.result.errors.length)Se=!0;if($e.length===0&&!Ne)return console.log(`
|
|
280
|
+
Check that every parent path component is a directory.`;return V}import{mkdirSync as yb}from"node:fs";import{dirname as vb}from"node:path";import{createInterface as bb}from"node:readline";import{existsSync as _u,readFileSync as pb}from"node:fs";function It(I,V){let X=wt(I,V);return{policy:X.policy,errors:he(bt(X.issues,St,(ee)=>ee.kind==="custom")," "," ")}}function Er(I,V){return It(I,V).errors}function Au(I,V){return{"safety.level":I.safety.level,...$s("safety.overrides",I.safety.overrides),"workflow.worktree_mode":String(I.workflow.worktree_mode),"destructive_command_protection.enabled":String(I.destructive_command_protection.enabled),...$s("destructive_command_protection.overrides",I.destructive_command_protection.overrides),"destructive_command_protection.allow_paths":Ds(I.destructive_command_protection.allow_paths),"secret_protection.enabled":String(I.secret_protection.enabled),...$s("secret_protection.overrides",I.secret_protection.overrides),"secret_protection.deny_paths":Ds(I.secret_protection.deny_paths),"secret_protection.allow_paths":Ds(I.secret_protection.allow_paths),...V?{"audit.retention_days":String(I.audit.retention_days)}:{}}}function _o(I,V,X){let ee=Au(I,X),ne=Au(V,X);return[...new Set([...Object.keys(ee),...Object.keys(ne)])].flatMap((te)=>ee[te]===ne[te]?[]:[{field:te,before:ee[te],after:ne[te]}])}function Tr(I,V){let X=p(I,V);if(!_u(X))return{baseline:_(globalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__,I.home),diagnostics:[]};let ee=$t(X),ne=It(ee.value,I.home);return{baseline:ne.policy,diagnostics:ee.errors.length>0?ee.errors:ne.errors}}function $t(I){if(!_u(I))return{errors:[`${I}: file not found`]};try{return{value:JSON.parse(pb(I,"utf-8")),errors:[]}}catch(V){let X=V instanceof Error?V.message:String(V);return{errors:[`${I}: ${V instanceof SyntaxError?`Invalid JSON: ${X}`:X}`]}}}function Io(I,V){let X=fb(I)?I:{};return{version:V.version,...Object.fromEntries(["safety","workflow","destructive_command_protection","secret_protection"].filter((ee)=>X[ee]!==void 0).map((ee)=>[ee,X[ee]]))}}function $s(I,V){return Object.fromEntries(Object.entries(V).flatMap(([X,ee])=>ee===void 0?[]:[[`${I}.${X}`,String(ee)]]))}function Ds(I){return I.length===0?"(none)":I.join(", ")}function fb(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}import{chmodSync as mb,existsSync as Iu,mkdirSync as gb,readFileSync as Ou}from"node:fs";import{dirname as hb}from"node:path";function $u(I,V={}){let X=p(I,V);if(!Iu(X))return{path:X,exists:!1,raw:"",policy:N(),errors:[]};let ee=Ou(X,"utf-8");if(!ee.trim())return{path:X,exists:!0,raw:ee,policy:N(),errors:["Config file is empty"]};try{let ne=It(JSON.parse(ee),I.home);return{path:X,exists:!0,raw:ee,policy:ne.policy,errors:ne.errors}}catch(ne){return{path:X,exists:!0,raw:ee,policy:N(),errors:[`Invalid JSON: ${ne instanceof Error?ne.message:String(ne)}`]}}}function Ln(I,V,X={}){let ee=p(I,X),ne=It(V,I.home);if(ne.errors.length>0)return{path:ee,policy:N(),errors:ne.errors};let te=ne.policy;return gb(hb(ee),{recursive:!0,mode:448}),x(pe(ee),`${JSON.stringify(te,null,2)}
|
|
281
|
+
`,384),mb(ee,384),{path:ee,policy:te,errors:[]}}function Du(I,V){let X=It(V,I.home);if(X.errors.length>0)return{errors:X.errors};return{preview:Qe(X.policy,I.env),errors:[]}}function Nu(I,V={}){let X=p(I,V);if(!Iu(X))return Ln(I,ae,V);let ee=Ou(X,"utf-8");if(!ee.trim())return Ln(I,ae,V);try{return Ln(I,_(JSON.parse(ee),I.home),V)}catch{return Ln(I,ae,V)}}var Lu=new Set(["check","apply"]),ju="(unset)";async function Hu(I,V,X={}){let ee=fn({label:"policy",booleans:{global:["-g","--global"]},positionals:"list"},V),ne=ee.positionals[0],te=[...ee.errors,...ne&&!Lu.has(ne)?[`Unknown policy subcommand: ${ne}`]:[],...ne&&Lu.has(ne)&&!ee.positionals[1]?[`policy ${ne} requires a file`]:[],...ee.positionals.slice(2).map((Be)=>`Unexpected policy argument: ${Be}`)];if(te.length>0){for(let Be of te)console.error(Be);return 1}let le=ee.positionals[1];if(!ne||!le)return er($r,console.error),1;let de=X.cwd??process.cwd(),be=ee.flags.global?p(I):S(de);if(!ee.flags.global&&L(I,{cwd:de}))return console.error(`${be} is the user policy, not a project policy; use --global for the user scope, or run from a project directory`),1;let Se=$t(le),Ie=[...Se.errors,...Er(Se.value,I.home).map((Be)=>`${le}: ${Be}`),...!ee.flags.global&&Cb(Se.value)&&Se.value.audit!==void 0?[`${le}: audit settings are user scope only; remove the audit section from a project proposal`]:[]];if(Ie.length>0){for(let Be of Ie)console.error(Be);return 1}let $e=_(Se.value,I.home);if(console.log(`Scope: ${ee.flags.global?"user":"project"} (${be})`),console.log(`Proposal: ${le}`),ee.flags.global)Fu(_($t(be).value,I.home),$e,!0);if(!ee.flags.global){let Be=Tr(I).baseline;console.log("Effective policy (user + project merged):"),Fu(se(Be,ve($t(be).value,I.home).policy).policy,se(Be,ve(Se.value,I.home).policy).policy,!1)}if(ne==="check")return 0;let Le=X.input??process.stdin,Ne=X.output??process.stdout;if(!Le.isTTY||!Ne.isTTY)return console.error("policy apply confirms interactively; run this yourself in a terminal:"),console.error(` cc-safety-net policy apply ${le}${ee.flags.global?" --global":""}`),1;if(!await wb(`Apply this policy to ${be}? [y/N] `,Le,Ne))return console.log("Cancelled; nothing was written."),0;return kb(I,be,Se.value,$e,ee.flags.global),console.log(`Policy applied: ${be}`),0}function wb(I,V,X){let ee=bb({input:V,output:X,terminal:!1});return new Promise((ne)=>{ee.once("close",()=>ne(!1)),ee.question(I,(te)=>{ne(/^y(es)?$/i.test(te.trim())),ee.close()})})}function kb(I,V,X,ee,ne){if(ne){Ln(I,ee);return}yb(vb(V),{recursive:!0}),yn(V,Io(X,ee))}function Fu(I,V,X){let ee=_o(I,V,X);if(ee.length===0){console.log("No changes.");return}console.log(`Changes (${ee.length}):`);for(let ne of ee)console.log(` ${ne.field}: ${ne.before??ju} -> ${ne.after??ju}`)}function Cb(I){return!!I&&typeof I==="object"&&!Array.isArray(I)}import{join as Lw}from"node:path";var Mu="# Custom Rules Reference\n\nAgent reference for generating CC Safety Net rulebook configuration.\n\n## Config Locations\n\n| Scope | Config path | Rulebook path | Priority |\n|-------|-------------|---------------|----------|\n| User | `~/.cc-safety-net/rules/rule.json` | `~/.cc-safety-net/rules/<rulebook-name>/rulebook.json` | First |\n| Project | `.cc-safety-net/rules/rule.json` | `.cc-safety-net/rules/<rulebook-name>/rulebook.json` | Second |\n| GitHub source | Listed in a local `rule.json` | Vendored into the consumer's `<rulebook-name>/rulebook.json` by `rule add` | Source order |\n\nEvery rulebook is a live file: the runtime reads it on each tool call, so an edit applies to the next command with no publishing step.\n\nUser scope is evaluated before project scope; within a scope, sources apply in `rules` array order. A duplicate active rulebook name keeps the first claim and ignores the later rulebook with a warning, so a user-scoped name shadows a project-scoped one.\n\nUse `cc-safety-net rule init` to create an inert local config. Use `--global` for user scope. Use `cc-safety-net rule init --example` to also create an inactive example rulebook. `CC_SAFETY_NET_HOME` overrides the `~/.cc-safety-net` user root.\n\nLegacy inline `.safety-net.json` and `~/.cc-safety-net/config.json` files are not loaded at runtime. Convert them with `cc-safety-net rule migrate`.\n\n## rule.json Schema\n\n```json\n{\n \"version\": 1,\n \"rules\": [\"project-rules\", \"owner/repo#main/team-rules\"],\n \"overrides\": {\n \"project-rules/block-docker-system-prune\": {\n \"reason\": \"Use targeted Docker cleanup commands.\"\n },\n \"team-rules/block-npm-global\": \"off\"\n },\n \"transparent_wrappers\": [\"rtk\"]\n}\n```\n\n- `version`: Required. Must be `1`.\n- `$schema`: Optional. `cc-safety-net rule verify` inserts it into a valid `rule.json` that lacks it.\n- `rules`: Optional array of rulebook source strings. Missing `rules` is treated as `[]`.\n- `overrides`: Optional object keyed by `<rulebook-name>/<rule-name>`.\n- `overrides` values are either `\"off\"` to disable a rule or an object with a required `reason` (replacement block reason) and an optional `intent` (one of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain`).\n- A project override cannot target a user-scoped rule: only that override is ignored, the user rule keeps its configured state, and `rule verify` reports the diagnostic as a failure.\n- `transparent_wrappers`: Optional array of command names that transparently execute a visible child command.\n- `caffeinate`, `exec`, `nice`, `nohup`, `setsid`, `stdbuf`, `time`, and `timeout` are built-in transparent wrappers and need no configuration. Configure only other wrappers you intentionally trust, such as `\"rtk\"`.\n- Use `cc-safety-net rule wrapper add rtk` to configure RTK without manually editing `rule.json`.\n- `command_tools`: Optional array of shell tools that a plugin adds to an agent and that CC Safety Net does not know. Each entry is a tool name such as `\"ops_bash\"`, or `{ \"name\": \"ops_run_background\", \"cwd\": \"cwd\" }` when the tool takes its working directory in a named argument (otherwise `workdir`, `cwd`, or `working_directory` is read). A call to a declared tool with a non-empty string `command` is analyzed like a built-in shell command. User and project lists merge; the user entry wins a name declared in both.\n- Built-in shell and file tools are already analyzed and cannot be declared; `rule verify` reports one declared by hand.\n- Use `cc-safety-net rule tool add ops_bash ops_run_background` to declare tools in the user config, or add `--project` for the project config.\n\n## Rulebook Sources\n\n- Local sources are bare rulebook names such as `project-rules`; the rulebook file is `.cc-safety-net/rules/project-rules/rulebook.json`.\n- Run `cc-safety-net rule add owner/repo` to add every rulebook currently present on the repository's default branch.\n- Use `--only` to select one or more rulebooks while preserving their order: `cc-safety-net rule add owner/repo --only aws gcloud`.\n- Use `--ref` to select a branch, tag, or commit instead of the default branch: `cc-safety-net rule add owner/repo --ref v2 --only aws`.\n- GitHub sources are stored in canonical form as `owner/repo#ref/<rulebook-name>`. That form remains valid in `rule.json` and as direct CLI input.\n- GitHub refs may contain `/`-separated path segments, such as `feature/rulebook-v2`.\n- The GitHub source name, the repository directory name, and the rulebook `name` must match exactly.\n- Rulebook source strings must be unique in a config.\n\n## rulebook.json Schema\n\n```json\n{\n \"rulebook_version\": 1,\n \"name\": \"project-rules\",\n \"version\": \"1.0.0\",\n \"description\": \"Project-specific CC Safety Net rules.\",\n \"author\": \"project\",\n \"allowed_commands\": [\"docker\"],\n \"rules\": [\n {\n \"name\": \"block-docker-system-prune\",\n \"command\": \"docker\",\n \"subcommand\": \"system\",\n \"block_args\": [\"prune\"],\n \"reason\": \"Use targeted cleanup instead.\"\n }\n ],\n \"tests\": [\n {\n \"command\": \"docker system prune\",\n \"expect\": \"blocked\",\n \"rule\": \"block-docker-system-prune\"\n },\n {\n \"command\": \"docker ps\",\n \"expect\": \"allowed\"\n }\n ]\n}\n```\n\n### Rulebook Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `rulebook_version` | Yes | Must be `1` or `2` |\n| `name` | Yes | `^[a-zA-Z][a-zA-Z0-9_-]{0,63}$` |\n| `version` | Yes | Non-empty string |\n| `description` | No | Free text; not type-checked at runtime |\n| `author` | No | Free text; not type-checked at runtime |\n| `allowed_commands` | Yes | Unique command names matching `^[a-zA-Z][a-zA-Z0-9_-]*$` |\n| `rules` | Yes | Array of rule objects |\n| `tests` | No | Array of fixtures |\n\n### Rule Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Unique within the rulebook (case-insensitive); same pattern as rulebook `name` |\n| `command` | Yes | Must be listed in `allowed_commands`; basename only, not path |\n| `subcommand` | No | Same pattern as `command`; omit to match any subcommand |\n| `intent` | No | One of `hard_stop`, `use_alternative`, `scope_down`, `manual_only`, `stop_and_explain` |\n| `block_args` | Yes | Non-empty array of non-empty strings |\n| `reason` | Yes | Non-empty string, max 256 chars |\n\n### Rule Fields (`rulebook_version` 2)\n\nVersion 2 replaces `subcommand` and `block_args` with an exact-token `match` object. Version 1 rulebooks keep their fields and their behavior; a client that does not support version 2 rejects the rulebook instead of applying broader version 1 semantics.\n\n```json\n{\n \"name\": \"block-terraform-apply-destroy\",\n \"command\": \"terraform\",\n \"match\": {\n \"command_path\": [\"apply\"],\n \"any_args\": [\"-destroy\", \"--destroy\"]\n },\n \"reason\": \"Review a destroy plan first with 'terraform plan -destroy'.\",\n \"intent\": \"use_alternative\"\n}\n```\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `name` | Yes | Same as version 1 |\n| `command` | Yes | Same as version 1 |\n| `match.command_path` | Yes | Non-empty array of non-empty command words |\n| `match.any_args` | No | Non-empty array of unique non-empty argument tokens |\n| `match.exclude_args` | No | Non-empty array of unique non-empty argument tokens |\n| `intent` | No | Same as version 1 |\n| `reason` | Yes | Same as version 1 |\n\n### Matching Behavior (`rulebook_version` 2)\n\n- **Command**: Normalized to lowercase basename, as in version 1.\n- **Command path**: After recognized global options and their values are skipped, the next command words must equal `command_path` exactly. AWS, gcloud, and Azure CLI value-taking global options are built in; Terraform's `-chdir=dir` is `=`-joined and is skipped with its own token.\n- **Unrecognized options**: A token starting with `-` that is not a recognized global option is skipped without consuming a value, so an unlisted value-taking option with a separate value (`--newflag value`) makes the rule miss. This fails open deliberately; document such gaps in the rulebook.\n- **`any_args`**: At least one listed token must appear literally among the arguments.\n- **`exclude_args`**: Any listed token appearing literally among the arguments prevents the match, which is how a safe preview such as `aws s3 rm --dryrun` stays allowed.\n- **No short-option expansion**: Arguments compare as exact tokens, so list every accepted spelling (`\"-destroy\"` and `\"--destroy\"`).\n- **Literal and case-sensitive**: No regex, glob, or substring matching. The first matching rule wins.\n- Release channels are separate rules: `gcloud beta compute instances delete` needs its own `command_path`.\n\n### Test Fixture Fields\n\n| Field | Required | Constraints |\n|-------|----------|-------------|\n| `command` | Yes | Non-empty shell command string |\n| `expect` | Yes | `\"blocked\"` or `\"allowed\"` |\n| `rule` | Required for blocked fixtures | Rule name expected to block the command |\n\nFixtures are optional documentation of intended behavior. Version 1 fixtures are shape-validated only. Version 2 fixtures are evaluated against the rulebook's own rules when a source is fetched by `rule add` or `rule update`, and by `rule verify`; a failing fixture rejects that source before it is written. Loading a rulebook does not re-evaluate fixtures. CC Safety Net never executes fixture commands; they are analyzer inputs only.\n\n## Matching Behavior\n\nThe subcommand, argument, and option rules below describe `rulebook_version` 1 rules; version 2 rules match as described in Matching Behavior (`rulebook_version` 2). Execution order and transparent wrappers apply to both.\n\n- **Command**: Normalized to lowercase basename with any trailing `.exe` removed (`/usr/bin/git` → `git`).\n- **Subcommand**: The first command token after recognized Git and Docker global options and their values; `--` ends option parsing. An unrecognized option without `=` may consume the following token as its value.\n- **Arguments**: Each `block_args` value is compared literally against every command token, including expanded short options. The command is blocked if **any** item matches.\n- **Short options**: Expanded (`-Ap` matches `-A`).\n- **Long options**: Exact match (`--all-files` does not match `--all`).\n- **Execution order**: Built-in rules first, then custom rulebooks. Custom rules only add restrictions.\n- **Transparent wrappers**: A configured wrapper such as `rtk` lets `rtk git commit` be analyzed as `git commit` only when `git` is protected by built-in analyzers or active custom rules. `rtk -- git commit` is also supported.\n\n## Workflow\n\n1. Run `cc-safety-net rule init` or create `rule.json` manually.\n2. Optionally run `cc-safety-net rule init --example` to create an inactive example rulebook.\n3. Use `cc-safety-net rule wrapper add rtk` for trusted transparent wrappers.\n4. Run `cc-safety-net rule add <source>` after creating or choosing a rulebook source; add `--only <rulebook...>` or `--ref <ref>` for repository selection. The command adds the selected sources and syncs them.\n5. Edit a local rulebook whenever you like: the edit is enforced on the next command, so there is nothing to run afterwards.\n6. Run `cc-safety-net rule update [source]` to re-fetch remote sources and rewrite the vendored copies; the command prints what changed. A source with an ordinary update failure keeps its vendored copy while the other selected sources still update. Resource-limit failures remain fatal for the whole update.\n7. Run `cc-safety-net rule verify` to validate config, local rulebooks, and shareable GitHub-source rulebook directories in the current repository (it does not fetch remote content).\n8. Run `cc-safety-net rule list` to inspect active rulebooks and transparent wrappers.\n\nA missing or invalid rulebook file makes that source inactive, and an unreadable or invalid `rule.json` makes every source in its scope inactive. Inactive sources stop applying their rules while other custom rules and all built-in protections stay active. Fix the file named in the diagnostic, or run `cc-safety-net rule update` when a remote source has not been vendored yet. Run `cc-safety-net status` to see degraded sources.\n";function Oo(I,V){if(!I.ok){Ku(I);return}Gu(I,V)}function Bu(I,V,X){if(I.ok)console.log(X);if(!I.add){Oo(I,`Added rulebook source: ${V}`);return}if(!I.ok){Ku(I);return}if(I.add.added.length>0)console.log(`Added ${I.add.added.length} ${I.add.added.length===1?"rulebook":"rulebooks"} from ${I.add.source} at ${I.add.ref}:`),I.add.added.forEach((ee)=>{console.log(` - ${ee}`)});if(I.add.alreadyConfigured.length>0)console.log(`Rulebooks already configured from ${I.add.source} at ${I.add.ref}: ${I.add.alreadyConfigured.join(", ")}`);if(I.add.commits.length>0)console.log(`Vendored at ${I.add.commits.map((ee)=>ee.slice(0,7)).join(", ")}.`);Gu(I,"Rule config updated.")}function Gu(I,V){for(let X of I.changes??[])console.log(X);console.log(V),console.log(""),xb(I.entries)}function xb(I){if(I.length===0){console.log("Active rulebooks: (none)");return}console.log(`Active rulebooks (${I.length}):`);for(let V of I)console.log(` - ${V.name} ${V.version} (${Pb(V.ruleCount)})`),console.log(` Source: ${V.spec}`)}function Pb(I){return`${I} ${I===1?"rule":"rules"}`}function qu(I){Vn("Active sources",I.rulebooks,(V)=>[`[${V.source}] ${V.name} ${V.version}`,` Source: ${V.spec}`]),Vn("Active rules",I.rules,(V)=>[`[${Rb(I,V.name)}] ${V.name}`,...Sb(V),` Reason: ${V.reason}`]),Vn("Disabled rules",Uu(I,"off"),(V)=>[V.key]),Vn("Reason overrides",Uu(I,"reason"),(V)=>[V.key,` Reason: ${V.value.reason}`]),Vn("Transparent wrappers",I.transparent_wrappers,(V)=>[V]),Vn("Issues",I.errors,(V)=>[V]),Vn("Warnings",I.warnings,(V)=>[V])}function Vu(I){Vn("Command tools",I,(V)=>typeof V.tool==="string"?[`[${V.scope}] ${V.tool}`]:[`[${V.scope}] ${V.tool.name}`,...V.tool.cwd===void 0?[]:[` Cwd argument: ${V.tool.cwd}`]])}function Vn(I,V,X){if(V.length===0){console.log(`${I}: (none)`);return}console.log(`${I} (${V.length}):`);for(let ee of V){let[ne,...te]=X(ee);console.log(` - ${ne}`);for(let le of te)console.log(` ${le}`)}}function Sb(I){if(!I.match)return[` Command: ${I.subcommand?`${I.command} ${I.subcommand}`:I.command}`,` Block args: ${I.block_args.join(", ")}`];return[` Command: ${[I.command,...I.match.command_path].join(" ")}`,...I.match.any_args?[` Any args: ${I.match.any_args.join(", ")}`]:[],...I.match.exclude_args?[` Exclude args: ${I.match.exclude_args.join(", ")}`]:[]]}function Rb(I,V){return I.rulebooks.find((X)=>X.rules.includes(V))?.source??"project"}function Uu(I,V){return Object.entries({...I.userConfig?.overrides,...I.projectConfig?.overrides}).filter((X)=>{if(V==="off")return X[1]==="off";return!!X[1]&&typeof X[1]==="object"}).map(([X,ee])=>({key:X,value:ee}))}function Ku(I){for(let V of I.errors)console.error(V)}import{dirname as gp,join as Mo}from"node:path";import{join as Fs,resolve as Fb}from"node:path";function Ar(I){let V=f(I);if(V.errors.length>0)return{ok:!1,result:{ok:!1,errors:V.errors,entries:[]}};return{ok:!0,config:V.config??ge}}function Ju(I){yn(I,ge)}function zu(I){yn(I,{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 Lo}from"node:path";var Eb="custom.";function $o(I){if(I.rulebook_version!==2)return[];let V=I.rules.map((X)=>({name:X.name,command:X.command,block_args:[],match:X.match,reason:X.reason,intent:X.intent}));return(I.tests??[]).flatMap((X,ee)=>{let ne=Ns(C(X.command));if(ne.length===0)return[`tests[${ee}]: could not parse fixture command: ${X.command}`];let te=ne.reduce((le,de)=>le??F(de,V)?.id.slice(Eb.length),void 0);if(X.expect==="blocked"){if(te===X.rule)return[];let le=te?`"${te}" matched first`:"no rule matched";return[`tests[${ee}]: expected "${X.rule}" to block "${X.command}" but ${le}`]}return te?[`tests[${ee}]: expected "${X.command}" to be allowed but "${te}" matched`]:[]})}function Ns(I){return I.nodes.flatMap((V)=>{if(V.kind==="group"||V.kind==="function")return Ns(V.body);if(V.kind!=="command")return[];let X=Ae(ce(V.dialect,V.words)).words.map(t);return[...X.length>0?[X]:[],...V.nested.flatMap((ee)=>Ns(ee))]})}var Do=Object.freeze({concurrency:4,maxRequests:131,maxResponseBytes:67108864});function No(I={}){return{requests:0,responseBytes:0,maxRequests:I.maxRequests??Do.maxRequests,maxResponseBytes:I.maxResponseBytes??Do.maxResponseBytes}}function jn(I){return{controller:new AbortController,budget:No(),resolveUrl:I}}function Wu(I){return I instanceof Error&&I.message==="Rule synchronization exceeds CC Safety Net's safe resource limits."}function Yu(I){if(I.requests>=I.maxRequests)throw Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");I.requests++}function Zu(I,V){if(V>I.maxResponseBytes-I.responseBytes)throw I.responseBytes+=V,Error("Rule synchronization exceeds CC Safety Net's safe resource limits.");I.responseBytes+=V}var ep=Object.freeze({timeoutMs:15000,metadataBytes:524288,commitBytes:262144,treeBytes:16777216,rawBytes:4194304});async function Xu(I,V,X=R(Lo(Lo(V)),"rules policy"),ee=jn()){if(T(I))return Ib(I,ee);return _b(I,V,X)}async function np(I,V,X,ee,ne,te){if(!T(I))return Xu(I,V,X,ee);let le=ne?null:Tb(I,V,X);if(le)return le;if(!ne&&!te)throw Error(`${I} is not vendored; run rule update ${I} to vendor it`);return Xu(I,V,X,ee)}function Tb(I,V,X=R(Lo(Lo(V)),"rules policy")){let ee=j(I),ne=U(V,ee.name),te=o(s(X,ne));if(te===null)return null;let le=ye(Ls(te,`Invalid rulebook ${ne}.`));if(le.name!==ee.name)throw Error(`rulebook name "${le.name}" in ${ne} must match "${ee.name}"`);return{spec:I,rulebook:le,content:te}}async function tp(I,V={}){if(!re(I))throw Error(`Invalid GitHub repository source: ${I}`);let[X,ee]=I.split("/");if(!X||!ee)throw Error(`Invalid GitHub repository source: ${I}`);if(V.ref!==void 0&&!fe(V.ref))throw Error(`GitHub rulebook refs must use valid path segments: ${V.ref}`);let ne=V.operation??jn(),te=V.ref??await Ab(X,ee,I,ne),le=await op(X,ee,te,I,ne),de=await jo(`https://api.github.com/repos/${X}/${ee}/git/trees/${le}?recursive=1`,"tree",ne),be=de.response;if(!be.ok)throw Error(`Failed to inspect ${I}: GitHub tree returned ${be.status}`);let Se=JSON.parse(de.content);if(!Array.isArray(Se?.tree))throw Error(`Failed to inspect ${I}: unexpected GitHub tree response`);let Ie=Se.tree,$e=[...new Set(Ie.flatMap((Le)=>{if(!Le||typeof Le!=="object")return[];let Ne=Le;if(Ne.type!=="blob"||typeof Ne.path!=="string")return[];let Fe=Ne.path.match(Nt);return Fe?.[1]?[Fe[1]]:[]}))].sort();if($e.length===0)throw Error(`No rulebooks found in ${I} under ${Ee}/`);return{source:I,owner:X,repo:ee,ref:te,commit:le,names:$e}}async function Ab(I,V,X,ee){let ne=await jo(`https://api.github.com/repos/${I}/${V}`,"metadata",ee),te=ne.response;if(!te.ok)throw Error(`Failed to inspect ${X}: GitHub returned ${te.status}`);let de=JSON.parse(ne.content)?.default_branch;if(typeof de!=="string"||de==="")throw Error(`Failed to inspect ${X}: missing default branch`);if(!fe(de))throw Error(`GitHub returned an invalid default branch: ${de}`);return de}function _b(I,V,X){Lt(I);let ee=U(V,I),ne=o(s(X,ee));if(ne===null)throw Error(`Rulebook source not found: ${I}`);let te=rp(Ls(ne,"Invalid local rulebook source."));if(te.name!==I)throw Error(`rulebook name "${te.name}" must match local source "${I}"`);return{spec:I,rulebook:te,content:ne}}async function Ib(I,V){let X=j(I),ee=await op(X.owner,X.repo,X.ref,I,V),ne=await jo(`https://raw.githubusercontent.com/${X.owner}/${X.repo}/${ee}/${X.path}`,"raw",V),te=ne.response;if(!te.ok)throw Error(`Failed to fetch ${I}: GitHub raw returned ${te.status}`);let le=ne.content,de=rp(Ls(le,"Invalid GitHub rulebook response."));if(de.name!==X.name)throw Error(`rulebook name "${de.name}" must match GitHub source "${X.name}"`);return{spec:I,rulebook:de,content:le}}function rp(I){let V=ye(I),X=$o(V);if(X.length>0)throw Error(X.join("; "));return V}function Ls(I,V){try{return JSON.parse(I)}catch{throw Error(V)}}async function op(I,V,X,ee,ne){let te=await jo(`https://api.github.com/repos/${I}/${V}/commits/${encodeURIComponent(X)}`,"commit",ne),le=te.response;if(!le.ok)throw Error(`Failed to resolve ${ee}: GitHub returned ${le.status}`);let de=JSON.parse(te.content);if(typeof de?.sha!=="string"||de.sha==="")throw Error(`Failed to resolve commit for ${ee}`);return de.sha}async function Ob(I,V,X={}){if(X.signal?.aborted)throw X.signal.reason;let ee=X.budget??No(),ne=new AbortController,te=()=>ne.abort(X.signal?.reason);X.signal?.addEventListener("abort",te,{once:!0});let le=!1,de=setTimeout(()=>{if(ne.signal.aborted)return;le=!0,ne.abort()},X.timeoutMs??ep.timeoutMs);try{if(X.signal?.aborted)throw X.signal.reason;Yu(ee);let be=await fetch(I,{signal:ne.signal,redirect:"error"});if(!be.ok)return ip(be),{response:be,content:""};return{response:be,content:await $b(be,V,ee,()=>ne.abort())}}catch(be){if(le)throw Error("GitHub request timed out",{cause:be});if(X.signal?.aborted)throw X.signal.reason;throw be}finally{clearTimeout(de),X.signal?.removeEventListener("abort",te)}}function jo(I,V,X){return Ob(X.resolveUrl?.(I)??I,V,{budget:X.budget,signal:X.controller.signal})}async function $b(I,V,X=No(),ee){let ne=ep[`${V}Bytes`],te=Number(I.headers.get("content-length"));if(Number.isFinite(te)&&te>ne)throw ip(I),Error(`GitHub ${V} response exceeds ${ne} bytes`);if(!I.body)return"";let le=I.body.getReader(),de=[],be=0;while(!0){let Se=await le.read();if(Se.done)break;try{Zu(X,Se.value.byteLength)}catch(Ie){throw ee?.(),Qu(le),Ie}if(be+=Se.value.byteLength,be>ne)throw ee?.(),Qu(le),Error(`GitHub ${V} response exceeds ${ne} bytes`);de.push(Buffer.from(Se.value))}return Buffer.concat(de,be).toString("utf-8")}function ip(I){if(!I.body)return;sp(()=>I.body?.cancel())}function Qu(I){sp(()=>I.cancel())}function sp(I){try{Promise.resolve(I()).catch(()=>{})}catch{}}var Db=/^([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)#(.+)$/;function ap(I,V){let X=dp(I.rules,V);if(X.length>0)return{ok:!0,specs:X};return cp(I.rules,V)}function lp(I,V){let X=dp(I,V);if(X.length>0)return{ok:!0,specs:X};let ee=Lb(I,V);if(ee.length>0)return{ok:!0,specs:ee};let ne=jb(I,V);if(!ne.ok)return ne;if(ne.specs.length>0)return{ok:!0,specs:ne.specs};return cp(I,V)}function cp(I,V){let X=I.filter((ee)=>js(ee)?.name===V);if(X.length===1)return{ok:!0,specs:X};return Nb(V,X)}function Nb(I,V){return{ok:!1,result:{ok:!1,errors:V.length===0?[`No configured rulebook matches ${I}`]:[`Ambiguous rulebook match ${I}: ${V.join(", ")}`],entries:[]}}}function dp(I,V){return I.filter((X)=>X===V)}function Lb(I,V){let X=V.match(Db),ee=X?.[1],ne=X?.[2],te=X?.[3];if(!ee||!ne||!te||!fe(te))return[];return up(I,(le)=>le.owner===ee&&le.repo===ne&&le.ref===te)}function jb(I,V){if(!re(V))return{ok:!0,specs:[]};let[X,ee]=V.split("/"),ne=up(I,(le)=>le.owner===X&&le.repo===ee);if(new Set(ne.map((le)=>js(le)?.ref).filter((le)=>!!le)).size<2)return{ok:!0,specs:ne};return{ok:!1,result:{ok:!1,errors:[`Multiple refs are configured for ${V}. Use an explicit ref:`,` cc-safety-net rule remove ${V}#<ref>`],entries:[]}}}function js(I){try{return j(I)}catch{return null}}function up(I,V){return I.filter((X)=>{let ee=js(X);return ee?V(ee):!1})}async function Ho(I,V={}){return Hb(I,V,await Fo(I,V,jn()))}function Hb(I,V,X){if(!X.ok)return X;let ee=hn(I,V),ne=[...new Set(J(ee.configPath,ee.filesystemScope))];if(ne.length===0)return X;return{ok:!1,errors:ne,entries:X.entries}}async function Fo(I,V,X,ee={},ne=new Set,te=new Set){try{let le=hn(I,V),de=Ar(le.configTarget);if(!de.ok)return de.result;let be=de.config,Se=V.only?ap(be,V.only):{ok:!0,specs:be.rules};if(!Se.ok)return Se.result;let Ie=new Set([...V.refresh?Se.specs:[],...ne]),$e=(nn)=>np(nn,le.configDir,le.filesystemScope,X,Ie.has(nn),!V.refresh||Ie.has(nn)),Le=await Wb(be.rules,V.refresh?(nn)=>$e(nn).then((sn)=>({ok:!0,item:sn})).catch((sn)=>{if(Wu(sn))throw sn;return{ok:!1,spec:nn,message:sn instanceof Error?sn.message:String(sn)}}):async(nn)=>({ok:!0,item:await $e(nn)}),X),Ne=Le.filter((nn)=>!nn.ok),Fe=Le.filter((nn)=>nn.ok).map((nn)=>nn.item),Be=Fe.flatMap((nn)=>Mb(nn,be.rules)),Me=Fe.flatMap((nn)=>Ub(nn,te,le)),tn=new Set([...Be,...Me].map((nn)=>nn.spec)),en=[...Ne,...Be,...Me],on=[],ln=Gb(on,()=>Fe.flatMap((nn)=>tn.has(nn.spec)||en.length>0&&te.has(nn.spec)?[]:Bb(nn,le,ee,on)));return{ok:en.length===0,errors:en.map((nn)=>`Failed to update ${nn.spec}: ${nn.message}`),entries:Fe.map(Vb),changes:ln}}catch(le){return Ir(le)}}function Mb(I,V){if(!T(I.spec))return[];let X=Xe(I.spec),ee=V.filter((ne)=>ne!==I.spec&&Xe(ne).toLowerCase()===X.toLowerCase());if(ee.length===0)return[];return[{ok:!1,spec:I.spec,message:`rulebook name "${X}" is also claimed by ${ee.join(", ")}; rename one of them`}]}function Ub(I,V,X){if(!V.has(I.spec)||!T(I.spec))return[];let ee=U(X.configDir,I.rulebook.name),ne=o(s(X.filesystemScope,ee));if(ne===null||ne===I.content)return[];return[{ok:!1,spec:I.spec,message:`${ee} already exists and no configured source claims it; remove or rename the file, then re-run rule add`}]}function Bb(I,V,X,ee){if(!T(I.spec))return[];let ne=U(V.configDir,I.rulebook.name),te=s(V.filesystemScope,ne),le=o(te);if(le===I.content)return[];return ee?.push({target:te,previous:le}),x(te,I.content,void 0,X._testAfterPolicyRename),qb(I,le)}function Gb(I,V){try{return V()}catch(X){for(let ee of[...I].reverse()){if(ee.previous===null){q(ee.target);continue}x(ee.target,ee.previous)}throw X}}function qb(I,V){if(V===null)return[`Vendored ${I.spec} (${I.rulebook.version})`];let X=Pe(V),ee="problem"in X?null:X.rulebook,ne=new Map(ee?.rules.map((le)=>[le.name,JSON.stringify(le)])??[]),te=new Set(I.rulebook.rules.map((le)=>le.name));return[`Updated ${I.spec} (${ee?.version??"unreadable"} -> ${I.rulebook.version})`,...[...te].filter((le)=>!ne.has(le)).map((le)=>` + ${le}`),...[...ne.keys()].filter((le)=>!te.has(le)).map((le)=>` - ${le}`),...I.rulebook.rules.filter((le)=>{let de=ne.get(le.name);return de!==void 0&&de!==JSON.stringify(le)}).map((le)=>` ~ ${le.name}`)]}function Vb(I){return{spec:I.spec,name:I.rulebook.name,version:I.rulebook.version,ruleCount:I.rulebook.rules.length}}async function pp(I,V,X={}){return Kb(I,V,X,jn())}async function Kb(I,V,X,ee,ne={}){let te=null,le=!1;try{let de=hn(I,X),be=o(de.configTarget);te={target:de.configTarget,content:be};let Se=Ar(de.configTarget);if(!Se.ok)return Se.result;let Ie=Se.config,$e=re(V)?await tp(V,{ref:X.ref,operation:ee}):null,Le=$e?Jb($e,X.rulebooks):[],Ne=$e?Le.map((en)=>zb(Ie.rules,$e,en)??`${V}#${$e.ref}/${en}`):[V],Fe=Ne.filter((en)=>!Ie.rules.includes(en)),Be=[...Ie.rules,...Fe];if(Be.length>ke)return Yb();if(Be.length!==Ie.rules.length)le=!0,yn(de.configTarget,{...Ie,rules:Be},void 0,ne._testAfterPolicyRename);let Me=await Fo(I,X,ee,ne,new Set(Fe),new Set(Fe));if(!Me.ok)_r(de.configTarget,be);if(!Me.ok||!$e)return Me;let tn=Le.filter((en,on)=>Fe.includes(Ne[on]??""));return{...Me,add:{source:V,ref:$e.ref,selected:Le,added:tn,alreadyConfigured:Le.filter((en)=>!tn.includes(en)),commits:Fe.length>0?[$e.commit]:[]}}}catch(de){if(le&&te)try{_r(te.target,te.content)}catch(be){return Ir(be)}return Ir(de)}}function Jb(I,V){let X=V?[...new Set(V)]:I.names,ee=X.filter((ne)=>!I.names.includes(ne));if(ee.length>0)throw Error(`Rulebooks not found in ${I.source} at ${I.ref}: ${ee.join(", ")}
|
|
282
|
+
Available rulebooks: ${I.names.join(", ")}`);return X}function zb(I,V,X){let ee=`${V.source}#${V.ref}/${X}`;if(I.includes(ee))return ee;let ne=`${V.source}#${V.commit}/${X}`;return I.find((te)=>te===ne)}async function Wb(I,V,X=jn()){if(I.length>ke)throw Error(Re);let ee=[],ne=0,te,le=Array.from({length:Math.min(I.length,Do.concurrency)},async()=>{while(!te){let de=ne;if(de>=I.length)return;ne++;try{ee[de]=await V(I[de],de,X.controller.signal)}catch(be){if(!te)te={value:be},ne=I.length,X.controller.abort(be);return}}});if(await Promise.all(le),te)throw te.value;return ee}function Yb(){return{ok:!1,errors:[Re],entries:[]}}async function fp(I,V,X={}){try{return await Zb(I,V,X,{})}catch(ee){return Ir(ee)}}async function Zb(I,V,X,ee){let ne=hn(I,X),te=f(ne.configTarget);if(te.errors.length>0)return{ok:!1,errors:te.errors,entries:[]};if(!te.config)return{ok:!1,errors:[`No config found at ${ne.configPath}`],entries:[]};let le=lp(te.config.rules,V);if(!le.ok)return le.result;let de=X.deleteSource?Xb(ne.configDir,le.specs,ne.filesystemScope):{ok:!0,dirs:[]};if(!de.ok)return de.result;let be=o(ne.configTarget);if(be===null)return Ir(Error("Rules config is unavailable."));try{yn(ne.configTarget,{...te.config,rules:te.config.rules.filter(($e)=>!le.specs.includes($e))},void 0,ee._testAfterPolicyRename)}catch($e){throw _r(ne.configTarget,be),$e}let Se=await Fo(I,X,jn(),ee);if(!Se.ok)return _r(ne.configTarget,be),Se;let Ie=Qb(de.dirs,ee,ne.filesystemScope);if(!Ie.ok){_r(ne.configTarget,be);let $e=await Fo(I,X,jn(),ee);if(!$e.ok)return{ok:!1,errors:[...Ie.result.errors,...$e.errors],entries:$e.entries};return Ie.result}return Se}function Xb(I,V,X){let ee=V.flatMap((de)=>m.test(de)?[]:["--delete-source can only delete local rulebook sources"]),ne=V.map((de)=>Fs(I,de)),te=ee.length>0?[]:ne.flatMap((de)=>mp(de,X)),le=[...ee,...te];return le.length>0?{ok:!1,result:{ok:!1,errors:le,entries:[]}}:{ok:!0,dirs:ne}}function mp(I,V){let X=Fb(I),ee=s(V,X),ne=we(ee);if(!ne)return[`Local rulebook source directory not found: ${I}`];let te=ne.find((le)=>le.name==="rulebook.json");if(!te)return[`Local rulebook source directory is missing rulebook.json: ${I}`];if(te.kind!=="file")throw new i(V.label);if(o(s(V,Fs(X,"rulebook.json"))),ne.length>1)return[`Local rulebook source directory contains extra files: ${I}. delete manually if you really want to remove the directory.`];return[]}function Qb(I,V,X){let ee=I.flatMap((ne)=>{try{if(!we(s(X,ne)))return[];let te=mp(ne,X);if(te.length>0)return te;return ew(ne,V,X),[]}catch(te){return[`Failed to delete local rulebook source ${ne}: ${te instanceof Error?te.message:String(te)}`]}});return ee.length>0?{ok:!1,result:{ok:!1,errors:ee,entries:[]}}:{ok:!0}}function ew(I,V,X){if(V._testDeleteLocalSourceDir){V._testDeleteLocalSourceDir(I);return}q(s(X,Fs(I,Ce))),Dt(s(X,I))}function _r(I,V){if(V===null){q(I);return}x(I,V)}function Ir(I){return{ok:!1,errors:[I instanceof Error?I.message:String(I)],entries:[]}}var nw=".safety-net.json",tw="~/.cc-safety-net/config.json";async function vp(I,V){let X=L(I,{cwd:V.cwd});if(X)console.log(`Skipped the project scope: ${D(V.cwd)} is the user rule config, not a project rule config`);return[X||await hp(I,{legacyPath:Ut(V.cwd),configPath:D(V.cwd),defaultRulebookName:"project-rules",migratedFrom:nw,cleanup:V.cleanup,syncOptions:{cwd:V.cwd}}),await hp(I,{legacyPath:Bt(I),configPath:K(I),defaultRulebookName:"user-rules",migratedFrom:tw,cleanup:V.cleanup,syncOptions:{cwd:V.cwd,global:!0}})].every((ne)=>ne)?0:1}async function hp(I,V){let X=hn(I,V.syncOptions),ee=s(X.filesystemScope,V.legacyPath),ne=o(ee);if(ne===null)return console.log(`No legacy config found at ${V.legacyPath}`),!0;let te=ow(ne);if(!te.ok){for(let Ne of te.errors)console.error(Ne);return!1}let le=f(X.configTarget);if(le.errors.length>0){for(let Ne of le.errors)console.error(Ne);return!1}let de=le.config??ge,be=iw(gp(V.configPath),de.rules,V.defaultRulebookName,V.migratedFrom,X.filesystemScope),Se=Mo(gp(V.configPath),be,"rulebook.json"),Ie=s(X.filesystemScope,Se),$e=[yp(X.configTarget),yp(Ie)],Le=await rw(I,V,X.configTarget,Ie,be,te.config.rules,{...de,rules:de.rules.includes(be)?de.rules:[...de.rules,be]});if(!Le.ok){lw($e);for(let Ne of Le.errors)console.error(Ne);return!1}if(!V.cleanup)return console.log(`Migrated legacy config at ${V.legacyPath}. Legacy file is no longer used.`),!0;if(!aw(X.configTarget,Ie,be,V.migratedFrom,te.config.rules))return console.error(`Migration cleanup verification failed for ${V.legacyPath}`),!1;return q(ee),console.log(`Deleted legacy config at ${V.legacyPath}`),!0}async function rw(I,V,X,ee,ne,te,le){try{return yn(X,le),yn(ee,sw(ne,V.migratedFrom,te)),await Ho(I,V.syncOptions)}catch(de){return{ok:!1,errors:[de instanceof Error?de.message:String(de)]}}}function ow(I){try{let V=JSON.parse(I),X=Qo(V);if(X.errors.length>0)return{ok:!1,errors:X.errors};return{ok:!0,config:{version:1,rules:V.rules??[]}}}catch{return{ok:!1,errors:["Invalid JSON"]}}}function iw(I,V,X,ee,ne){let te=V.find((le)=>cw(s(ne,Mo(I,le,"rulebook.json")))===ee);if(te)return te;if(o(s(ne,Mo(I,X,"rulebook.json")))===null)return X;for(let le=2;;le++){let de=`${X}-${le}`;if(o(s(ne,Mo(I,de,"rulebook.json")))===null)return de}}function sw(I,V,X){return{rulebook_version:1,name:I,version:"1.0.0",description:"Migrated CC Safety Net rules.",author:"project",migrated_from:V,allowed_commands:[...new Set(X.map((ee)=>ee.command))],rules:X,tests:X.map((ee)=>({command:[ee.command,ee.subcommand,ee.block_args[0]].filter(Boolean).join(" "),expect:"blocked",rule:ee.name}))}}function aw(I,V,X,ee,ne){if(!f(I).config?.rules.includes(X))return!1;try{let le=o(V);if(le===null)return!1;let de=JSON.parse(le);return de.migrated_from===ee&&JSON.stringify(de.rules)===JSON.stringify(ne)}catch{return!1}}function yp(I){return{target:I,content:o(I)}}function lw(I){for(let V of I){if(V.content===null){q(V.target);continue}x(V.target,V.content)}}function cw(I){let V=o(I);if(V===null)return null;try{let X=JSON.parse(V);return typeof X.migrated_from==="string"?X.migrated_from:null}catch{return null}}import{mkdir as dw,readFile as uw,writeFile as pw}from"node:fs/promises";import{dirname as fw,join as mw}from"node:path";var gw=86400000,hw=604800000;async function wp(I,V=Date.now()){if(I.env.get("CC_SAFETY_NET_NO_UPDATE_CHECK"))return null;let X=ut(I);if(!X)return null;let ee=mw(X,".cc-safety-net","update-check.json"),ne=await yw(ee,V);if(!ne.lastCheck||V-ne.lastCheck>gw){let de=await Hn();if(ne.lastCheck=V,de.latestVersion)ne.latestVersion=de.latestVersion;if(!await bp(ee,ne))return null;if(de.error)return null}let te=ne.latestVersion,le=un();if(!te||!ii(te,le))return null;if(ne.notifiedVersion===te&&ne.notifiedAt!==void 0&&V-ne.notifiedAt<hw)return null;if(ne.notifiedVersion=te,ne.notifiedAt=V,!await bp(ee,ne))return null;return`UPDATE_AVAILABLE: cc-safety-net v${te} is available (running v${le}). 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 yw(I,V){let X=await uw(I,"utf8").then((te)=>JSON.parse(te)).catch(()=>{return});if(!X||typeof X!=="object"||Array.isArray(X))return{};let ee=X,ne=(te)=>typeof te==="number"&&Number.isFinite(te)&&te<=V?te:void 0;return{lastCheck:ne(ee.lastCheck),latestVersion:typeof ee.latestVersion==="string"?ee.latestVersion:void 0,notifiedVersion:typeof ee.notifiedVersion==="string"?ee.notifiedVersion:void 0,notifiedAt:ne(ee.notifiedAt)}}async function bp(I,V){return dw(fw(I),{recursive:!0,mode:448}).then(()=>pw(I,JSON.stringify(V),{mode:384})).then(()=>!0).catch(()=>!1)}import{join as Cw,resolve as Us}from"node:path";var kp=new Map([["Bash","posix"],["PowerShell","powershell"],["Monitor","posix"]]);var Cp=new Map([["Bash","auto"]]);var xp=new Map([["bash","auto"],["Bash","auto"],["powershell","powershell"],["PowerShell","powershell"]]);var Pp=new Map([["Shell","auto"]]);var Sp=new Map([["exec","auto"]]),Rp="write_to_process";var Ep=new Map([["Execute","auto"]]);var Tp=new Map([["run_shell_command","auto"]]);var Ap=new Map([["run_terminal_command","auto"],["run_terminal_cmd","auto"],["monitor","auto"],["bash","auto"],["Shell","auto"]]);var _p=new Map([["terminal","posix"]]);var Ip=new Map([["Bash","posix"]]);var Op="exec";var ww=[["antigravity-cli",[...il.keys(),sl]],["claude-code",[...kp.keys()]],["codex",[...Cp.keys()]],["copilot-cli",[...xp.keys()]],["cursor",[...Pp.keys()]],["deepseek-harness",[...ze.keys()]],["devin",[...Sp.keys(),Rp]],["droid",[...Ep.keys()]],["gemini-cli",[...Tp.keys()]],["grok-build",[...Ap.keys()]],["hermes-agent",[..._p.keys()]],["kimi-code",[...Ip.keys()]],["openclaw",[Op]],["opencode",[it,Oe]],["pi",[...ct.keys()]]].flatMap(([I,V])=>V.map((X)=>({name:X,integration:cn(I)}))),$p="and is already analyzed. Built-in tools cannot be declared.";function Uo(I){let V=je(I),X=[...new Set(ww.filter((ee)=>je(ee.name)===V).map((ee)=>ee.integration))].sort((ee,ne)=>ee.localeCompare(ne));if(X.length>0)return`"${I}" is a built-in shell tool of ${kw(X)}, ${$p}`;if(b(I)!=="unknown")return`"${I}" is a built-in file tool, ${$p}`;return}function kw(I){return I.length===1?I[0]??"":`${I.slice(0,-1).join(", ")} and ${I.at(-1)}`}var Np="CC Safety Net Config",xw="═".repeat(Np.length),Pw="https://raw.githubusercontent.com/kenryu42/cc-safety-net/main/assets/cc-safety-net.schema.json",Sw=new Set(["rule.json","rule.lock","cache"]);function Lp(I,V={}){try{return Rw(I,V)}catch(X){if(X instanceof i)return console.error(X.message),1;throw X}}function Rw(I,V){let X=V.cwd??process.cwd(),ee=oe(I,{cwd:X}),ne=Bt(I),te=Ut(X),le=Us(X,Ee),de=s(ee.userScope,ne),be=s(ee.projectScope,te),Se=!1,Ie=!1,$e=[],Le=[],Ne=Ew(s(ee.projectScope,le));if(Aw(),o(ee.userConfigTarget)!==null){let Fe=Fn(ee.userConfigTarget);if(Fe.errors.push(...J(ee.userConfigPath,ee.userScope),...Dp(ee.userConfigTarget)),$e.push({scope:"User",path:ee.userConfigPath,result:Fe,schema:"rules",target:ee.userConfigTarget}),Fe.errors.length>0)Se=!0}if(o(de)!==null)if(Ie=!0,o(ee.userConfigTarget)!==null)Le.push(Bo("user","cleanup"));else{let Fe=ei(de);if($e.push({scope:"User",path:ne,result:Fe,schema:"legacy",inactive:!0,target:de}),Le.push(Bo("user",Fe.errors.length>0?"fix-or-delete":"migrate")),Fe.errors.length>0)Se=!0}if(o(ee.projectConfigTarget)!==null){let Fe=Fn(ee.projectConfigTarget);if(Fe.errors.push(...J(ee.projectConfigPath,ee.projectScope),...Dp(ee.projectConfigTarget)),$e.push({scope:"Project",path:Us(ee.projectConfigPath),result:Fe,schema:"rules",target:ee.projectConfigTarget}),Fe.errors.length>0)Se=!0;if(o(be)!==null)Ie=!0,Le.push(Bo("project","cleanup"))}else if(o(be)!==null){Ie=!0,Se=!0;let Fe=ei(be);$e.push({scope:"Project",path:Us(te),result:Fe,schema:"legacy",inactive:!0,target:be}),Le.push(Bo("project",Fe.errors.length>0?"fix-or-delete":"migrate"))}if(Ne?.result.errors.length)Se=!0;if($e.length===0&&!Ne)return console.log(`
|
|
283
283
|
No config files found. Using built-in rules only.`),0;for(let Fe of $e)if(Fe.inactive)Iw(Fe.scope,Fe.path,Fe.result);else if(Fe.result.errors.length>0)Ow(Fe.scope,Fe.path,Fe.result.errors);else{if(Fe.schema==="rules"&&Nw(Fe.target))console.log(`
|
|
284
284
|
Added $schema to ${Fe.scope.toLowerCase()} config.`);_w(Fe.scope,Fe.path,Fe.result,Fe.schema)}for(let Fe of Le)console.error(`
|
|
285
285
|
${qe.red(Fe)}`);if(Ne)if(Ne.result.errors.length>0)Dw(Ne.path,Ne.result.errors);else $w(Ne.path,Ne.result);if(Se)return console.error(`
|
|
286
286
|
Config validation failed.`),1;return console.log(Ie?`
|
|
287
287
|
Configs valid with warnings.`:`
|
|
288
|
-
All configs valid.`),0}function Dp(I){return(f(I).config?.command_tools??[]).flatMap((V)=>Uo(typeof V==="string"?V:V.name)??[])}function Bo(I,V){let X=`legacy ${I} config`;if(V==="cleanup")return`Warning: Legacy ${I} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(V==="migrate")return`Warning: Legacy ${I} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${I} config is no longer supported. Fix or delete the ${X}, then run \`npx -y cc-safety-net rule migrate\`.`}function Ew(I){if(we(I)===null)return null;let V=Tw(I);if(V.ruleNames.size===0&&V.errors.length===0)return null;return{path:I.path,result:V}}function Tw(I){let V=[],X=new Set,ee=(we(I)??[]).filter((ne)=>!Sw.has(ne.name)).sort((ne,te)=>ne.name.localeCompare(te.name));if(ee.length===0)return{errors:V,ruleNames:X};for(let ne of ee){if(!m.test(ne.name)){V.push(`rulebook directory names must match ${m}: ${ne.name}`);continue}if(ne.kind!=="directory"){V.push(`${ne.name} must be a rulebook directory`);continue}let te=s(I.scope,Cw(I.path,ne.name,"rulebook.json")),le=o(te);if(le===null){V.push(`${ne.name}/rulebook.json is required`);continue}try{let de;try{de=JSON.parse(le)}catch{V.push(`${ne.name}/rulebook.json: invalid JSON`);continue}let
|
|
288
|
+
All configs valid.`),0}function Dp(I){return(f(I).config?.command_tools??[]).flatMap((V)=>Uo(typeof V==="string"?V:V.name)??[])}function Bo(I,V){let X=`legacy ${I} config`;if(V==="cleanup")return`Warning: Legacy ${I} config is no longer needed. Run \`npx -y cc-safety-net rule migrate --cleanup\` to clean it up safely.`;if(V==="migrate")return`Warning: Legacy ${I} config is ignored by CC Safety Net. Run \`npx -y cc-safety-net rule migrate\`.`;return`Warning: Legacy ${I} config is no longer supported. Fix or delete the ${X}, then run \`npx -y cc-safety-net rule migrate\`.`}function Ew(I){if(we(I)===null)return null;let V=Tw(I);if(V.ruleNames.size===0&&V.errors.length===0)return null;return{path:I.path,result:V}}function Tw(I){let V=[],X=new Set,ee=(we(I)??[]).filter((ne)=>!Sw.has(ne.name)).sort((ne,te)=>ne.name.localeCompare(te.name));if(ee.length===0)return{errors:V,ruleNames:X};for(let ne of ee){if(!m.test(ne.name)){V.push(`rulebook directory names must match ${m}: ${ne.name}`);continue}if(ne.kind!=="directory"){V.push(`${ne.name} must be a rulebook directory`);continue}let te=s(I.scope,Cw(I.path,ne.name,"rulebook.json")),le=o(te);if(le===null){V.push(`${ne.name}/rulebook.json is required`);continue}try{let de;try{de=JSON.parse(le)}catch{V.push(`${ne.name}/rulebook.json: invalid JSON`);continue}let be=ye(de);if(be.name!==ne.name){V.push(`rulebook name "${be.name}" must match folder "${ne.name}"`);continue}let Se=$o(be);if(Se.length>0){V.push(...Se.map((Ie)=>`${ne.name}/rulebook.json: ${Ie}`));continue}X.add(ne.name)}catch(de){V.push(de instanceof Error?`${ne.name}/rulebook.json: ${de.message}`:`${ne.name}/rulebook.json: ${String(de)}`)}}return{errors:V,ruleNames:X}}function Aw(){console.log(Np),console.log(xw)}function _w(I,V,X,ee){if(console.log(`
|
|
289
289
|
✓ ${I} config: ${V}`),console.log(` Schema: ${ee==="rules"?"rulebook sources":"legacy inline rules"}`),X.ruleNames.size>0){console.log(` ${ee==="rules"?"Sources":"Rules"}:`);let ne=1;for(let te of X.ruleNames)console.log(` ${ne}. ${te}`),ne++}else console.log(` ${ee==="rules"?"Sources":"Rules"}: (none)`)}function Iw(I,V,X){if(console.error(`
|
|
290
290
|
✗ Legacy ${I.toLowerCase()} config: ${V}`),console.error(" Schema: legacy inline rules"),console.error(" Status: ignored by CC Safety Net"),X.errors.length>0){console.error(" Errors:");let ee=1;for(let ne of X.errors)for(let te of ne.split("; "))console.error(` ${ee}. ${te}`),ee++;return}if(X.ruleNames.size>0){console.error(" Rules:");let ee=1;for(let ne of X.ruleNames)console.error(` ${ee}. ${ne}`),ee++;return}console.error(" Rules: (none)")}function Ow(I,V,X){jp(`${I} config`,V,X)}function $w(I,V){console.log(`
|
|
291
291
|
✓ GitHub source rules: ${I}`),console.log(" Rulebooks:");let X=1;for(let ee of V.ruleNames)console.log(` ${X}. ${ee}`),X++}function Dw(I,V){jp("GitHub source rules",I,V)}function jp(I,V,X){console.error(`
|
|
292
|
-
✗ ${I}: ${V}`),console.error(" Errors:");let ee=1;for(let ne of X)for(let te of ne.split("; "))console.error(` ${ee}. ${te}`),ee++}function Nw(I){try{let V=o(I);if(V===null)return!1;let X=JSON.parse(V);if(X.$schema)return!1;return x(I,JSON.stringify({$schema:Pw,...X},null,2)),!0}catch(V){if(V instanceof i)throw V;return!1}}var Fp=new Set(["init","add","remove","update","sync","list","wrapper","tool","migrate","doc","verify"]),jw=new Set(["init","add","remove","update","sync","wrapper"]),Mp=new Set(["add","remove","list"]),Fw="cc-safety-net/rulebooks";async function Up(I,V){try{return await Hw(I,V)}catch(X){if(X instanceof i)return console.error(X.message),1;throw X}}async function Hw(I,V){let X=Uw(V),ee=X.help?Mw(X.positionals):null;if(ee)return er(ee),0;if(X.errors.length>0){for(let Se of X.errors)console.error(Se);return 1}let ne=X.positionals[0];if(!ne)return er(Ht,console.error),1;let te=X.positionals[1],le={global:X.global},de=process.cwd();if((ne==="tool"?X.project:!X.global&&jw.has(ne)&&!(ne==="wrapper"&&te==="list"))&&L(I,{cwd:de}))return console.error(`${D(de)} is the user rule config, not a project rule config; ${ne==="tool"?"drop --project":"use --global"} for the user scope, or run from a project directory`),1;if(ne==="init"){let Se=hn(I,le);qw(Se.configTarget);let Ie=Lw(Se.configDir,"example-rules","rulebook.json"),$e=s(Se.filesystemScope,Ie);if(X.example&&o($e)===null)zu($e);let Le=J(Se.configPath,Se.filesystemScope);for(let Ne of Le)console.error(Ne);if(Le.length>0)return 1;return console.log("Rule config initialized."),0}if(ne==="add"){let Se=Bp(X);if(!Se)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let Ie=hn(I,le),$e=await pp(I,Se,{...le,ref:X.ref,rulebooks:X.only.length>0?X.only:void 0});return Bu($e,Se,`Scope: ${X.global?"user":"project"} (${Ie.configDir})`),$e.ok?0:1}if(ne==="remove"){if(!te)return console.error("rule remove requires a source"),1;let Se=await fp(I,te,{...le,deleteSource:X.deleteSource});return Oo(Se,`Removed rulebook source: ${te}`),Se.ok?0:1}if(ne==="update"){let Se=await Ho(I,{...le,only:te,refresh:!0});return Oo(Se,"Rule config updated."),Se.ok?0:1}if(ne==="sync")return Za(I,{global:X.global});if(ne==="list"){let Se=ie(I,{cwd:de});return qu(Se),Se.errors.length>0?1:0}if(ne==="wrapper")return Vw(I,X);if(ne==="tool")return Jw(I,X,de);if(ne==="migrate")return vp(I,{cleanup:X.cleanup,cwd:de});if(ne==="doc"){console.log(Mu);let Se=await wp(I);if(Se)console.error(Se);return 0}if(ne==="verify")return Lp(I);return 1}function Mw(I){if(I.length===0)return Ht;let V=Ht.subcommands.filter((ee)=>ee.usage.split(" ")[0]===I[0]);if(V.length===0)return null;if(I.length===1&&V.length>1)return{name:`rule ${I[0]}`,description:`Subcommands of rule ${I[0]}`,usage:`rule ${I[0]} <subcommand>`,subcommands:V,options:[]};let X=I.length===1?V[0]:V.find((ee)=>ee.usage.split(" ")[1]===I[1]);if(!X)return null;return{name:`rule ${I[0]}`,description:X.description,usage:`rule ${X.usage}`,options:I[0]==="add"?Yo:[],examples:I[0]==="add"?Zo:void 0}}function Uw(I){let V=fn({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"},I),X={...V.flags,ref:V.values.ref,cwdArg:V.values.cwdArg,only:V.lists.only??[],help:V.help,positionals:V.positionals,errors:V.errors};return Bw(X),X}function Bw(I){let[V]=I.positionals;if(V&&!Fp.has(V))I.errors.push(`Unknown rule subcommand: ${V}`);if(I.deleteSource&&V!=="remove")if(V&&Fp.has(V))I.errors.push(`Unknown option for rule ${V}: --delete-source`);else I.errors.push("--delete-source is only valid with 'rule remove'");if(I.cleanup&&V!=="migrate")I.errors.push(Kn(V,"--cleanup"));if(I.example&&V!=="init")I.errors.push(Kn(V,"--example"));if(I.ref&&V!=="add")I.errors.push(Kn(V,"--ref"));if(I.only.length>0&&V!=="add")I.errors.push(Kn(V,"--only"));let X=V==="tool"?I.positionals[1]:void 0,ee=X&&Mp.has(X)?`tool ${X}`:V;if(I.project&&X!=="add"&&X!=="remove")I.errors.push(Kn(ee,"--project"));if(I.cwdArg!==void 0&&X!=="add")I.errors.push(Kn(ee,"--cwd-arg"));if(V==="tool"&&I.global)I.errors.push(Kn(V,"--global"));if(V==="add")Gw(I);if(V==="migrate"){if(I.global)I.errors.push(Kn(V,"--global"));if(I.positionals.length>1)I.errors.push(`Unexpected rule migrate argument: ${I.positionals[1]}`)}else if(V==="wrapper")Hp(I,"a command");else if(V==="tool")Hp(I,"a tool name");else if(I.positionals.length>2)I.errors.push(`Unexpected rule argument: ${I.positionals[2]}`);if(V==="list"&&I.global)I.errors.push("Unknown option for rule list: --global")}function Bp(I){if(I.positionals[1])return I.positionals[1];if(I.ref||I.only.length>0)return Fw;return}function Gw(I){let V=Bp(I);if(!V)return;if((I.ref||I.only.length>0)&&!re(V)){if(I.ref)I.errors.push(`--ref can only select a ref for an owner/repo source: ${V}`);if(I.only.length>0)I.errors.push("--only can only select rulebooks from an owner/repo source");return}if(I.ref&&!fe(I.ref))I.errors.push(`--ref must use valid path segments: ${I.ref}`);let X=I.only.filter((ee)=>!m.test(ee));if(X.length>0)I.errors.push(`Invalid rulebook names: ${X.join(", ")}`)}function Kn(I,V){return I?`Unknown option for rule ${I}: ${V}`:`Unknown option for rule: ${V}`}function Hp(I,V){let X=I.positionals[0],ee=I.positionals[1],ne=I.positionals[2];if(!ee){I.errors.push(`rule ${X} requires add, remove, or list`);return}if(!Mp.has(ee)){I.errors.push(`Unknown rule ${X} action: ${ee}`);return}if(ee==="list"){if(ne)I.errors.push(`Unexpected rule ${X} argument: ${ne}`);return}if(!ne){I.errors.push(`rule ${X} ${ee} requires ${V}`);return}if(X!=="tool"&&I.positionals.length>3)I.errors.push(`Unexpected rule ${X} argument: ${I.positionals[3]}`)}function qw(I){if(o(I)===null){Ju(I);return}let V=f(I);if(!V.config)return;yn(I,V.config)}async function Vw(I,V){let X=V.positionals[1],ee=V.positionals[2],ne=hn(I,{global:V.global}).configTarget;if(X==="list"){let ve=f(ne);if(ve.errors.length>0){for(let Se of ve.errors)console.error(Se);return 1}return Kw(ve.config?.transparent_wrappers??[]),0}if(!ee||!P.test(ee))return console.error("transparent wrapper must match command pattern"),1;if(Ke(ee))return console.error(`reserved command "${ee}" cannot be a wrapper`),1;let te=f(ne);if(te.errors.length>0){for(let ve of te.errors)console.error(ve);return 1}let le=te.config??ge,de=X==="add"?[...new Set([...le.transparent_wrappers??[],ee])]:(le.transparent_wrappers??[]).filter((ve)=>ve!==ee);return yn(ne,{...le,transparent_wrappers:de}),console.log(X==="add"?`Added transparent wrapper: ${ee}`:`Removed transparent wrapper: ${ee}`),0}function Kw(I){if(I.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${I.length}):`);for(let V of I)console.log(` - ${V}`)}function Jw(I,V,X){let ee=V.positionals[1],ne=[...new Set(V.positionals.slice(2))];if(ee==="list")return zw(I,X);let te=[...ne.flatMap((Se)=>{if(!Ye.test(Se))return[`"${Se}" is not a tool name: ${Te}.`];let Ie=ee==="add"?Uo(Se):void 0;return Ie?[Ie]:[]}),...V.cwdArg!==void 0&&!Ye.test(V.cwdArg)?[`"${V.cwdArg}" is not an argument name: ${Te}.`]:[]];if(te.length>0){for(let Se of te)console.error(qe.red(`Error: ${Se}`));return 1}let le=hn(I,{global:!V.project}),de=Ar(le.configTarget);if(!de.ok){for(let Se of de.result.errors)console.error(Se);return 1}let ve=ne.reduce((Se,Ie)=>{let $e=V.cwdArg===void 0?Ie:{name:Ie,cwd:V.cwdArg},Le=(Ne)=>(typeof Ne==="string"?Ne:Ne.name)===Ie;if(ee==="remove")return Se.filter((Ne)=>!Le(Ne));return Se.some(Le)?Se.map((Ne)=>Le(Ne)?$e:Ne):[...Se,$e]},de.config.command_tools??[]);yn(le.configTarget,{...de.config,command_tools:ve});for(let Se of ne)console.log(ee==="add"?`Added command tool: ${Se}${V.cwdArg===void 0?"":` (cwd argument: ${V.cwdArg})`}`:`Removed command tool: ${Se}`);return console.log(`Scope: ${V.project?"project":"user"} (${le.configPath})`),0}function zw(I,V){let X=(L(I,{cwd:V})?["user"]:["user","project"]).map((ne)=>{let te=hn(I,{global:ne==="user"});return{scope:ne,path:te.configPath,...f(te.configTarget)}}),ee=X.flatMap((ne)=>ne.errors.map((te)=>`${ne.path}: ${te}`));if(ee.length>0){for(let ne of ee)console.error(ne);return 1}return Vu(X.flatMap((ne)=>(ne.config?.command_tools??[]).map((te)=>({scope:ne.scope,tool:te})))),0}import{sep as ek}from"node:path";import{existsSync as Ww,readFileSync as Yw}from"node:fs";import{join as Zw}from"node:path";async function Xw(I){if(I.isTTY)return null;return(await gt(I).catch(()=>null))?.trim()||null}function Qw(I){let V=I.env.get("CLAUDE_SETTINGS_PATH");if(V)return V;return Zw(Wr(I),"settings.json")}function Bs(I){let V=Qw(I);if(!Ww(V))return!1;try{let X=Yw(V,"utf-8"),ee=JSON.parse(X);if(!ee.enabledPlugins)return!1;let ne="cc-safety-net@cc-marketplace";if(!(ne in ee.enabledPlugins))return!1;return ee.enabledPlugins[ne]===!0}catch(X){if(k(r.debug,I.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${V}: ${X instanceof Error?X.message:String(X)}`);return!1}}async function Gs(I,V=process.stdin){let X=Bs(I),ee;if(!X)ee="\uD83D\uDEE1️ CC Safety Net ❌";else{let te=w(I,{cwd:process.cwd()}),le=te.policy,de=O(le,I.env),ve=Object.values(Z(le,de.capabilities)).some(($e)=>$e.changesInherited),Se={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[ve?"custom":de.effectiveLevel],Ie=te.policyScopes&&!te.policyScopes.weakeningsIgnored&&te.policyScopes.weakenings.length>0?"\uD83D\uDD3B":"";ee=`\uD83D\uDEE1️ CC Safety Net ${Se}${de.worktreeMode?"\uD83C\uDF33":""}${Ie}${te.state==="degraded"?"⚠️":""}`}let ne=await Xw(V);if(ne&&!ne.startsWith("{"))console.log(`${ne} | ${ee}`);else console.log(ee)}function Gp(I){let V=w(I,{cwd:process.cwd()}),X=V.policy,ee=O(X,I.env),ne=!!process.env.NO_COLOR||!process.stdout.isTTY,te=Math.min(process.stdout.columns||80,100),le=ne?"ok":"✔",de=ne?"OFF":"✘",ve=(Be,Me)=>{let tn=` ${Be.padEnd(13)}${Me}`;return(tn.length>te?`${tn.slice(0,te-1)}…`:tn).replaceAll(de,qe.red(de))},Se=Object.values(Z(X,ee.capabilities)).some((Be)=>Be.changesInherited),Ie=(Be)=>Be===I.home||Be.startsWith(`${I.home}${ek}`)?`~${Be.slice(I.home.length)}`:Be,$e={ready:qe.green,degraded:qe.yellow}[V.state],Le=V.policyScopes?.weakenings??[],Ne=[...Bs(I)?[]:["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."],...V.diagnostics],Fe=ne?"-":"·";console.log([`${ne?"":"\uD83D\uDEE1️ "}CC Safety Net — ${$e(V.state)}`,"",ve("Protection",`destructive ${X.destructiveCommandProtectionEnabled?le:de} secrets ${X.secretProtection.enabled?le:de}`),ve("Level",Se?`${ee.effectiveLevel} (customised)`:ee.effectiveLevel),ve("Rules",X.rules.length===0?"none active":`${X.rules.length} active`),ve("Policy",Ie(p(I))),...V.policyScopes?[ve("Project",Ie(S(process.cwd())))]:[],...ee.worktreeMode?[ve("Worktree","relaxations active")]:[],"",...Le.length===0?[]:[V.policyScopes?.weakeningsIgnored?" Project policy (ignored)":" Project policy",...Le.flatMap((Be)=>br(Be," ",te-6).map((Me,tn)=>tn===0?` ${Me}`:Me)),""],...Ne.length===0?[" Everything configured is active."]:[" Not active",...Ne.flatMap((Be)=>br(Be," ",te-6).map((Me,tn)=>tn===0?` ${Fe} ${Me}`:Me)),""," Full report: cc-safety-net doctor"]].join(`
|
|
293
|
-
`))}import{spawn as cf}from"node:child_process";import{randomBytes as dk}from"node:crypto";import{existsSync as df,mkdirSync as uk,readFileSync as pk}from"node:fs";import{createServer as fk}from"node:http";import{dirname as uf,join as mk}from"node:path";import{Writable as gk}from"node:stream";var Go=500;function nk(I){let V=I.filter((ne)=>ne.decision!=="allow"),X=I.filter((ne)=>ne.decision==="allow"),ee=Math.min(V.length,Math.max(Go-X.length,Math.ceil(Go/2)));return[...V.slice(0,ee),...X.slice(0,Go-ee)]}function qp(I,V,X=W(I)){if(X)Q(I,X);let ee=(Me)=>new Date(Me.getFullYear(),Me.getMonth(),Me.getDate()).getTime(),ne=ee(new Date),te=new Date(ne);te.setDate(te.getDate()-(V-1));let le=te.getTime(),de=[],
|
|
292
|
+
✗ ${I}: ${V}`),console.error(" Errors:");let ee=1;for(let ne of X)for(let te of ne.split("; "))console.error(` ${ee}. ${te}`),ee++}function Nw(I){try{let V=o(I);if(V===null)return!1;let X=JSON.parse(V);if(X.$schema)return!1;return x(I,JSON.stringify({$schema:Pw,...X},null,2)),!0}catch(V){if(V instanceof i)throw V;return!1}}var Fp=new Set(["init","add","remove","update","sync","list","wrapper","tool","migrate","doc","verify"]),jw=new Set(["init","add","remove","update","sync","wrapper"]),Mp=new Set(["add","remove","list"]),Fw="cc-safety-net/rulebooks";async function Up(I,V){try{return await Hw(I,V)}catch(X){if(X instanceof i)return console.error(X.message),1;throw X}}async function Hw(I,V){let X=Uw(V),ee=X.help?Mw(X.positionals):null;if(ee)return er(ee),0;if(X.errors.length>0){for(let Se of X.errors)console.error(Se);return 1}let ne=X.positionals[0];if(!ne)return er(Ht,console.error),1;let te=X.positionals[1],le={global:X.global},de=process.cwd();if((ne==="tool"?X.project:!X.global&&jw.has(ne)&&!(ne==="wrapper"&&te==="list"))&&L(I,{cwd:de}))return console.error(`${D(de)} is the user rule config, not a project rule config; ${ne==="tool"?"drop --project":"use --global"} for the user scope, or run from a project directory`),1;if(ne==="init"){let Se=hn(I,le);qw(Se.configTarget);let Ie=Lw(Se.configDir,"example-rules","rulebook.json"),$e=s(Se.filesystemScope,Ie);if(X.example&&o($e)===null)zu($e);let Le=J(Se.configPath,Se.filesystemScope);for(let Ne of Le)console.error(Ne);if(Le.length>0)return 1;return console.log("Rule config initialized."),0}if(ne==="add"){let Se=Bp(X);if(!Se)return console.error("rule add requires a source (pass --only <rulebook...> to select from cc-safety-net/rulebooks)"),1;let Ie=hn(I,le),$e=await pp(I,Se,{...le,ref:X.ref,rulebooks:X.only.length>0?X.only:void 0});return Bu($e,Se,`Scope: ${X.global?"user":"project"} (${Ie.configDir})`),$e.ok?0:1}if(ne==="remove"){if(!te)return console.error("rule remove requires a source"),1;let Se=await fp(I,te,{...le,deleteSource:X.deleteSource});return Oo(Se,`Removed rulebook source: ${te}`),Se.ok?0:1}if(ne==="update"){let Se=await Ho(I,{...le,only:te,refresh:!0});return Oo(Se,"Rule config updated."),Se.ok?0:1}if(ne==="sync")return Za(I,{global:X.global});if(ne==="list"){let Se=ie(I,{cwd:de});return qu(Se),Se.errors.length>0?1:0}if(ne==="wrapper")return Vw(I,X);if(ne==="tool")return Jw(I,X,de);if(ne==="migrate")return vp(I,{cleanup:X.cleanup,cwd:de});if(ne==="doc"){console.log(Mu);let Se=await wp(I);if(Se)console.error(Se);return 0}if(ne==="verify")return Lp(I);return 1}function Mw(I){if(I.length===0)return Ht;let V=Ht.subcommands.filter((ee)=>ee.usage.split(" ")[0]===I[0]);if(V.length===0)return null;if(I.length===1&&V.length>1)return{name:`rule ${I[0]}`,description:`Subcommands of rule ${I[0]}`,usage:`rule ${I[0]} <subcommand>`,subcommands:V,options:[]};let X=I.length===1?V[0]:V.find((ee)=>ee.usage.split(" ")[1]===I[1]);if(!X)return null;return{name:`rule ${I[0]}`,description:X.description,usage:`rule ${X.usage}`,options:I[0]==="add"?Yo:[],examples:I[0]==="add"?Zo:void 0}}function Uw(I){let V=fn({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"},I),X={...V.flags,ref:V.values.ref,cwdArg:V.values.cwdArg,only:V.lists.only??[],help:V.help,positionals:V.positionals,errors:V.errors};return Bw(X),X}function Bw(I){let[V]=I.positionals;if(V&&!Fp.has(V))I.errors.push(`Unknown rule subcommand: ${V}`);if(I.deleteSource&&V!=="remove")if(V&&Fp.has(V))I.errors.push(`Unknown option for rule ${V}: --delete-source`);else I.errors.push("--delete-source is only valid with 'rule remove'");if(I.cleanup&&V!=="migrate")I.errors.push(Kn(V,"--cleanup"));if(I.example&&V!=="init")I.errors.push(Kn(V,"--example"));if(I.ref&&V!=="add")I.errors.push(Kn(V,"--ref"));if(I.only.length>0&&V!=="add")I.errors.push(Kn(V,"--only"));let X=V==="tool"?I.positionals[1]:void 0,ee=X&&Mp.has(X)?`tool ${X}`:V;if(I.project&&X!=="add"&&X!=="remove")I.errors.push(Kn(ee,"--project"));if(I.cwdArg!==void 0&&X!=="add")I.errors.push(Kn(ee,"--cwd-arg"));if(V==="tool"&&I.global)I.errors.push(Kn(V,"--global"));if(V==="add")Gw(I);if(V==="migrate"){if(I.global)I.errors.push(Kn(V,"--global"));if(I.positionals.length>1)I.errors.push(`Unexpected rule migrate argument: ${I.positionals[1]}`)}else if(V==="wrapper")Hp(I,"a command");else if(V==="tool")Hp(I,"a tool name");else if(I.positionals.length>2)I.errors.push(`Unexpected rule argument: ${I.positionals[2]}`);if(V==="list"&&I.global)I.errors.push("Unknown option for rule list: --global")}function Bp(I){if(I.positionals[1])return I.positionals[1];if(I.ref||I.only.length>0)return Fw;return}function Gw(I){let V=Bp(I);if(!V)return;if((I.ref||I.only.length>0)&&!re(V)){if(I.ref)I.errors.push(`--ref can only select a ref for an owner/repo source: ${V}`);if(I.only.length>0)I.errors.push("--only can only select rulebooks from an owner/repo source");return}if(I.ref&&!fe(I.ref))I.errors.push(`--ref must use valid path segments: ${I.ref}`);let X=I.only.filter((ee)=>!m.test(ee));if(X.length>0)I.errors.push(`Invalid rulebook names: ${X.join(", ")}`)}function Kn(I,V){return I?`Unknown option for rule ${I}: ${V}`:`Unknown option for rule: ${V}`}function Hp(I,V){let X=I.positionals[0],ee=I.positionals[1],ne=I.positionals[2];if(!ee){I.errors.push(`rule ${X} requires add, remove, or list`);return}if(!Mp.has(ee)){I.errors.push(`Unknown rule ${X} action: ${ee}`);return}if(ee==="list"){if(ne)I.errors.push(`Unexpected rule ${X} argument: ${ne}`);return}if(!ne){I.errors.push(`rule ${X} ${ee} requires ${V}`);return}if(X!=="tool"&&I.positionals.length>3)I.errors.push(`Unexpected rule ${X} argument: ${I.positionals[3]}`)}function qw(I){if(o(I)===null){Ju(I);return}let V=f(I);if(!V.config)return;yn(I,V.config)}async function Vw(I,V){let X=V.positionals[1],ee=V.positionals[2],ne=hn(I,{global:V.global}).configTarget;if(X==="list"){let be=f(ne);if(be.errors.length>0){for(let Se of be.errors)console.error(Se);return 1}return Kw(be.config?.transparent_wrappers??[]),0}if(!ee||!P.test(ee))return console.error("transparent wrapper must match command pattern"),1;if(Ke(ee))return console.error(`reserved command "${ee}" cannot be a wrapper`),1;let te=f(ne);if(te.errors.length>0){for(let be of te.errors)console.error(be);return 1}let le=te.config??ge,de=X==="add"?[...new Set([...le.transparent_wrappers??[],ee])]:(le.transparent_wrappers??[]).filter((be)=>be!==ee);return yn(ne,{...le,transparent_wrappers:de}),console.log(X==="add"?`Added transparent wrapper: ${ee}`:`Removed transparent wrapper: ${ee}`),0}function Kw(I){if(I.length===0){console.log("Transparent wrappers: (none)");return}console.log(`Transparent wrappers (${I.length}):`);for(let V of I)console.log(` - ${V}`)}function Jw(I,V,X){let ee=V.positionals[1],ne=[...new Set(V.positionals.slice(2))];if(ee==="list")return zw(I,X);let te=[...ne.flatMap((Se)=>{if(!Ye.test(Se))return[`"${Se}" is not a tool name: ${Te}.`];let Ie=ee==="add"?Uo(Se):void 0;return Ie?[Ie]:[]}),...V.cwdArg!==void 0&&!Ye.test(V.cwdArg)?[`"${V.cwdArg}" is not an argument name: ${Te}.`]:[]];if(te.length>0){for(let Se of te)console.error(qe.red(`Error: ${Se}`));return 1}let le=hn(I,{global:!V.project}),de=Ar(le.configTarget);if(!de.ok){for(let Se of de.result.errors)console.error(Se);return 1}let be=ne.reduce((Se,Ie)=>{let $e=V.cwdArg===void 0?Ie:{name:Ie,cwd:V.cwdArg},Le=(Ne)=>(typeof Ne==="string"?Ne:Ne.name)===Ie;if(ee==="remove")return Se.filter((Ne)=>!Le(Ne));return Se.some(Le)?Se.map((Ne)=>Le(Ne)?$e:Ne):[...Se,$e]},de.config.command_tools??[]);yn(le.configTarget,{...de.config,command_tools:be});for(let Se of ne)console.log(ee==="add"?`Added command tool: ${Se}${V.cwdArg===void 0?"":` (cwd argument: ${V.cwdArg})`}`:`Removed command tool: ${Se}`);return console.log(`Scope: ${V.project?"project":"user"} (${le.configPath})`),0}function zw(I,V){let X=(L(I,{cwd:V})?["user"]:["user","project"]).map((ne)=>{let te=hn(I,{global:ne==="user"});return{scope:ne,path:te.configPath,...f(te.configTarget)}}),ee=X.flatMap((ne)=>ne.errors.map((te)=>`${ne.path}: ${te}`));if(ee.length>0){for(let ne of ee)console.error(ne);return 1}return Vu(X.flatMap((ne)=>(ne.config?.command_tools??[]).map((te)=>({scope:ne.scope,tool:te})))),0}import{sep as ek}from"node:path";import{existsSync as Ww,readFileSync as Yw}from"node:fs";import{join as Zw}from"node:path";async function Xw(I){if(I.isTTY)return null;return(await gt(I).catch(()=>null))?.trim()||null}function Qw(I){let V=I.env.get("CLAUDE_SETTINGS_PATH");if(V)return V;return Zw(Wr(I),"settings.json")}function Bs(I){let V=Qw(I);if(!Ww(V))return!1;try{let X=Yw(V,"utf-8"),ee=JSON.parse(X);if(!ee.enabledPlugins)return!1;let ne="cc-safety-net@cc-marketplace";if(!(ne in ee.enabledPlugins))return!1;return ee.enabledPlugins[ne]===!0}catch(X){if(k(r.debug,I.env))console.error(`CC Safety Net debug: failed to read Claude settings: ${V}: ${X instanceof Error?X.message:String(X)}`);return!1}}async function Gs(I,V=process.stdin){let X=Bs(I),ee;if(!X)ee="\uD83D\uDEE1️ CC Safety Net ❌";else{let te=w(I,{cwd:process.cwd()}),le=te.policy,de=O(le,I.env),be=Object.values(Z(le,de.capabilities)).some(($e)=>$e.changesInherited),Se={standard:"✅",strict:"\uD83D\uDD12",paranoid:"\uD83D\uDC41️",custom:"\uD83D\uDD27"}[be?"custom":de.effectiveLevel],Ie=te.policyScopes&&!te.policyScopes.weakeningsIgnored&&te.policyScopes.weakenings.length>0?"\uD83D\uDD3B":"";ee=`\uD83D\uDEE1️ CC Safety Net ${Se}${de.worktreeMode?"\uD83C\uDF33":""}${Ie}${te.state==="degraded"?"⚠️":""}`}let ne=await Xw(V);if(ne&&!ne.startsWith("{"))console.log(`${ne} | ${ee}`);else console.log(ee)}function Gp(I){let V=w(I,{cwd:process.cwd()}),X=V.policy,ee=O(X,I.env),ne=!!process.env.NO_COLOR||!process.stdout.isTTY,te=Math.min(process.stdout.columns||80,100),le=ne?"ok":"✔",de=ne?"OFF":"✘",be=(Be,Me)=>{let tn=` ${Be.padEnd(13)}${Me}`;return(tn.length>te?`${tn.slice(0,te-1)}…`:tn).replaceAll(de,qe.red(de))},Se=Object.values(Z(X,ee.capabilities)).some((Be)=>Be.changesInherited),Ie=(Be)=>Be===I.home||Be.startsWith(`${I.home}${ek}`)?`~${Be.slice(I.home.length)}`:Be,$e={ready:qe.green,degraded:qe.yellow}[V.state],Le=V.policyScopes?.weakenings??[],Ne=[...Bs(I)?[]:["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."],...V.diagnostics],Fe=ne?"-":"·";console.log([`${ne?"":"\uD83D\uDEE1️ "}CC Safety Net — ${$e(V.state)}`,"",be("Protection",`destructive ${X.destructiveCommandProtectionEnabled?le:de} secrets ${X.secretProtection.enabled?le:de}`),be("Level",Se?`${ee.effectiveLevel} (customised)`:ee.effectiveLevel),be("Rules",X.rules.length===0?"none active":`${X.rules.length} active`),be("Policy",Ie(p(I))),...V.policyScopes?[be("Project",Ie(S(process.cwd())))]:[],...ee.worktreeMode?[be("Worktree","relaxations active")]:[],"",...Le.length===0?[]:[V.policyScopes?.weakeningsIgnored?" Project policy (ignored)":" Project policy",...Le.flatMap((Be)=>br(Be," ",te-6).map((Me,tn)=>tn===0?` ${Me}`:Me)),""],...Ne.length===0?[" Everything configured is active."]:[" Not active",...Ne.flatMap((Be)=>br(Be," ",te-6).map((Me,tn)=>tn===0?` ${Fe} ${Me}`:Me)),""," Full report: cc-safety-net doctor"]].join(`
|
|
293
|
+
`))}import{spawn as cf}from"node:child_process";import{randomBytes as dk}from"node:crypto";import{existsSync as df,mkdirSync as uk,readFileSync as pk}from"node:fs";import{createServer as fk}from"node:http";import{dirname as uf,join as mk}from"node:path";import{Writable as gk}from"node:stream";var Go=500;function nk(I){let V=I.filter((ne)=>ne.decision!=="allow"),X=I.filter((ne)=>ne.decision==="allow"),ee=Math.min(V.length,Math.max(Go-X.length,Math.ceil(Go/2)));return[...V.slice(0,ee),...X.slice(0,Go-ee)]}function qp(I,V,X=W(I)){if(X)Q(I,X);let ee=(Me)=>new Date(Me.getFullYear(),Me.getMonth(),Me.getDate()).getTime(),ne=ee(new Date),te=new Date(ne);te.setDate(te.getDate()-(V-1));let le=te.getTime(),de=[],be={count:0};for(let Me of X?Jn(X,be):[])for(let tn of Ft(Me,be)){let en=new Date(tn.ts).getTime();if(!Number.isFinite(en))continue;if(en>=le)de.push(tn)}de.sort((Me,tn)=>new Date(tn.ts).getTime()-new Date(Me.ts).getTime());let Se=Array.from({length:V},()=>0),Ie=Array.from({length:V},()=>0),$e={},Le={},Ne={},Fe=0,Be=0;for(let Me of de){let tn=Me.agent||"unknown";$e[tn]=($e[tn]??0)+1;let en=Math.round((ne-ee(new Date(Me.ts)))/86400000),on=V-1-en,ln=en>=0&&en<V;if(ln)Ie[on]=(Ie[on]??0)+1;if(Me.decision!=="allow"){if(Fe++,Me.ruleId)Le[Me.ruleId]=(Le[Me.ruleId]??0)+1;let nn=Jo(Me.segment||Me.command);if(nn)Ne[nn]=(Ne[nn]??0)+1;if(Me.failureStage)Be++;if(ln)Se[on]=(Se[on]??0)+1}}return{days:V,logsDir:X,homeDir:I.home,totalInWindow:de.length,truncated:de.length>Go,unreadable:be.count,counts:{blocked:Fe,allowed:de.length-Fe,agents:$e,blockedByDay:Se,analyzedByDay:Ie,rules:Le,commands:Ne,errors:Be},entries:nk(de).sort((Me,tn)=>new Date(tn.ts).getTime()-new Date(Me.ts).getTime())}}import{spawn as tk}from"node:child_process";import{existsSync as rk,statSync as Vp}from"node:fs";import{delimiter as ok,join as ik}from"node:path";var sk=120000,qo="Choose the project folder",ak=`try
|
|
294
294
|
return POSIX path of (choose folder with prompt "${qo}")
|
|
295
295
|
on error number -128
|
|
296
296
|
return ""
|
|
297
297
|
end try`,lk=`Add-Type -AssemblyName System.Windows.Forms
|
|
298
298
|
$dialog = New-Object System.Windows.Forms.FolderBrowserDialog
|
|
299
299
|
$dialog.Description = '${qo}'
|
|
300
|
-
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Kp=[{binary:"zenity",args:["--file-selection","--directory",`--title=${qo}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",qo]}],Jp=(I,V)=>(V.PATH??"").split(ok).some((X)=>{if(X.length===0)return!1;try{let ee=Vp(ik(X,I));return ee.isFile()&&(ee.mode&73)!==0}catch{return!1}});function qs(I,V){if(I==="darwin"||I==="win32")return!0;if(I!=="linux")return!1;if(!V.DISPLAY&&!V.WAYLAND_DISPLAY)return!1;return Kp.some((X)=>Jp(X.binary,V))}function ck(I,V){if(I==="darwin")return{cmd:"osascript",args:["-e",ak]};if(I==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",lk]};let X=Kp.find((ee)=>Jp(ee.binary,V));return X?{cmd:X.binary,args:X.args}:null}function Vs(I=process.platform,V=process.env){let X=ck(I,V);if(!X)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((ee)=>{let ne=tk(X.cmd,X.args,{env:V,stdio:["ignore","pipe","pipe"]}),te="",le=!1,de=(Se)=>{if(le)return;le=!0,clearTimeout(
|
|
300
|
+
if ($dialog.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK) { [Console]::Out.Write($dialog.SelectedPath) }`,Kp=[{binary:"zenity",args:["--file-selection","--directory",`--title=${qo}`]},{binary:"kdialog",args:["--getexistingdirectory",".","--title",qo]}],Jp=(I,V)=>(V.PATH??"").split(ok).some((X)=>{if(X.length===0)return!1;try{let ee=Vp(ik(X,I));return ee.isFile()&&(ee.mode&73)!==0}catch{return!1}});function qs(I,V){if(I==="darwin"||I==="win32")return!0;if(I!=="linux")return!1;if(!V.DISPLAY&&!V.WAYLAND_DISPLAY)return!1;return Kp.some((X)=>Jp(X.binary,V))}function ck(I,V){if(I==="darwin")return{cmd:"osascript",args:["-e",ak]};if(I==="win32")return{cmd:"powershell.exe",args:["-NoProfile","-STA","-Command",lk]};let X=Kp.find((ee)=>Jp(ee.binary,V));return X?{cmd:X.binary,args:X.args}:null}function Vs(I=process.platform,V=process.env){let X=ck(I,V);if(!X)return Promise.resolve({error:"No folder dialog is available on this system"});return new Promise((ee)=>{let ne=tk(X.cmd,X.args,{env:V,stdio:["ignore","pipe","pipe"]}),te="",le=!1,de=(Se)=>{if(le)return;le=!0,clearTimeout(be),ee(Se)},be=setTimeout(()=>{ne.kill(),de({error:"The folder dialog timed out"})},sk);ne.stdout.on("data",(Se)=>{te+=Se.toString()}),ne.on("error",()=>de({error:`Could not open the folder dialog (${X.cmd})`})),ne.on("close",()=>{let Se=te.trim().replace(/\/+$/,"");if(!Se)return de({cancelled:!0});if(!rk(Se)||!Vp(Se).isDirectory())return de({error:"That selection is not a folder on disk"});de({path:Se})})})}var zp=["en","ja","zh-CN"],Wp=["light","dark"],Vo=(I,V)=>I.includes(V),Yp=(I)=>typeof I==="object"&&I!==null&&!Array.isArray(I),Zp=(I)=>{let V=Yp(I)?I:{};return{...Vo(zp,V.language)?{language:V.language}:{},...Vo(Wp,V.theme)?{theme:V.theme}:{}}},Xp=(I)=>{if(!Yp(I))return null;let V=Object.keys(I).every((ne)=>ne==="language"||ne==="theme"),X=I.language===void 0||Vo(zp,I.language),ee=I.theme===void 0||Vo([...Wp,"auto"],I.theme);return V&&X&&ee?I:null},Qp=(I,V)=>{let X=V.language??I.language,ee=V.theme==="auto"?void 0:V.theme??I.theme;return{...X?{language:X}:{},...ee?{theme:ee}:{}}};var ef=`<!doctype html>
|
|
301
301
|
<html lang="en">
|
|
302
302
|
<head>
|
|
303
303
|
<meta charset="utf-8">
|
|
@@ -7063,7 +7063,7 @@ loadPolicy().then((loaded) => {
|
|
|
7063
7063
|
</script>
|
|
7064
7064
|
</body>
|
|
7065
7065
|
</html>
|
|
7066
|
-
`;var nf='<script id="ccsn-data" type="application/json">';function tf(I,V=ef){return V.replace(nf,()=>nf+JSON.stringify(I).replaceAll("<","\\u003c"))}var Js="kenryu42/cc-safety-net",hk=`https://github.com/${Js}`,pf=1e4,yk=7,vk="The project draft directory changed; reload the draft before applying.",bk="audit settings are user scope only; remove the audit section from a project proposal";async function ff(I,V={}){let X=fn({label:"gui",booleans:{noOpen:["--no-open"]}},I),ee=V.log??console.log,ne=V.error??console.error;if(X.errors.length>0){for(let le of X.errors)ne(le);return ne("Usage: cc-safety-net gui [--no-open]"),1}let te=await wk(c,V);if(ee(`CC Safety Net policy GUI: ${te.url}`),!X.flags.noOpen)try{await(V.openBrowser??Ok)(te.url)}catch(le){ne(`Failed to open browser: ${le instanceof Error?le.message:String(le)}`),ne(`Open this URL manually: ${te.url}`)}if(V.keepAlive===!1)return await te.close(),0;return await Ik(te),0}async function wk(I,V={}){let X=dk(24).toString("base64url"),ee={dir:null,revision:0},ne=fk((de,
|
|
7067
|
-
`),null}catch(X){return X instanceof Error?X.message:String(X)}}function Ks(I){return{...I,cwd:I.cwd??process.cwd()}}function mf(I,V){return I.dir??V.cwd??process.cwd()}function gf(I,V,X){if(!L(I,{...X,cwd:V}))return null;return`${S(V)} is the user policy, not a project policy; choose a project directory, or run the GUI from one`}function sf(I,V){let X=S(I),ee=df(X)?$t(X):{value:void 0,errors:[]},ne=
|
|
7068
|
-
`),{path:ee,errors:[]}}catch(te){return{path:ee,errors:[te instanceof Error?te.message:String(te)]}}}function Sk(I,V,X,ee){let ne=_(X,I.home),te=w(I,Ks(ee)),le=Ge({rules:te.policy.rules,transparentWrappers:te.policy.transparentWrappers,commandTools:te.policy.commandTools,safety:tt(ne.safety),worktreeMode:ne.workflow.worktree_mode,destructiveCommandProtectionEnabled:ne.destructive_command_protection.enabled,destructiveCommandRuleOverrides:ne.destructive_command_protection.overrides,destructiveCommandAllowPaths:ne.destructive_command_protection.allow_paths,secretProtection:{enabled:ne.secret_protection.enabled,disabledRules:Ct(ne.secret_protection.overrides),denyPaths:ne.secret_protection.deny_paths,allowPaths:ne.secret_protection.allow_paths}});return wr(V,{policySnapshot:le,cwd:ee.cwd,userConfigDir:ee.userConfigDir},I)}function Rk(I,V){if(I===null)return Math.min(yk,V);let X=Number(I);if(!Number.isInteger(X)||X<1||X>V)return null;return X}function Ek(I,V,X){if(V.searchParams.get("token")!==X)return!1;if(I.method!=="POST")return!0;return I.headers["x-cc-safety-net-token"]===X}var Tk=1048576;async function or(I){let V=[],X=0;for await(let ee of I){let ne=ee;if(X+=ne.byteLength,X>Tk)return{ok:!1,status:413,error:"Request body is too large"};V.push(ne)}try{return{ok:!0,value:JSON.parse(Buffer.concat(V).toString("utf-8")||"{}")}}catch(ee){return{ok:!1,status:400,error:`Invalid JSON: ${ee instanceof Error?ee.message:String(ee)}`}}}function Ak(I,V){I.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),I.end(V)}function rn(I,V,X){I.writeHead(V,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),I.end(JSON.stringify(X))}function _k(I){return new Promise((V,X)=>{I.close((ee)=>ee?X(ee):V())})}function Ik(I){return new Promise((V)=>{let X=()=>{process.off("SIGINT",ee),process.off("SIGTERM",ee)},ee=()=>{X(),I.close().then(V)};process.once("SIGINT",ee),process.once("SIGTERM",ee)})}function Ok(I){let V=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",X=process.platform==="win32"?["/c","start","",I]:[I];return new Promise((ee,ne)=>{let te=cf(V,X,{detached:!0,stdio:"ignore"}),le=(
|
|
7069
|
-
`)}}finally{console.log=le,console.error=de}},ne=lf.then(ee);return lf=ne.then(()=>{return},()=>{return}),ne}async function Fk(I,V={}){let[X,ee]=await Promise.all([Mk(V.fetchRepo),Promise.resolve(Lr(I,ue(I),V.logsDir).totalBlocked)]);return{starCount:X,blockedTotal:ee}}function Hk(I,V,X){return new Promise((ee)=>{let ne=cf(I,V,{stdio:"ignore",windowsHide:!0}),te=!1,le=setTimeout(()=>{ne.kill(),de(null)},X),de=(
|
|
7066
|
+
`;var nf='<script id="ccsn-data" type="application/json">';function tf(I,V=ef){return V.replace(nf,()=>nf+JSON.stringify(I).replaceAll("<","\\u003c"))}var Js="kenryu42/cc-safety-net",hk=`https://github.com/${Js}`,pf=1e4,yk=7,vk="The project draft directory changed; reload the draft before applying.",bk="audit settings are user scope only; remove the audit section from a project proposal";async function ff(I,V={}){let X=fn({label:"gui",booleans:{noOpen:["--no-open"]}},I),ee=V.log??console.log,ne=V.error??console.error;if(X.errors.length>0){for(let le of X.errors)ne(le);return ne("Usage: cc-safety-net gui [--no-open]"),1}let te=await wk(c,V);if(ee(`CC Safety Net policy GUI: ${te.url}`),!X.flags.noOpen)try{await(V.openBrowser??Ok)(te.url)}catch(le){ne(`Failed to open browser: ${le instanceof Error?le.message:String(le)}`),ne(`Open this URL manually: ${te.url}`)}if(V.keepAlive===!1)return await te.close(),0;return await Ik(te),0}async function wk(I,V={}){let X=dk(24).toString("base64url"),ee={dir:null,revision:0},ne=fk((de,be)=>{kk(I,de,be,X,V,ee)});await new Promise((de,be)=>{ne.once("error",be),ne.listen(0,"127.0.0.1",()=>{ne.off("error",be),de()})});let le=`http://127.0.0.1:${ne.address().port}`;return{origin:le,token:X,url:`${le}/?token=${encodeURIComponent(X)}`,close:()=>_k(ne)}}async function kk(I,V,X,ee,ne,te){let le=I(),de=new URL(V.url??"/","http://127.0.0.1");if(V.method==="GET"&&de.pathname==="/favicon.ico"){X.writeHead(204,{"cache-control":"no-store"}),X.end();return}if(!Ek(V,de,ee)){rn(X,403,{error:"Forbidden"});return}if(V.method==="GET"&&de.pathname==="/"){let be=of(rf(le,ne));await Promise.resolve(ne.buildDocument?.()).then((Se)=>Ak(X,tf({token:ee,preferences:be},Se)),(Se)=>rn(X,500,{error:Se instanceof Error?Se.message:String(Se)}));return}if(V.method==="POST"&&de.pathname==="/api/preferences"){let be=await or(V);if(!be.ok){rn(X,be.status,{errors:[be.error]});return}let Se=Xp(be.value);if(!Se){rn(X,400,{errors:["preferences accept only language (en, ja, zh-CN) and theme (auto, light, dark)"]});return}let Ie=rf(le,ne),$e=Qp(of(Ie),Se),Le=Ck(Ie,$e);rn(X,Le?500:200,Le?{errors:[Le]}:{preferences:$e});return}if(V.method==="GET"&&de.pathname==="/api/policy"){let be=$u(le,ne),Se=w(le,Ks(ne));rn(X,200,{...be,configState:nt(Se),...Se.policyScopes?{projectPolicy:{path:S(ne.cwd??process.cwd()),weakenings:Se.policyScopes.weakeningsIgnored?[]:Se.policyScopes.weakenings}}:{},destructiveCommandRules:Y,secretPatterns:xt,version:un(),preview:be.errors.length>0?null:Qe(be.policy,le.env)});return}if(V.method==="POST"&&de.pathname==="/api/policy/preview"){let be=await or(V);if(!be.ok){rn(X,be.status,{errors:[be.error]});return}let Se=Du(le,be.value);rn(X,Se.errors.length>0?400:200,Se);return}if(V.method==="POST"&&de.pathname==="/api/policy/explain"){let be=await or(V);if(!be.ok){rn(X,be.status,{errors:[be.error]});return}let Se=be.value;if(Se===null||typeof Se.command!=="string"){rn(X,400,{errors:["command must be a string"]});return}let Ie=Er(Se.policy,le.home);if(Ie.length>0){rn(X,400,{errors:Ie});return}rn(X,200,Sk(le,Se.command,Se.policy,ne));return}if(V.method==="POST"&&de.pathname==="/api/policy"){let be=await or(V);if(!be.ok){rn(X,be.status,{errors:[be.error]});return}let Se=Ln(le,be.value,ne);rn(X,Se.errors.length>0?400:200,Se);return}if(V.method==="POST"&&de.pathname==="/api/reset"){rn(X,200,Ln(le,ae,ne));return}if(V.method==="POST"&&de.pathname==="/api/repair"){rn(X,200,Nu(le,ne));return}if(V.method==="POST"&&de.pathname==="/api/policy/project/choose-directory"){let be=await(ne.chooseDirectory??Vs)();if("path"in be)te.dir=be.path,te.revision+=1;rn(X,200,{cancelled:"cancelled"in be,..."error"in be?{error:be.error}:{}});return}if(V.method==="GET"&&de.pathname==="/api/policy/project"){let be=mf(te,ne),Se=gf(le,be,ne),Ie=Se?{projection:{},diagnostics:[Se]}:sf(be,le.home),$e=Tr(le,ne);rn(X,200,{path:S(be),revision:te.revision,baseline:$e.baseline,userPolicyDiagnostics:$e.diagnostics,projection:Ie.projection,projectionDiagnostics:Ie.diagnostics,canPickDirectory:qs(process.platform,process.env)});return}if(V.method==="POST"&&de.pathname==="/api/policy/project/diff"){let be=await af(le,V,X,te,ne);if(!be)return;let Se=sf(be.dir,le.home),Ie=Tr(le,ne).baseline,$e=se(Ie,ve(be.proposal,le.home).policy);rn(X,200,{rows:_o(se(Ie,Se.projection).policy,$e.policy,!1),weakenings:$e.weakenings,existingFileDiagnostics:Se.diagnostics});return}if(V.method==="POST"&&de.pathname==="/api/policy/project/apply"){let be=await af(le,V,X,te,ne);if(!be)return;let Se=Pk(be.dir,be.proposal,le.home);rn(X,Se.errors.length>0?500:200,Se);return}if(V.method==="GET"&&de.pathname==="/api/activity"){let be=ue(le,ne),Se=Rk(de.searchParams.get("days"),be);if(Se===null){rn(X,400,{error:`days must be an integer between 1 and ${be}`});return}rn(X,200,qp(le,Se,ne.activityLogsDir));return}if(V.method==="POST"&&de.pathname==="/api/rules/choose-directory"){rn(X,200,await Vs());return}if(V.method==="GET"&&de.pathname==="/api/rules"){let be=ie(le,Ks(ne)),Se=new Map(be.rules.map((Ie)=>[Ie.name,Ie]));rn(X,200,{projectPath:ne.cwd??process.cwd(),canPickDirectory:qs(process.platform,process.env),rulebooks:be.rulebooks.map((Ie)=>({source:Ie.source,spec:Ie.spec,name:Ie.name,version:Ie.version,rules:Ie.rules.flatMap(($e)=>{let Le=Se.get($e);if(!Le)return[];return[{name:Le.name,command:Le.command,subcommand:Le.subcommand,block_args:Le.block_args,reason:Le.reason}]})})),errors:be.errors,warnings:be.warnings});return}if(V.method==="GET"&&de.pathname==="/api/star/context"){rn(X,200,await(ne.fetchStarContext??(()=>Fk(le,{logsDir:ne.activityLogsDir})))());return}if(V.method==="POST"&&de.pathname==="/api/star"){let be=await(ne.starRepo??$k)();rn(X,200,be.ok?{ok:!0}:{ok:!1,fallbackUrl:hk});return}if(V.method==="GET"&&de.pathname==="/api/integrations"){rn(X,200,await(ne.fetchIntegrations??(()=>Dk(le)))());return}if(V.method==="GET"&&de.pathname==="/api/health"){rn(X,200,await(ne.fetchHealth??Lk)());return}if(V.method==="POST"&&(de.pathname==="/api/install"||de.pathname==="/api/uninstall")){let be=await or(V);if(!be.ok){rn(X,be.status,{errors:[be.error]});return}let Se=be.value?.target;if(typeof Se!=="string"||!_n.some(($e)=>$e.target===Se)){rn(X,400,{error:"unknown target"});return}let Ie=de.pathname==="/api/install"?"install":"uninstall";rn(X,200,await(ne.runIntegration??jk)(Ie,Se));return}rn(X,404,{error:"Not found"})}function rf(I,V){return mk(uf(me(I,V)),"gui.json")}function of(I){if(!df(I))return{};try{return Zp(JSON.parse(pk(I,"utf-8")))}catch{return{}}}function Ck(I,V){try{return uk(uf(I),{recursive:!0}),an(I,`${JSON.stringify(V,null,2)}
|
|
7067
|
+
`),null}catch(X){return X instanceof Error?X.message:String(X)}}function Ks(I){return{...I,cwd:I.cwd??process.cwd()}}function mf(I,V){return I.dir??V.cwd??process.cwd()}function gf(I,V,X){if(!L(I,{...X,cwd:V}))return null;return`${S(V)} is the user policy, not a project policy; choose a project directory, or run the GUI from one`}function sf(I,V){let X=S(I),ee=df(X)?$t(X):{value:void 0,errors:[]},ne=ve(ee.value,V);return{projection:ne.policy,diagnostics:[...ee.errors,...ne.diagnostics]}}async function af(I,V,X,ee,ne){let te=mf(ee,ne),le=ee.revision,de=await or(V);if(!de.ok)return rn(X,de.status,{errors:[de.error]}),null;let be=de.value;if(typeof be?.revision!=="number")return rn(X,400,{errors:["revision must be a number"]}),null;if(be.revision!==le)return rn(X,409,{errors:[vk]}),null;let Se=gf(I,te,ne);if(Se)return rn(X,400,{errors:[Se]}),null;let Ie=xk(be.proposal,I.home);if(Ie.length>0)return rn(X,400,{errors:Ie}),null;return{dir:te,proposal:be.proposal}}function xk(I,V){let X=Er(I,V);if(X.length>0)return X;return I?.audit===void 0?[]:[bk]}function Pk(I,V,X){let ee=S(I),ne=Io(V,_(V,X));try{return x(s(R(I,"project policy"),ee),`${JSON.stringify(ne,null,2)}
|
|
7068
|
+
`),{path:ee,errors:[]}}catch(te){return{path:ee,errors:[te instanceof Error?te.message:String(te)]}}}function Sk(I,V,X,ee){let ne=_(X,I.home),te=w(I,Ks(ee)),le=Ge({rules:te.policy.rules,transparentWrappers:te.policy.transparentWrappers,commandTools:te.policy.commandTools,safety:tt(ne.safety),worktreeMode:ne.workflow.worktree_mode,destructiveCommandProtectionEnabled:ne.destructive_command_protection.enabled,destructiveCommandRuleOverrides:ne.destructive_command_protection.overrides,destructiveCommandAllowPaths:ne.destructive_command_protection.allow_paths,secretProtection:{enabled:ne.secret_protection.enabled,disabledRules:Ct(ne.secret_protection.overrides),denyPaths:ne.secret_protection.deny_paths,allowPaths:ne.secret_protection.allow_paths}});return wr(V,{policySnapshot:le,cwd:ee.cwd,userConfigDir:ee.userConfigDir},I)}function Rk(I,V){if(I===null)return Math.min(yk,V);let X=Number(I);if(!Number.isInteger(X)||X<1||X>V)return null;return X}function Ek(I,V,X){if(V.searchParams.get("token")!==X)return!1;if(I.method!=="POST")return!0;return I.headers["x-cc-safety-net-token"]===X}var Tk=1048576;async function or(I){let V=[],X=0;for await(let ee of I){let ne=ee;if(X+=ne.byteLength,X>Tk)return{ok:!1,status:413,error:"Request body is too large"};V.push(ne)}try{return{ok:!0,value:JSON.parse(Buffer.concat(V).toString("utf-8")||"{}")}}catch(ee){return{ok:!1,status:400,error:`Invalid JSON: ${ee instanceof Error?ee.message:String(ee)}`}}}function Ak(I,V){I.writeHead(200,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),I.end(V)}function rn(I,V,X){I.writeHead(V,{"content-type":"application/json; charset=utf-8","cache-control":"no-store"}),I.end(JSON.stringify(X))}function _k(I){return new Promise((V,X)=>{I.close((ee)=>ee?X(ee):V())})}function Ik(I){return new Promise((V)=>{let X=()=>{process.off("SIGINT",ee),process.off("SIGTERM",ee)},ee=()=>{X(),I.close().then(V)};process.once("SIGINT",ee),process.once("SIGTERM",ee)})}function Ok(I){let V=process.platform==="darwin"?"open":process.platform==="win32"?"cmd":"xdg-open",X=process.platform==="win32"?["/c","start","",I]:[I];return new Promise((ee,ne)=>{let te=cf(V,X,{detached:!0,stdio:"ignore"}),le=(be)=>{te.off("spawn",de),ne(be)},de=()=>{te.off("error",le),te.unref(),ee()};te.once("error",le),te.once("spawn",de)})}async function $k(I="gh",V=pf){return{ok:await Hk(I,["api","-X","PUT",`/user/starred/${Js}`],V)===0}}async function Dk(I,V={}){let X=await Mr((ne)=>Xt({environment:I,cwd:process.cwd(),openCodeVersion:ne}).status!=="n/a",V.fetcher),ee=Nk(I,X);return{targets:xn.map((ne)=>{let te=ee.find((le)=>le.platform===ne.id);return{target:ne.id,label:cn(ne.id),version:X.versions[ne.id]??null,status:te?.configured?"active":te?.detected?"disabled":te?.inspectionStatus==="not-inspected"?"not-inspected":"not-installed"}}),system:{version:X.version,nodeVersion:X.nodeVersion,platform:X.platform}}}function Nk(I,V){return Qt(I,process.cwd(),{ampPluginListOutput:V.ampPluginListOutput,codexPluginListOutput:V.codexPluginListOutput,copilotCliVersion:V.versions["copilot-cli"],openCodeVersion:V.versions.opencode,openCodePluginListOutput:V.openCodePluginListOutput})}async function Lk(I={}){let V=await(I.checkUpdates??Hn)();return{update:{latestVersion:V.latestVersion??null,updateAvailable:V.updateAvailable}}}var lf=Promise.resolve();function jk(I,V,X={}){let ee=async()=>{let te=[],{log:le,error:de}=console;console.log=(...be)=>te.push(be.map(String).join(" ")),console.error=console.log;try{return{ok:await Rr(I,[],{selectTargets:async()=>[V],output:new gk({write(Se,Ie,$e){te.push(String(Se).replace(/\n$/,"")),$e()}}),...X})===0,output:te.join(`
|
|
7069
|
+
`)}}finally{console.log=le,console.error=de}},ne=lf.then(ee);return lf=ne.then(()=>{return},()=>{return}),ne}async function Fk(I,V={}){let[X,ee]=await Promise.all([Mk(V.fetchRepo),Promise.resolve(Lr(I,ue(I),V.logsDir).totalBlocked)]);return{starCount:X,blockedTotal:ee}}function Hk(I,V,X){return new Promise((ee)=>{let ne=cf(I,V,{stdio:"ignore",windowsHide:!0}),te=!1,le=setTimeout(()=>{ne.kill(),de(null)},X),de=(be)=>{if(te)return;te=!0,clearTimeout(le),ee(be)};ne.once("error",()=>de(null)),ne.once("close",de)})}async function Mk(I=fetch){try{let V=await I(`https://api.github.com/repos/${Js}`,{headers:{accept:"application/vnd.github+json"},signal:AbortSignal.timeout(pf)});if(!V.ok)return null;let X=await V.json();return typeof X.stargazers_count==="number"?X.stargazers_count:null}catch{return null}}function Uk(I){if(I[0]!=="help")return!1;let V=I[1];if(!V)ys(),process.exit(0);if(kr(V))process.exit(0);console.error(`Unknown command: ${V}`),console.error("Run 'cc-safety-net --help' for available commands."),process.exit(1)}var Bk={hook:async()=>{console.error("hook requires exactly one integration flag. Try: cc-safety-net hook --kimi-code"),kr("hook",console.error),process.exit(1)},install:async(I)=>{process.exit(await Rr("install",I))},update:async(I)=>{process.exit(await Os(I))},uninstall:async(I)=>{process.exit(await Rr("uninstall",I))},rule:async(I)=>{process.exit(await Up(c(),I))},policy:async(I)=>{process.exit(await Hu(c(),I))},status:async(I)=>{if(In(fn({label:"status"},I).errors))process.exit(1);Gp(c())},statusline:async(I)=>{let V=fn({label:"statusline",booleans:{claudeCode:["-cc","--claude-code"]}},I);if(V.errors.length===0&&V.flags.claudeCode){await Gs(c());return}if(In(V.errors),!V.flags.claudeCode)console.error("statusline requires --claude-code (-cc)");kr("statusline",console.error),process.exit(1)},doctor:async(I)=>{let V=as(I);if(!V)process.exit(1);let X=await ed(c(),{json:V.json,skipUpdateCheck:V.skipUpdateCheck});process.exit(X)},logs:async(I)=>{process.exit(await na(c(),I))},gui:async(I)=>{process.exit(await ff(I))},explain:async(I)=>{process.exit(await dd(c(),I))}};async function Gk(I){let V=fn({label:"cc-safety-net",booleans:{version:["-V","--version"]},positionals:"list"},I);if(Uk(I))return;let X=I[0],ee=X?Nr(X):void 0;if(V.help&&ee&&ee.name!=="rule")kr(ee.name),process.exit(0);if(!X||V.help&&!ee)ys(),process.exit(0);if(V.flags.version)fd(),process.exit(0);if(ee){await Bk[ee.name](I.slice(1));return}if(X==="--statusline"){await Gs(c());return}console.error(X.startsWith("-")?`Unknown option: ${X}`:`Unknown command: ${X}`),console.error("Run 'cc-safety-net --help' for usage."),process.exit(1)}export{Gk as runCli};
|